@coderook/cli 0.38.2 → 0.40.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.
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.REGISTRY = void 0;
7
8
  /**
8
9
  * cbx — the CodeBox engine from the command line, talking to CodeRook.
9
10
  *
@@ -40,6 +41,7 @@ const issue_command_js_1 = require("./issue_command.js");
40
41
  const verify_command_js_1 = require("./verify_command.js");
41
42
  const community_command_js_1 = require("./community_command.js");
42
43
  const pr_command_js_1 = require("./pr_command.js");
44
+ const settings_commands_js_1 = require("./settings_commands.js");
43
45
  const project_commands_js_1 = require("./project_commands.js");
44
46
  const track_commands_js_1 = require("./track_commands.js");
45
47
  const tracks_js_1 = require("../../cbx/src/core/tracks.js");
@@ -52,6 +54,8 @@ const worktree_js_1 = require("../../cbx/src/core/worktree.js");
52
54
  const rules_js_1 = require("../../cbx/src/core/rules.js");
53
55
  const upload_js_1 = require("../../cbx/src/core/upload.js");
54
56
  const download_js_1 = require("../../cbx/src/core/download.js");
57
+ const machine_js_1 = require("./machine.js");
58
+ const workspace_machine_js_1 = require("./workspace_machine.js");
55
59
  const safe_path_js_1 = require("../../cbx/src/shared/safe_path.js");
56
60
  const faults_js_1 = require("../../cbx/src/core/faults.js");
57
61
  const version_commands_js_1 = require("./version_commands.js");
@@ -430,6 +434,30 @@ async function commandLink(parsed) {
430
434
  console.log(dim(` ${accent("cbx status")} shows how this folder differs from it; nothing was sent or fetched.`));
431
435
  return 0;
432
436
  }
437
+ /**
438
+ * Run a folder command, then tell the project which version this machine's
439
+ * folder now holds (machine.ts): after a save nothing is left unsent, after a
440
+ * fetch the count is not known without scanning again.
441
+ */
442
+ function announcing(run, saved) {
443
+ return async (parsed) => {
444
+ const code = await run(parsed);
445
+ if (code === 0) {
446
+ const folder = folderFor(parsed);
447
+ const link = await (0, config_js_1.readLink)(folder).catch(() => null);
448
+ if (link) {
449
+ await (0, machine_js_1.checkIn)(link.repositoryId, {
450
+ kind: "folder",
451
+ folder,
452
+ track: link.track ?? null,
453
+ baseVersionId: link.baseVersionId ?? link.versionId ?? null,
454
+ changedFiles: saved ? 0 : null,
455
+ });
456
+ }
457
+ }
458
+ return code;
459
+ };
460
+ }
433
461
  async function commandStatus(parsed) {
434
462
  const folder = folderFor(parsed);
435
463
  let link;
@@ -461,6 +489,14 @@ async function commandStatus(parsed) {
461
489
  const found = await (0, worktree_js_1.changedFiles)(folder, rules, baseline, "synchronize");
462
490
  const gone = found.filter((file) => file.deleted);
463
491
  const files = found.filter((file) => !file.deleted);
492
+ // Tells the project's Actions page what this machine's folder holds; never delays or fails status.
493
+ void (0, machine_js_1.checkIn)(link?.repositoryId, {
494
+ kind: "folder",
495
+ folder,
496
+ track: link?.track ?? null,
497
+ baseVersionId: link?.baseVersionId ?? link?.versionId ?? null,
498
+ changedFiles: found.length,
499
+ });
464
500
  console.log(bold(node_path_1.default.basename(folder)) + dim(` ${folder}`));
465
501
  console.log(link
466
502
  ? `Account holds ${accent(`v${link.sequence}`)} · ${Object.keys(link.manifest).length} ${Object.keys(link.manifest).length === 1 ? "file" : "files"} ${dim(`(${link.slug})`)}`
@@ -688,7 +724,7 @@ async function commandImport(parsed) {
688
724
  flags: submitFlags,
689
725
  });
690
726
  if (code === 0 && plan.temporary) {
691
- console.log(dim(`The working copy stays at ${plan.folder} until you remove it.
727
+ console.log(dim(`The working copy stays at ${plan.folder} until you remove it.
692
728
  ` +
693
729
  `Run ${accent("cbx get " + plan.name)} anywhere to fetch it fresh.`));
694
730
  }
@@ -974,17 +1010,17 @@ async function commandSubmit(parsed) {
974
1010
  */
975
1011
  const shielded = (await (0, worktree_js_1.detectPrivateDirectories)(folder)).filter((finding) => [...sending].some((file) => file === finding.path || file.startsWith(`${finding.path}/`)));
976
1012
  if (shielded.length && !hasFlag(parsed, "allow-private")) {
977
- console.log(red(`
1013
+ console.log(red(`
978
1014
  ${shielded.length} folder${shielded.length === 1 ? "" : "s"} here belong${shielded.length === 1 ? "s" : ""} to a program, not to your project:`));
979
1015
  for (const finding of shielded) {
980
1016
  console.log(` ${finding.path} ${dim(`— ${finding.because}`)}`);
981
1017
  }
982
- console.log(`
1018
+ console.log(`
983
1019
  Nothing was sent. To leave them behind:`);
984
1020
  for (const finding of shielded) {
985
1021
  console.log(` ${accent(`echo "${finding.rule}" >> .gitignore`)}`);
986
1022
  }
987
- console.error(`
1023
+ console.error(`
988
1024
  Or pass ${accent("--allow-private")} if they genuinely belong in the project.`);
989
1025
  return 1;
990
1026
  }
@@ -1033,7 +1069,7 @@ Or pass ${accent("--allow-private")} if they genuinely belong in the project.`);
1033
1069
  `rest were not opened.`));
1034
1070
  }
1035
1071
  if (stillPasted.length) {
1036
- console.log(red(`
1072
+ console.log(red(`
1037
1073
  ${stillPasted.length} file${stillPasted.length === 1 ? " has a credential" : "s have credentials"} inside:`));
1038
1074
  for (const finding of stillPasted.slice(0, 20)) {
1039
1075
  console.log(` ${finding.path}`);
@@ -1048,11 +1084,11 @@ ${stillPasted.length} file${stillPasted.length === 1 ? " has a credential" : "s
1048
1084
  console.log(dim(` …and ${stillPasted.length - 20} more`));
1049
1085
  }
1050
1086
  if (!hasFlag(parsed, "allow-secrets")) {
1051
- console.error(`
1087
+ console.error(`
1052
1088
  Nothing was sent. Move the key into an environment variable, and if` +
1053
1089
  ` it has ever been published, replace it at the service that issued` +
1054
1090
  ` it — a key that has leaked stays leaked.` +
1055
- `
1091
+ `
1056
1092
  Pass ${accent("--allow-secrets")} if these are not real keys.`);
1057
1093
  return 1;
1058
1094
  }
@@ -1258,7 +1294,7 @@ Pass ${accent("--allow-secrets")} if these are not real keys.`);
1258
1294
  continue;
1259
1295
  }
1260
1296
  if (failure?.kind === "interrupted") {
1261
- console.error(red(`
1297
+ console.error(red(`
1262
1298
  The connection failed: ${text}`));
1263
1299
  console.error(`Your work may already have been saved. Run the same command again —` +
1264
1300
  ` it will not create a second version.`);
@@ -1501,7 +1537,7 @@ async function commandGet(parsed) {
1501
1537
  `changed while the interrupted fetch was stopped:`));
1502
1538
  for (const file of changedInTheGap.slice(0, 20))
1503
1539
  console.error(` ${file.path}`);
1504
- console.error(`
1540
+ console.error(`
1505
1541
  Save them with ${accent("cbx submit")}, or finish the fetch and ` +
1506
1542
  `discard them with ${accent("cbx get --replace")}.`);
1507
1543
  return 1;
@@ -1784,8 +1820,8 @@ async function suggestRules(folder, apply) {
1784
1820
  const addition = (0, detect_js_1.rulesFromSuggestions)(recommended);
1785
1821
  const shared = rules.shared.trimEnd();
1786
1822
  await (0, worktree_js_1.writeRules)(folder, {
1787
- shared: shared ? `${shared}
1788
-
1823
+ shared: shared ? `${shared}
1824
+
1789
1825
  ${addition}` : addition,
1790
1826
  local: rules.local,
1791
1827
  });
@@ -1990,7 +2026,7 @@ async function commandMerges(parsed) {
1990
2026
  const counts = merge.conflicts;
1991
2027
  console.log(`${accent(merge.reference)} ${counts ? `${counts.unresolved} of ${counts.total} still to decide` : ""} ${dim(new Date(merge.createdAt).toLocaleString())}`);
1992
2028
  }
1993
- console.log(dim(`
2029
+ console.log(dim(`
1994
2030
  Run cbx merge <reference> to look at one.`));
1995
2031
  return 0;
1996
2032
  }
@@ -2093,7 +2129,7 @@ async function commandMerge(parsed) {
2093
2129
  console.log(dim(` waiting on ${waiting.map((person) => person.displayName).join(", ")}`));
2094
2130
  }
2095
2131
  }
2096
- console.log(`
2132
+ console.log(`
2097
2133
  ${accent(now.mergeTrack.reference)} · ` +
2098
2134
  /*
2099
2135
  The combined version is only counted once it can be built; until then
@@ -2112,7 +2148,7 @@ ${accent(now.mergeTrack.reference)} · ` +
2112
2148
  return 1;
2113
2149
  }
2114
2150
  const applied = await (0, api_js_1.applyMerge)(summary.id);
2115
- console.log(`
2151
+ console.log(`
2116
2152
  Applied as ${accent(`v${applied.version.sequence}`)}.`);
2117
2153
  if (applied.closedIssues?.length) {
2118
2154
  console.log(`Closed ${applied.closedIssues.map((number) => `#${number}`).join(", ")}.`);
@@ -2122,13 +2158,13 @@ Applied as ${accent(`v${applied.version.sequence}`)}.`);
2122
2158
  }
2123
2159
  const stillOpen = now.conflicts.some((conflict) => !conflict.resolvedAt);
2124
2160
  if (!decision && stillOpen) {
2125
- console.log(dim(`
2161
+ console.log(dim(`
2126
2162
  --mine keeps yours, --theirs keeps what was already saved,` +
2127
- ` --both keeps theirs and saves yours beside it, --drop removes the file.
2163
+ ` --both keeps theirs and saves yours beside it, --drop removes the file.
2128
2164
  Add --path <file> for one file, then --apply when ready.`));
2129
2165
  }
2130
2166
  else if (now.provisional.ready) {
2131
- console.log(dim(`
2167
+ console.log(dim(`
2132
2168
  Run cbx merge ${now.mergeTrack.reference} --apply to publish it.`));
2133
2169
  }
2134
2170
  return 0;
@@ -2286,7 +2322,7 @@ const SPECS = [
2286
2322
  },
2287
2323
  {
2288
2324
  name: "status",
2289
- group: "Working with a folder",
2325
+ group: "Saving work",
2290
2326
  summary: "what is here that is not saved yet",
2291
2327
  usage: "status [folder]",
2292
2328
  detail: "Compares the folder against the last version you sent and lists what\n" +
@@ -2298,7 +2334,7 @@ const SPECS = [
2298
2334
  {
2299
2335
  name: "submit",
2300
2336
  aliases: ["publish"],
2301
- group: "Working with a folder",
2337
+ group: "Saving work",
2302
2338
  summary: "send the changes as a new save",
2303
2339
  usage: 'submit [folder] -m "…"',
2304
2340
  detail: "Sends everything that changed since the last save. If the folder is\n" +
@@ -2347,12 +2383,12 @@ const SPECS = [
2347
2383
  'cbx submit --into voxai-coder -m "First save from the Linux machine"',
2348
2384
  'cbx submit --track spike -m "Try the other encoder"',
2349
2385
  ],
2350
- run: commandSubmit,
2386
+ run: announcing(commandSubmit, true),
2351
2387
  },
2352
2388
  {
2353
2389
  name: "diff",
2354
2390
  aliases: ["changes"],
2355
- group: "Working with a folder",
2391
+ group: "Saving work",
2356
2392
  summary: "what changed, line by line",
2357
2393
  usage: "diff [from] [to]",
2358
2394
  detail: "With nothing after it, compares this folder against the version it is\n" +
@@ -2429,6 +2465,7 @@ const SPECS = [
2429
2465
  group: "History on this machine",
2430
2466
  summary: "put files back the way a save had them",
2431
2467
  usage: "restore [paths…] [--from <save>]",
2468
+ brief: "restore [paths…]",
2432
2469
  detail: "With no paths, makes the whole folder match the save; with paths,\n" +
2433
2470
  "only those files and folders. The default is the last save, which\n" +
2434
2471
  "throws away what you changed since.\n\n" +
@@ -2463,7 +2500,7 @@ const SPECS = [
2463
2500
  },
2464
2501
  {
2465
2502
  name: "link",
2466
- group: "Working with a folder",
2503
+ group: "Getting started",
2467
2504
  summary: "connect this folder to a project already on your account",
2468
2505
  usage: "link <project> [folder]",
2469
2506
  detail: "Says which project this folder is a copy of, without sending or\n" +
@@ -2477,7 +2514,7 @@ const SPECS = [
2477
2514
  },
2478
2515
  {
2479
2516
  name: "unlink",
2480
- group: "Working with a folder",
2517
+ group: "Getting started",
2481
2518
  summary: "detach this folder from its project",
2482
2519
  usage: "unlink [folder]",
2483
2520
  detail: "Forgets which project this folder belongs to. Nothing is deleted:\n" +
@@ -2566,7 +2603,7 @@ const SPECS = [
2566
2603
  */
2567
2604
  name: "track",
2568
2605
  aliases: ["checkout"],
2569
- group: "Working with a folder",
2606
+ group: "Saving work",
2570
2607
  summary: "show or change the line this folder saves to",
2571
2608
  usage: "track [name]",
2572
2609
  detail: "With no name, prints the line this folder saves to. With one, switches\n" +
@@ -2587,7 +2624,7 @@ const SPECS = [
2587
2624
  {
2588
2625
  name: "tracks",
2589
2626
  aliases: ["branch", "branches"],
2590
- group: "Your projects",
2627
+ group: "Lines, merges and pull requests",
2591
2628
  summary: "the lines a project has, and any waiting on a decision",
2592
2629
  usage: "tracks [project]",
2593
2630
  detail: "Lists every line on the project, marking the one this folder saves to.\n" +
@@ -2599,17 +2636,17 @@ const SPECS = [
2599
2636
  },
2600
2637
  {
2601
2638
  name: "get",
2602
- group: "Working with a folder",
2639
+ group: "Saving work",
2603
2640
  summary: "bring this folder up to date",
2604
2641
  usage: "get [folder]",
2605
2642
  options: [
2606
2643
  { flags: "--replace", description: "make it an exact copy, discarding local changes" },
2607
2644
  ],
2608
- run: commandGet,
2645
+ run: announcing(commandGet, false),
2609
2646
  },
2610
2647
  {
2611
2648
  name: "clone",
2612
- group: "Working with a folder",
2649
+ group: "Getting started",
2613
2650
  summary: "fetch a project into a new folder",
2614
2651
  usage: "clone <project> [dir]",
2615
2652
  options: [
@@ -2624,7 +2661,7 @@ const SPECS = [
2624
2661
  {
2625
2662
  name: "licence",
2626
2663
  aliases: ["license"],
2627
- group: "Working with a folder",
2664
+ group: "Saving work",
2628
2665
  summary: "choose a licence, so people may actually use your work",
2629
2666
  usage: "licence [name] [folder]",
2630
2667
  detail: "A project with no licence cannot be used by anybody, whatever else it\n" +
@@ -2654,7 +2691,7 @@ const SPECS = [
2654
2691
  {
2655
2692
  name: "ignore",
2656
2693
  aliases: ["rules"],
2657
- group: "Working with a folder",
2694
+ group: "Saving work",
2658
2695
  summary: "show the ignore rules for this folder",
2659
2696
  usage: "ignore [folder]",
2660
2697
  detail: "The local list of things not to send — build output, dependencies,\n" +
@@ -2688,14 +2725,14 @@ const SPECS = [
2688
2725
  },
2689
2726
  {
2690
2727
  name: "projects",
2691
- group: "Your projects",
2728
+ group: "Getting started",
2692
2729
  summary: "every project on your account",
2693
2730
  usage: "projects",
2694
2731
  run: () => commandProjects(),
2695
2732
  },
2696
2733
  {
2697
2734
  name: "versions",
2698
- group: "Your projects",
2735
+ group: "Versions and releases",
2699
2736
  summary: "what has been saved to a project",
2700
2737
  usage: "versions [project]",
2701
2738
  detail: "Newest first. Run it inside a linked folder to leave the name out.\n\n" +
@@ -2716,9 +2753,10 @@ const SPECS = [
2716
2753
  },
2717
2754
  {
2718
2755
  name: "workspace",
2719
- group: "Your projects",
2756
+ group: "Workspaces",
2720
2757
  summary: "edit, save and run a private project remotely without a checkout",
2721
- usage: "workspace <open|list|show|read|files|search|diff|patch|save|run|logs|cancel|deploy|preview|handoff|close|recipe> <project> [workspace] [job]",
2758
+ usage: "workspace <open|list|show|read|files|search|diff|patch|save|run|logs|cancel|deploy|preview|handoff|close|recipe|assign|assignments|unassign|checkout> <project> [workspace] [job] | workspace push [folder]",
2759
+ brief: "workspace <action> <project>",
2722
2760
  detail: "Works on CodeRook's durable remote draft, never the current local folder. Use --data-file for structured edits or recipe configuration. Mutations need the reviewed --revision and a unique --key; reuse the same key and request when retrying. Recipes reference existing project workflows. Saving and deploying are separate operations.",
2723
2761
  options: [
2724
2762
  { flags: "--data-file <path>", description: "read an operation's JSON from this local file" },
@@ -2737,32 +2775,40 @@ const SPECS = [
2737
2775
  { flags: "--version <id>", description: "saved workspace version to deploy" },
2738
2776
  { flags: "-m, --message <text>", description: "describe the version being saved" },
2739
2777
  { flags: "--note <text>", description: "task context for another computer/assistant" },
2778
+ { flags: "--days <number>", description: "assign: how long the handed-over token lasts (1-90, default 14)" },
2779
+ { flags: "--save", description: "push: save the draft after sending the changes" },
2780
+ { flags: "--dry-run", description: "push: list what would be sent, send nothing" },
2740
2781
  ],
2741
- examples: ["cbx workspace open my-project --name \"Laptop work\" --key laptop-open-001", "cbx workspace list my-project"],
2782
+ examples: ["cbx workspace open my-project --name \"Laptop work\" --key laptop-open-001", "cbx workspace list my-project", "cbx workspace assign my-project <draft> --name Laptop", "cbx workspace checkout my-project <draft>", "cbx workspace push --save -m \"Fix the export dialog\""],
2742
2783
  run: workspace_command_js_1.commandWorkspace,
2743
2784
  },
2785
+ {
2786
+ name: "machines",
2787
+ group: "Actions and builds",
2788
+ summary: "the PCs on a project, how far behind each is, and its runners",
2789
+ usage: "machines [project]",
2790
+ detail: "Every PC with a folder linked to the project, or working on a draft handed to it, says which version it holds when cbx runs there. " +
2791
+ "This lists them with how many versions behind the project's line each is and how many files it has not saved, then the project's runners. " +
2792
+ "Machines not seen for 30 days are left out. Set CODEROOK_NO_PRESENCE to keep a machine off the list.",
2793
+ examples: ["cbx machines", "cbx machines my-project"],
2794
+ run: async (parsed) => (0, workspace_machine_js_1.commandMachines)(parsed, (await (0, config_js_1.readLink)(folderFor(parsed)).catch(() => null))?.repositoryId ?? null),
2795
+ },
2744
2796
  {
2745
2797
  name: "ai",
2746
- group: "Your projects",
2747
- summary: "what this project says about machines",
2748
- usage: "ai [project] [--read off]",
2749
- detail: "Shows the four answers a project gives about automated clients, and\n" +
2750
- "changes them. Everything is allowed until you say otherwise.\n\n" +
2798
+ group: "Project settings",
2799
+ summary: "what this project lets AI do (read only)",
2800
+ usage: "ai [project]",
2801
+ detail: "Shows the four answers a project gives about automated clients: can AI\n" +
2802
+ "read it, download it, contribute to it, and make requests to it.\n" +
2803
+ "Everything is allowed until somebody says otherwise.\n\n" +
2751
2804
  "Turning reading off is the one that refuses model training: it declares\n" +
2752
2805
  "the project as not-for-training in the page, in the response headers,\n" +
2753
- "and in the service's robots.txt. Turning downloads off does not — those\n" +
2754
- "are separate questions and answering one says nothing about the other.",
2755
- options: [
2756
- { flags: "--read [off]", description: "reading, indexing, summarising, training" },
2757
- { flags: "--download [off]", description: "taking the files" },
2758
- { flags: "--contribute [off]", description: "automated contributions" },
2759
- { flags: "--request [off]", description: "automated calls to its endpoints" },
2760
- ],
2761
- examples: [
2762
- "cbx ai my-project",
2763
- "cbx ai my-project --read off",
2764
- "cbx ai my-project --download off --request off",
2765
- ],
2806
+ "and in the service's robots.txt.\n\n" +
2807
+ "These are changed by a person, on the website (the project's Settings →\n" +
2808
+ "Access & AI) or in the desktop app, never from the command line. The\n" +
2809
+ "service refuses the change from any token, so an assistant holding one\n" +
2810
+ "cannot switch off the rule that keeps it out.",
2811
+ examples: ["cbx ai", "cbx ai my-project"],
2766
2812
  run: project_commands_js_1.commandAi,
2767
2813
  },
2768
2814
  {
@@ -2771,7 +2817,7 @@ const SPECS = [
2771
2817
  release. This is who can reach the project, and it is named for that.
2772
2818
  */
2773
2819
  name: "visibility",
2774
- group: "Your projects",
2820
+ group: "Project settings",
2775
2821
  summary: "who can reach a project: private, link only or public",
2776
2822
  usage: "visibility [level] [project]",
2777
2823
  detail: "The level is public, unlisted or private. With none, says what the\n" +
@@ -2794,9 +2840,158 @@ const SPECS = [
2794
2840
  ],
2795
2841
  run: project_commands_js_1.commandVisibility,
2796
2842
  },
2843
+ {
2844
+ /*
2845
+ Not `name` or `rename`, which read as acting on a file or a line. This
2846
+ is what the project says about itself: the website's Settings → General.
2847
+ */
2848
+ name: "about",
2849
+ group: "Project settings",
2850
+ summary: "a project's name, description and address",
2851
+ usage: "about [project] [--name <text>] [--description <text>]",
2852
+ brief: "about [project]",
2853
+ detail: "Shows the project's name, description, address and visibility, and\n" +
2854
+ "changes the name or the description. The address comes from the\n" +
2855
+ "project's short name, which stays as it is. An empty description\n" +
2856
+ "clears it.",
2857
+ options: [
2858
+ { flags: "--name <text>", description: "what the project is called" },
2859
+ { flags: "--description <text>", description: "one or two sentences about it" },
2860
+ { flags: "--project <name>", description: "a project other than this folder's" },
2861
+ ],
2862
+ examples: [
2863
+ "cbx about",
2864
+ 'cbx about --name "Night Owl Diner"',
2865
+ 'cbx about my-project --description "A diner sim set after midnight."',
2866
+ ],
2867
+ run: settings_commands_js_1.commandAbout,
2868
+ },
2869
+ {
2870
+ /*
2871
+ Beside `cbx tracks` rather than inside it. That lists where somebody can
2872
+ save and is read all day; these are the rules an owner sets once.
2873
+ */
2874
+ name: "line-rules",
2875
+ group: "Lines, merges and pull requests",
2876
+ summary: "protection, approvals and required checks on each line",
2877
+ usage: "line-rules [line] [--protect|--unprotect] [--approvals <n>] [--checks <a,b>] [--code-owners on|off] [--project <p>]",
2878
+ brief: "line-rules [line] [options]",
2879
+ detail: "With no line, lists every line with its rules and the code owners read\n" +
2880
+ "from the default line's CODEOWNERS file. Name a line to change it — the\n" +
2881
+ "website's Settings → Lines & reviews. Only the owner and admins can.\n\n" +
2882
+ "A protected line refuses restores and merges that would overwrite it.\n" +
2883
+ "Approvals is how many people must approve before a merge may land (0 to\n" +
2884
+ "10). Checks are the names that must pass, comma separated; none clears\n" +
2885
+ "them. Code owners on means a code owner of what changed must approve.",
2886
+ options: [
2887
+ { flags: "--protect", description: "protect the line" },
2888
+ { flags: "--unprotect", description: "stop protecting it" },
2889
+ { flags: "--approvals <n>", description: "approvals a merge needs, 0 to 10" },
2890
+ { flags: "--checks <a,b>", description: "checks that must pass; none for no checks" },
2891
+ { flags: "--code-owners <on|off>", description: "whether a code owner must approve" },
2892
+ { flags: "--project <name>", description: "a project other than this folder's" },
2893
+ ],
2894
+ examples: [
2895
+ "cbx line-rules",
2896
+ "cbx line-rules main --protect --approvals 1",
2897
+ "cbx line-rules main --checks build,test --code-owners on",
2898
+ "cbx line-rules release --unprotect --checks none",
2899
+ ],
2900
+ run: settings_commands_js_1.commandLineRules,
2901
+ },
2902
+ {
2903
+ name: "upload-rules",
2904
+ group: "Project settings",
2905
+ summary: "what uploads leave out, and encrypting secret files",
2906
+ usage: "upload-rules [--ignore <file>] [--keep <file>] [--encrypt on|off] [--warn-large <MiB>] [--hold-pushes on|off] [--project <p>]",
2907
+ brief: "upload-rules [options]",
2908
+ detail: "The project's upload rules — the website's Settings → Files & privacy →\n" +
2909
+ "Encrypted uploads. The desktop app and the website's scans read them.\n" +
2910
+ "Ignore rules leave files out; keep rules bring back what an ignore rule\n" +
2911
+ "caught. Both are read from a file of patterns, one per line, in the\n" +
2912
+ "shape of a .gitignore; none clears them. This folder's own ignore file\n" +
2913
+ "is `cbx ignore`.\n\n" +
2914
+ "--encrypt covers files recognised as secrets before they are stored.\n" +
2915
+ "--hold-pushes makes saves from anybody below admin wait for an admin to\n" +
2916
+ "accept them (see `cbx held`). Owners and admins change these.",
2917
+ options: [
2918
+ { flags: "--ignore <file>", description: "replace the ignore rules with this file's" },
2919
+ { flags: "--keep <file>", description: "replace the keep rules with this file's" },
2920
+ { flags: "--encrypt <on|off>", description: "encrypt files recognised as secrets" },
2921
+ { flags: "--warn-large <MiB>", description: "warn about files larger than this" },
2922
+ { flags: "--hold-pushes <on|off>", description: "saves below admin wait to be accepted" },
2923
+ { flags: "--project <name>", description: "a project other than this folder's" },
2924
+ ],
2925
+ examples: [
2926
+ "cbx upload-rules",
2927
+ "cbx upload-rules --ignore .coderookignore --warn-large 512",
2928
+ "cbx upload-rules --encrypt on --keep none",
2929
+ ],
2930
+ run: settings_commands_js_1.commandUploadRules,
2931
+ },
2932
+ {
2933
+ name: "assistant",
2934
+ group: "Project settings",
2935
+ summary: "the pull-request assistant: when it works and what it may do",
2936
+ usage: "assistant [manual|automated] [project] [--review on|off] [--describe on|off] [--suggest on|off] [--change on|off] [--approve on|off] [--merge on|off]",
2937
+ brief: "assistant [manual|automated]",
2938
+ detail: "Manual means it works only when somebody asks on a pull request.\n" +
2939
+ "Automated means it works on its own, doing what is switched on:\n" +
2940
+ "reviewing, describing, suggesting, changing, approving and merging.\n" +
2941
+ "Merging needs approving on too. Automated comes with a subscription on\n" +
2942
+ "the owner's account. Only the project's admins change it — the\n" +
2943
+ "website's Settings → Automation.",
2944
+ options: [
2945
+ { flags: "--review <on|off>", description: "review each pull request" },
2946
+ { flags: "--describe <on|off>", description: "write the description" },
2947
+ { flags: "--suggest <on|off>", description: "suggest changes" },
2948
+ { flags: "--change <on|off>", description: "make changes when asked" },
2949
+ { flags: "--approve <on|off>", description: "approve when it finds nothing" },
2950
+ { flags: "--merge <on|off>", description: "merge what it approved (needs --approve on)" },
2951
+ { flags: "--project <name>", description: "a project other than this folder's" },
2952
+ ],
2953
+ examples: [
2954
+ "cbx assistant",
2955
+ "cbx assistant automated --review on --describe on",
2956
+ "cbx assistant --approve on --merge on",
2957
+ "cbx assistant manual",
2958
+ ],
2959
+ run: settings_commands_js_1.commandAssistant,
2960
+ },
2961
+ {
2962
+ /*
2963
+ Not `transfer`, which already brings a project in from GitHub, GitLab
2964
+ or Codeberg. This hands one of yours to somebody else.
2965
+ */
2966
+ name: "hand-over",
2967
+ group: "Project settings",
2968
+ summary: "offer a project to another owner, or answer an offer",
2969
+ usage: "hand-over <username|email> [project] [--drop-access] [--yes] | hand-over offers | hand-over accept|decline|cancel <project>",
2970
+ brief: "hand-over <user> [project]",
2971
+ detail: "Offers the project to another account, as the website's Settings →\n" +
2972
+ "Danger zone does. Nothing moves until they accept, and the offer lapses\n" +
2973
+ "after fourteen days. Once accepted it is theirs, and only they can give\n" +
2974
+ "it back, so this asks for TRANSFER to be typed unless --yes is given.\n" +
2975
+ "Only the owner can offer a project.\n\n" +
2976
+ "You keep admin access afterwards unless --drop-access says otherwise.\n" +
2977
+ "`hand-over offers` lists offers to you and by you; accept or decline one\n" +
2978
+ "made to you, or cancel one you made.",
2979
+ options: [
2980
+ { flags: "--drop-access", description: "give up your access when they accept" },
2981
+ { flags: "-y, --yes", description: "offer it without asking, for scripts" },
2982
+ { flags: "--project <name>", description: "a project other than this folder's" },
2983
+ ],
2984
+ examples: [
2985
+ "cbx hand-over sam my-project",
2986
+ "cbx hand-over sam@example.com --drop-access",
2987
+ "cbx hand-over offers",
2988
+ "cbx hand-over accept night-owl-diner",
2989
+ ],
2990
+ run: settings_commands_js_1.commandHandOver,
2991
+ },
2797
2992
  {
2798
2993
  name: "pages",
2799
- group: "Your projects",
2994
+ group: "Project settings",
2800
2995
  summary: "serve a public project as a website",
2801
2996
  usage: "pages [auto|on|off] [project]",
2802
2997
  detail: "With no word, says whether the project's site is on, its address, which\n" +
@@ -2829,9 +3024,10 @@ const SPECS = [
2829
3024
  },
2830
3025
  {
2831
3026
  name: "private",
2832
- group: "Your projects",
3027
+ group: "Project settings",
2833
3028
  summary: "files and folders only the project's own people may see",
2834
3029
  usage: "private [list|add|remove|set] [pattern…] [--project <project>]",
3030
+ brief: "private [list|add|remove|set]",
2835
3031
  detail: "Keeps chosen files out of sight in a public project: visitors, the\n" +
2836
3032
  "public API, git clone, zips, Pages and search leave them out, while\n" +
2837
3033
  "members see everything. Patterns work like a .gitignore:\n\n" +
@@ -2854,9 +3050,10 @@ const SPECS = [
2854
3050
  },
2855
3051
  {
2856
3052
  name: "mods",
2857
- group: "Your projects",
3053
+ group: "Mods and bundles",
2858
3054
  summary: "mod repositories for games: set one up, publish to one",
2859
3055
  usage: "mods <create|repos|info|settings|builds|list|publish|remove|block|reports|delete> …",
3056
+ brief: "mods <action> …",
2860
3057
  detail: "A mod repository is where a game's players get mods from. Its owner\n" +
2861
3058
  "sets the rules — which file types a mod may hold, archives opened and\n" +
2862
3059
  "checked too, the manifest each upload carries, size limits, and whether\n" +
@@ -2920,7 +3117,7 @@ const SPECS = [
2920
3117
  },
2921
3118
  {
2922
3119
  name: "issues",
2923
- group: "Your projects",
3120
+ group: "Issues",
2924
3121
  summary: "issues on a project, or open one",
2925
3122
  usage: "issues [project]",
2926
3123
  detail: "Labels are given when the issue is opened rather than added\n" +
@@ -2942,20 +3139,39 @@ const SPECS = [
2942
3139
  },
2943
3140
  {
2944
3141
  name: "issue",
2945
- group: "Your projects",
2946
- summary: "read, answer, close, label or assign one issue",
2947
- usage: "issue view|comment|close|reopen|label|assign <number> … | issue labels | issue rules",
3142
+ group: "Issues",
3143
+ summary: "read, answer, close, label or assign one issue; labels and rules",
3144
+ usage: "issue view|comment|close|reopen|label|assign <number> … | issue labels [add|change|remove <name>] | issue rules [add <kind> | on|off|change|remove <n>]",
3145
+ brief: "issue <action> [number]",
2948
3146
  detail: "Closing says why: completed (the default), --reason not-planned, or\n" +
2949
3147
  "--duplicate-of <n>. Labels and assignment need write access; replying\n" +
2950
3148
  "needs only read access, as on the website.\n\n" +
3149
+ "The project's labels and issue rules are the website's Settings → Issues.\n" +
3150
+ "`issue labels` lists the labels; add, change and remove manage them.\n" +
3151
+ "`issue rules` lists the rules, numbered; a rule is changed by its number.\n" +
3152
+ "The kinds and what each takes:\n\n" +
3153
+ " auto-label --words <a,b> --label <name> [--in title|body|both]\n" +
3154
+ " auto-assign --assignees <a,b> [--label <name>]\n" +
3155
+ " welcome -m <message>\n" +
3156
+ " stale [--days <n>] [--close-after <n>] [--label] [-m] [--exempt <a,b>]\n\n" +
2951
3157
  "Inside a run, CODEROOK_TOKEN and CODEROOK_PROJECT are set, so a workflow\n" +
2952
3158
  "can comment on or label the issue that started it with no setup.",
2953
3159
  options: [
2954
- { flags: "-m, --message <text>", description: "what to say (comment, or a note when closing)" },
3160
+ { flags: "-m, --message <text>", description: "what to say (comment, a note when closing, a rule's message)" },
2955
3161
  { flags: "--reason <completed|not-planned>", description: "why it is closed" },
2956
3162
  { flags: "--duplicate-of <n>", description: "close as a duplicate of another issue" },
2957
3163
  { flags: "--remove", description: "take the labels off instead" },
2958
3164
  { flags: "--starter", description: "with labels: add the usual set" },
3165
+ { flags: "--colour <hex>", description: "labels add/change: its colour, like d73a4a" },
3166
+ { flags: "--description <text>", description: "labels add/change: what it is for" },
3167
+ { flags: "--name <text>", description: "labels change: rename it" },
3168
+ { flags: "--words <a,b>", description: "rules: words that earn the label (auto-label)" },
3169
+ { flags: "--label <name>", description: "rules: the label to add, or to act on" },
3170
+ { flags: "--in <where>", description: "rules: title, body or both (auto-label)" },
3171
+ { flags: "--assignees <a,b>", description: "rules: who to assign (auto-assign)" },
3172
+ { flags: "--days <n>", description: "rules: quiet days before an issue is stale" },
3173
+ { flags: "--close-after <n>", description: "rules: days after that before it is closed" },
3174
+ { flags: "--exempt <a,b>", description: "rules: labels that keep an issue from going stale" },
2959
3175
  { flags: "--project <name>", description: "which project" },
2960
3176
  ],
2961
3177
  examples: [
@@ -2965,13 +3181,18 @@ const SPECS = [
2965
3181
  "cbx issue label 12 bug,ui",
2966
3182
  "cbx issue assign 12 sam",
2967
3183
  "cbx issue labels --starter",
3184
+ 'cbx issue labels add crash --colour d73a4a --description "It falls over"',
3185
+ "cbx issue labels remove wontfix",
3186
+ "cbx issue rules add auto-label --words crash,freeze --label crash",
3187
+ 'cbx issue rules add welcome -m "Thanks — we read every report."',
3188
+ "cbx issue rules off 2",
2968
3189
  ],
2969
3190
  run: issue_command_js_1.commandIssue,
2970
3191
  },
2971
3192
  {
2972
3193
  name: "releases",
2973
3194
  aliases: ["tags"],
2974
- group: "Your projects",
3195
+ group: "Versions and releases",
2975
3196
  summary: "what has been released, and its files",
2976
3197
  usage: "releases [project]",
2977
3198
  detail: "Each release with its files and who can take them: public (source and\n" +
@@ -2989,7 +3210,7 @@ const SPECS = [
2989
3210
  */
2990
3211
  name: "hooks",
2991
3212
  aliases: ["webhooks"],
2992
- group: "Your projects",
3213
+ group: "Project settings",
2993
3214
  summary: "where this project tells something else what happened",
2994
3215
  usage: "hooks [project]",
2995
3216
  detail: "A signed POST to an address of yours when something happens here.\n" +
@@ -2999,17 +3220,31 @@ const SPECS = [
2999
3220
  "check.reported, change_request.opened, change_request.reviewed,\n" +
3000
3221
  "issue.opened, issue.closed, issue.reopened, issue.commented,\n" +
3001
3222
  "issue.labeled, run.finished, run.failed, release.published.\n" +
3002
- "Naming none of them sends all of them.",
3223
+ "Naming none of them sends all of them.\n\n" +
3224
+ "A hook is named by its id or its address. With only one hook on the\n" +
3225
+ "project, --test, --deliveries, --redeliver and --on need no name.\n" +
3226
+ "Twenty failures in a row switch a hook off; --on switches it back on\n" +
3227
+ "with a clean count.",
3003
3228
  options: [
3004
3229
  { flags: "--add <url>", description: "notify this address; https only" },
3005
- { flags: "--events <a,b>", description: "only these, comma separated" },
3230
+ { flags: "--events <a,b>", description: "only these, comma separated (with --hook: change them; all for every one)" },
3006
3231
  { flags: "--remove <id>", description: "stop notifying it" },
3232
+ { flags: "--hook <id>", description: "which hook --events or --redeliver is about" },
3233
+ { flags: "--test [id]", description: "send a signed ping now and say how it was answered" },
3234
+ { flags: "--deliveries [id]", description: "the most recent deliveries and how each went" },
3235
+ { flags: "--redeliver <delivery>", description: "send a delivery again (the start of its id is enough)" },
3236
+ { flags: "--on [id]", description: "switch a hook that was switched off back on" },
3007
3237
  { flags: "--project <name>", description: "which project" },
3008
3238
  ],
3009
3239
  examples: [
3010
3240
  "cbx hooks",
3011
3241
  "cbx hooks --add https://example.com/coderook",
3012
3242
  "cbx hooks --add https://example.com/builds --events version.published",
3243
+ "cbx hooks --test",
3244
+ "cbx hooks --deliveries 3f2a9c10-…",
3245
+ "cbx hooks --redeliver 7b1e04aa --hook 3f2a9c10-…",
3246
+ "cbx hooks --hook 3f2a9c10-… --events release.published,run.failed",
3247
+ "cbx hooks --on 3f2a9c10-…",
3013
3248
  ],
3014
3249
  run: service_commands_js_1.commandHooks,
3015
3250
  },
@@ -3022,7 +3257,7 @@ const SPECS = [
3022
3257
  This moves the project.
3023
3258
  */
3024
3259
  name: "undo",
3025
- group: "Your projects",
3260
+ group: "Versions and releases",
3026
3261
  summary: "put the project back on an earlier save",
3027
3262
  usage: "undo [n] [project]",
3028
3263
  detail: "Goes back one save unless you name another to go back to.\n\n" +
@@ -3041,7 +3276,7 @@ const SPECS = [
3041
3276
  actually offers.
3042
3277
  */
3043
3278
  name: "promote",
3044
- group: "Your projects",
3279
+ group: "Versions and releases",
3045
3280
  summary: "turn a commit into a version people can fetch",
3046
3281
  usage: "promote [n] [project]",
3047
3282
  detail: "Shows the last ten commits and asks which one. Give a number to skip\n" +
@@ -3077,7 +3312,7 @@ const SPECS = [
3077
3312
  hides it, labels it — which is what it does anyway.
3078
3313
  */
3079
3314
  name: "attach",
3080
- group: "Your projects",
3315
+ group: "Versions and releases",
3081
3316
  summary: "put a file people can download on a version",
3082
3317
  usage: "attach <file> [n] [project]",
3083
3318
  detail: "A version can carry downloads — an installer, a build, a changelog —\n" +
@@ -3102,7 +3337,7 @@ const SPECS = [
3102
3337
  {
3103
3338
  name: "notes",
3104
3339
  aliases: ["release-notes"],
3105
- group: "Your projects",
3340
+ group: "Versions and releases",
3106
3341
  summary: "read or write what a version says about itself",
3107
3342
  usage: "notes [n] [project]",
3108
3343
  detail: "The release info the website shows on a version, and the same field\n" +
@@ -3130,7 +3365,7 @@ const SPECS = [
3130
3365
  {
3131
3366
  name: "mark",
3132
3367
  aliases: ["set"],
3133
- group: "Your projects",
3368
+ group: "Versions and releases",
3134
3369
  summary: "name, hide, pin or label one save",
3135
3370
  usage: "mark [n] [project]",
3136
3371
  detail: "Changes the newest version unless you name another.\n" +
@@ -3162,9 +3397,10 @@ const SPECS = [
3162
3397
  },
3163
3398
  {
3164
3399
  name: "labels",
3165
- group: "Your projects",
3400
+ group: "Versions and releases",
3166
3401
  summary: "the labels this project puts on versions",
3167
3402
  usage: "labels [list|add|remove] [name] [colour]",
3403
+ brief: "labels [list|add|remove]",
3168
3404
  detail: "A label is a name and a colour. Put as many on a version as you like —\n" +
3169
3405
  "how you group and colour your own history is yours to decide.",
3170
3406
  examples: [
@@ -3178,7 +3414,7 @@ const SPECS = [
3178
3414
  {
3179
3415
  name: "held",
3180
3416
  aliases: ["waiting"],
3181
- group: "Your projects",
3417
+ group: "Versions and releases",
3182
3418
  summary: "versions waiting for somebody to approve them",
3183
3419
  usage: "held [project]",
3184
3420
  detail: "A project can be set to hold pushes from anyone below admin until an\n" +
@@ -3188,9 +3424,10 @@ const SPECS = [
3188
3424
  },
3189
3425
  {
3190
3426
  name: "review",
3191
- group: "Your projects",
3427
+ group: "Versions and releases",
3192
3428
  summary: "accept a held version, or turn it down",
3193
3429
  usage: "review <n> --approve | --decline",
3430
+ brief: "review <n> --approve|--decline",
3194
3431
  options: [
3195
3432
  {
3196
3433
  flags: "--approve",
@@ -3212,7 +3449,7 @@ const SPECS = [
3212
3449
  saying what was removed and by whom.
3213
3450
  */
3214
3451
  name: "take-down",
3215
- group: "Your projects",
3452
+ group: "Versions and releases",
3216
3453
  summary: "remove a version's files, for something published by mistake",
3217
3454
  usage: "take-down <n> --yes",
3218
3455
  detail: "The files go and do not come back. The version stays in the history as\n" +
@@ -3232,7 +3469,7 @@ const SPECS = [
3232
3469
  */
3233
3470
  name: "release",
3234
3471
  aliases: ["tag"],
3235
- group: "Your projects",
3472
+ group: "Versions and releases",
3236
3473
  summary: "give a version a name, so people know which one to fetch",
3237
3474
  usage: "release <name> [project]",
3238
3475
  detail: "Names the newest version unless you name another with --version.\n" +
@@ -3267,9 +3504,10 @@ const SPECS = [
3267
3504
  },
3268
3505
  {
3269
3506
  name: "fork",
3270
- group: "Your projects",
3507
+ group: "Project settings",
3271
3508
  summary: "your own copy of somebody's project, and offering work back",
3272
3509
  usage: "fork <owner/project> [--name <slug>] | fork offer [line] --title <text> | fork sync",
3510
+ brief: "fork <owner/project>",
3273
3511
  detail: "A fork is a private project under your account with the original's latest\n" +
3274
3512
  "public version (its private files left out). Nothing is uploaded again.\n\n" +
3275
3513
  "Inside a fork, `cbx fork offer <line>` offers that line to the original as\n" +
@@ -3288,32 +3526,44 @@ const SPECS = [
3288
3526
  },
3289
3527
  {
3290
3528
  name: "security",
3291
- group: "Your projects",
3292
- summary: "report a vulnerability privately, or handle reports",
3293
- usage: "security report <owner/project> --title <text> | security list | view|reply|mark S-<n>",
3529
+ group: "Project settings",
3530
+ summary: "report a vulnerability privately, handle reports, set the policy",
3531
+ usage: "security report <owner/project> --title <text> | security list | view|reply|mark S-<n> | security policy [--on|--off] [--text <file>]",
3532
+ brief: "security <action> [S-n]",
3294
3533
  detail: "A report is seen only by the project's owner and admins, and by whoever\n" +
3295
3534
  "sent it. Please use this rather than a public issue for anything that\n" +
3296
- "could hurt people using the project.",
3535
+ "could hurt people using the project.\n\n" +
3536
+ "`security policy` shows whether the project takes private reports and\n" +
3537
+ "what it tells people about sending one (the website's Settings →\n" +
3538
+ "Security). --text reads a file when one by that name exists, and uses\n" +
3539
+ "the words themselves otherwise. Owners and admins change it.",
3297
3540
  options: [
3298
3541
  { flags: "--title <text>", description: "report: what is wrong" },
3299
3542
  { flags: "--body <text>", description: "report: details and how to reproduce it" },
3300
3543
  { flags: "--severity <level>", description: "report: low, medium, high or critical" },
3301
3544
  { flags: "-m, --message <text>", description: "reply: what to say" },
3302
- { flags: "--project <name>", description: "list/view/reply/mark: which project" },
3545
+ { flags: "--on", description: "policy: take private reports" },
3546
+ { flags: "--off", description: "policy: stop taking them" },
3547
+ { flags: "--text <file or text>", description: "policy: the reporting policy" },
3548
+ { flags: "--clear", description: "policy: remove the written policy" },
3549
+ { flags: "--project <name>", description: "list/view/reply/mark/policy: which project" },
3303
3550
  ],
3304
3551
  examples: [
3305
3552
  'cbx security report sam/editor --title "Path traversal in export" --severity high',
3306
3553
  "cbx security list",
3307
3554
  'cbx security reply S-3 -m "Confirmed; fix in 2.0.1"',
3308
3555
  "cbx security mark S-3 fixed",
3556
+ "cbx security policy",
3557
+ "cbx security policy --on --text SECURITY.md",
3309
3558
  ],
3310
3559
  run: community_command_js_1.commandSecurity,
3311
3560
  },
3312
3561
  {
3313
3562
  name: "verify",
3314
- group: "Your projects",
3563
+ group: "Versions and releases",
3315
3564
  summary: "check a download against its release's signed manifest",
3316
3565
  usage: "verify <owner/project> <release> <file…>",
3566
+ brief: "verify <owner/project> …",
3317
3567
  detail: "Every public release has a manifest listing each file with its size and\n" +
3318
3568
  "SHA-256, signed with CodeRook's release key. This checks the signature,\n" +
3319
3569
  "then the files you downloaded. A mismatch means do not run it.",
@@ -3323,7 +3573,7 @@ const SPECS = [
3323
3573
  },
3324
3574
  {
3325
3575
  name: "deps",
3326
- group: "Your projects",
3576
+ group: "Versions and releases",
3327
3577
  summary: "known vulnerabilities in a save's dependencies",
3328
3578
  usage: "deps [version]",
3329
3579
  detail: "Reads the lockfiles in the save (package-lock.json, yarn.lock,\n" +
@@ -3341,7 +3591,7 @@ const SPECS = [
3341
3591
  {
3342
3592
  name: "actions",
3343
3593
  aliases: ["workflows"],
3344
- group: "Your projects",
3594
+ group: "Actions and builds",
3345
3595
  summary: "the automations a project has",
3346
3596
  usage: "actions [project]",
3347
3597
  detail: "Shows what each action runs, what it runs on, and how many of its\n" +
@@ -3381,9 +3631,10 @@ const SPECS = [
3381
3631
  },
3382
3632
  {
3383
3633
  name: "pr",
3384
- group: "Working with a folder",
3634
+ group: "Lines, merges and pull requests",
3385
3635
  summary: "pull requests: list, read, review, comment, merge",
3386
3636
  usage: "pr <list|view|files|comment|approve|request-changes|ask|label|title|ready|draft|retarget|close|reopen|merge> [M-3] …",
3637
+ brief: "pr <action> [M-3]",
3387
3638
  detail: "A pull request is a line offered to another line (cbx propose opens one).\n" +
3388
3639
  "This is the Pull requests tab of the website, from here:\n\n" +
3389
3640
  " list [--all|--state merged] [--mine] [--label bug] the project's pull requests\n" +
@@ -3426,7 +3677,7 @@ const SPECS = [
3426
3677
  },
3427
3678
  {
3428
3679
  name: "cancel",
3429
- group: "Actions",
3680
+ group: "Actions and builds",
3430
3681
  summary: "stop a run that is waiting or working",
3431
3682
  usage: "cancel <number> [project]",
3432
3683
  detail: "Marks the run cancelled at once. A runner working on it is told at its next\n" +
@@ -3436,7 +3687,7 @@ const SPECS = [
3436
3687
  },
3437
3688
  {
3438
3689
  name: "rerun",
3439
- group: "Actions",
3690
+ group: "Actions and builds",
3440
3691
  summary: "run a finished run again",
3441
3692
  usage: "rerun <number> [project]",
3442
3693
  detail: "Queues the same action against the same save. When the run was checking a\n" +
@@ -3446,7 +3697,7 @@ const SPECS = [
3446
3697
  },
3447
3698
  {
3448
3699
  name: "approve",
3449
- group: "Actions",
3700
+ group: "Actions and builds",
3450
3701
  summary: "let a run that waits for approval start",
3451
3702
  usage: "approve <number> [project]",
3452
3703
  detail: "An action marked as needing approval (often one that publishes) waits\n" +
@@ -3457,9 +3708,10 @@ const SPECS = [
3457
3708
  {
3458
3709
  name: "secret",
3459
3710
  aliases: ["secrets"],
3460
- group: "Actions",
3711
+ group: "Project settings",
3461
3712
  summary: "values runs need that must not be in the files",
3462
3713
  usage: "secret list | set <NAME> | remove <NAME>",
3714
+ brief: "secret list|set|remove [NAME]",
3463
3715
  detail: "A secret is handed to each run as an environment variable of the same\n" +
3464
3716
  "name, but only to runs started by people who can change the project.\n" +
3465
3717
  "Run logs show *** in its place. Its value is never shown again.\n\n" +
@@ -3480,7 +3732,7 @@ const SPECS = [
3480
3732
  },
3481
3733
  {
3482
3734
  name: "runs",
3483
- group: "Actions",
3735
+ group: "Actions and builds",
3484
3736
  summary: "what has run, and how it went",
3485
3737
  usage: "runs [project]",
3486
3738
  detail: "Newest first, with the machine that took each one. A run that is still\n" +
@@ -3497,7 +3749,7 @@ const SPECS = [
3497
3749
  },
3498
3750
  {
3499
3751
  name: "logs",
3500
- group: "Actions",
3752
+ group: "Actions and builds",
3501
3753
  summary: "what one run printed",
3502
3754
  usage: "logs <number> [project]",
3503
3755
  detail: "The output the runner sent up, in order. Anything the command wrote to\n" +
@@ -3509,7 +3761,7 @@ const SPECS = [
3509
3761
  },
3510
3762
  {
3511
3763
  name: "delete",
3512
- group: "Your projects",
3764
+ group: "Project settings",
3513
3765
  summary: "delete a project",
3514
3766
  usage: "delete [project]",
3515
3767
  detail: "Asks for the project name to be typed before it does anything. The\n" +
@@ -3521,25 +3773,34 @@ const SPECS = [
3521
3773
  {
3522
3774
  name: "people",
3523
3775
  aliases: ["collaborators"],
3524
- group: "People",
3525
- summary: "who can reach a project, and invite somebody",
3776
+ group: "Project settings",
3777
+ summary: "who can reach a project: invite, change a role, remove",
3526
3778
  usage: "people [project]",
3779
+ detail: "Lists the project's people and the invites waiting on a reply. Somebody\n" +
3780
+ "is named by their email address or display name, as the list shows them.\n" +
3781
+ "Only the project's owner and admins can see the list or change it.",
3527
3782
  options: [
3528
3783
  { flags: "--invite <email>", description: "ask somebody to join" },
3529
- { flags: "--role <role>", description: "write, read or admin (default write)" },
3784
+ { flags: "--role <role>", description: "write, read or admin (default write when inviting)" },
3785
+ { flags: "--change <who>", description: "give one of the project's people the --role named" },
3786
+ { flags: "--remove <who>", description: "take somebody off the project" },
3787
+ { flags: "--cancel-invite <email>", description: "withdraw an invite nobody has accepted" },
3530
3788
  { flags: "--accept <link>", description: "join a project you were invited to" },
3531
3789
  ],
3532
3790
  examples: [
3533
3791
  "cbx people my-project --invite sam@example.com",
3792
+ "cbx people --change sam@example.com --role admin",
3793
+ "cbx people --remove sam@example.com",
3534
3794
  "cbx people --accept https://coderook.com/?invite=…",
3535
3795
  ],
3536
3796
  run: service_commands_js_1.commandCollaborators,
3537
3797
  },
3538
3798
  {
3539
3799
  name: "watch",
3540
- group: "People",
3800
+ group: "Project settings",
3541
3801
  summary: "what reaches you about a project",
3542
3802
  usage: "watch [project] [--level versions]",
3803
+ brief: "watch [project]",
3543
3804
  options: [
3544
3805
  {
3545
3806
  flags: "--level <level>",
@@ -3551,7 +3812,7 @@ const SPECS = [
3551
3812
  },
3552
3813
  {
3553
3814
  name: "tokens",
3554
- group: "Other",
3815
+ group: "For assistants",
3555
3816
  summary: "the tokens that can act as your account",
3556
3817
  usage: "tokens",
3557
3818
  detail: "Lists personal access tokens with when each was last used, which is\n" +
@@ -3562,9 +3823,10 @@ const SPECS = [
3562
3823
  },
3563
3824
  {
3564
3825
  name: "propose",
3565
- group: "Working with a folder",
3826
+ group: "Lines, merges and pull requests",
3566
3827
  summary: "offer this folder's line to main",
3567
3828
  usage: 'propose -m "title" [--into main] [--body text] [folder]',
3829
+ brief: "propose -m \"title\" [folder]",
3568
3830
  options: [
3569
3831
  { flags: "-m, --message <text>", description: "the proposal's title" },
3570
3832
  { flags: "--into <line>", description: "the line to propose into (default main)" },
@@ -3579,7 +3841,7 @@ const SPECS = [
3579
3841
  },
3580
3842
  {
3581
3843
  name: "proposals",
3582
- group: "Working with a folder",
3844
+ group: "Lines, merges and pull requests",
3583
3845
  summary: "open proposals on this project",
3584
3846
  usage: "proposals [--all] [folder]",
3585
3847
  options: [{ flags: "--all", description: "include merged and cancelled ones" }],
@@ -3587,7 +3849,7 @@ const SPECS = [
3587
3849
  },
3588
3850
  {
3589
3851
  name: "merges",
3590
- group: "When somebody saved first",
3852
+ group: "Lines, merges and pull requests",
3591
3853
  summary: "this folder's uploads waiting on a decision",
3592
3854
  usage: "merges [folder]",
3593
3855
  detail: "Both merge commands read the project this folder is linked to, so run\n" +
@@ -3596,7 +3858,7 @@ const SPECS = [
3596
3858
  },
3597
3859
  {
3598
3860
  name: "merge",
3599
- group: "When somebody saved first",
3861
+ group: "Lines, merges and pull requests",
3600
3862
  summary: "merge a line here, or decide one waiting on CodeRook",
3601
3863
  usage: "merge <line | ref>",
3602
3864
  detail: "In a folder with a history of its own, merges a line or a save into\n" +
@@ -3620,21 +3882,21 @@ const SPECS = [
3620
3882
  },
3621
3883
  {
3622
3884
  name: "bundle",
3623
- group: "Bundles",
3885
+ group: "Mods and bundles",
3624
3886
  summary: "pack the project as a .cbx",
3625
3887
  usage: "bundle [folder] [out]",
3626
3888
  run: commandBundle,
3627
3889
  },
3628
3890
  {
3629
3891
  name: "unbundle",
3630
- group: "Bundles",
3892
+ group: "Mods and bundles",
3631
3893
  summary: "extract a .cbx",
3632
3894
  usage: "unbundle <file> [dir]",
3633
3895
  run: commandUnbundle,
3634
3896
  },
3635
3897
  {
3636
3898
  name: "inspect",
3637
- group: "Bundles",
3899
+ group: "Mods and bundles",
3638
3900
  summary: "what a .cbx contains",
3639
3901
  usage: "inspect <file>",
3640
3902
  options: [{ flags: "--files", description: "list every file inside" }],
@@ -3642,7 +3904,7 @@ const SPECS = [
3642
3904
  },
3643
3905
  {
3644
3906
  name: "runner",
3645
- group: "Actions",
3907
+ group: "Actions and builds",
3646
3908
  summary: "take this project's runs and do them here",
3647
3909
  usage: "runner <project>",
3648
3910
  detail: "Claims queued runs for a project and executes them on this machine.\n" +
@@ -3664,7 +3926,7 @@ const SPECS = [
3664
3926
  is a file in a folder, and this already knows where the folder is.
3665
3927
  */
3666
3928
  name: "skill",
3667
- group: "Other",
3929
+ group: "For assistants",
3668
3930
  summary: "teach Claude Code about CodeRook",
3669
3931
  usage: "skill [--project]",
3670
3932
  detail: "Writes a short guide into Claude Code's skills folder, so it knows what\n" +
@@ -3696,7 +3958,7 @@ const SPECS = [
3696
3958
  stdin and stdout, and exits with them.
3697
3959
  */
3698
3960
  name: "mcp",
3699
- group: "Other",
3961
+ group: "For assistants",
3700
3962
  summary: "serve CodeRook to Claude Code, Codex and other assistants",
3701
3963
  usage: "mcp [--workspaces]",
3702
3964
  options: [{ flags: "--workspaces", description: "opt into the remote connector's write/run/deploy tools and workspace permissions" }],
@@ -3724,7 +3986,7 @@ const SPECS = [
3724
3986
  },
3725
3987
  {
3726
3988
  name: "doctor",
3727
- group: "Other",
3989
+ group: "Getting started",
3728
3990
  summary: "check the service, config and sign-in",
3729
3991
  usage: "doctor",
3730
3992
  run: () => commandDoctor(),
@@ -3749,9 +4011,10 @@ function localTwin(name, original, local, row, extra) {
3749
4011
  }
3750
4012
  SPECS.push({
3751
4013
  name: "build",
3752
- group: "Actions",
4014
+ group: "Actions and builds",
3753
4015
  summary: "build executables for Windows, Linux and macOS on this machine",
3754
4016
  usage: "build [folder] [--target win,linux,mac]",
4017
+ brief: "build [folder] [--target …]",
3755
4018
  detail: "Builds the project in this folder for each target, using whatever this\n" +
3756
4019
  "machine has: Go, Bun, Deno and .NET build every platform from any one;\n" +
3757
4020
  "Rust does with cargo-zigbuild; Electron builds Linux from Windows with\n" +
@@ -3800,7 +4063,8 @@ SPECS.push(localTwin("push", "submit", local_commands_js_1.localPush, {
3800
4063
  "Anywhere else, this is `cbx get`.",
3801
4064
  examples: ["cbx pull", "cbx pull my-project"],
3802
4065
  }, [{ flags: "-f, --force", description: "discard unsaved changes that are in the way" }]));
3803
- const REGISTRY = (0, registry_js_1.buildRegistry)(SPECS);
4066
+ /* Exported for the help test (test/help_listing.test.ts); nothing else imports this file. */
4067
+ exports.REGISTRY = (0, registry_js_1.buildRegistry)(SPECS);
3804
4068
  async function main(argv) {
3805
4069
  const old = (0, node_check_js_1.nodeTooOld)();
3806
4070
  if (old) {
@@ -3809,7 +4073,7 @@ async function main(argv) {
3809
4073
  }
3810
4074
  const [name, ...rest] = argv;
3811
4075
  if (!name || name === "--help" || name === "-h") {
3812
- console.log((0, help_js_1.renderHelp)(REGISTRY, version_js_1.VERSION));
4076
+ console.log((0, help_js_1.renderHelp)(exports.REGISTRY, version_js_1.VERSION));
3813
4077
  return 0;
3814
4078
  }
3815
4079
  if (name === "--version" || name === "-v" || name === "version") {
@@ -3824,20 +4088,20 @@ async function main(argv) {
3824
4088
  if (name === "help") {
3825
4089
  const wanted = rest[0];
3826
4090
  if (!wanted) {
3827
- console.log((0, help_js_1.renderHelp)(REGISTRY, version_js_1.VERSION));
4091
+ console.log((0, help_js_1.renderHelp)(exports.REGISTRY, version_js_1.VERSION));
3828
4092
  return 0;
3829
4093
  }
3830
- const spec = REGISTRY.lookup.get(wanted);
4094
+ const spec = exports.REGISTRY.lookup.get(wanted);
3831
4095
  if (!spec) {
3832
- console.error((0, help_js_1.renderUnknown)(wanted, (0, registry_js_1.nearestCommand)(REGISTRY, wanted)));
4096
+ console.error((0, help_js_1.renderUnknown)(wanted, (0, registry_js_1.nearestCommand)(exports.REGISTRY, wanted)));
3833
4097
  return 1;
3834
4098
  }
3835
4099
  console.log((0, help_js_1.renderCommandHelp)(spec));
3836
4100
  return 0;
3837
4101
  }
3838
- const spec = REGISTRY.lookup.get(name);
4102
+ const spec = exports.REGISTRY.lookup.get(name);
3839
4103
  if (!spec) {
3840
- console.error((0, help_js_1.renderUnknown)(name, (0, registry_js_1.nearestCommand)(REGISTRY, name)));
4104
+ console.error((0, help_js_1.renderUnknown)(name, (0, registry_js_1.nearestCommand)(exports.REGISTRY, name)));
3841
4105
  return 1;
3842
4106
  }
3843
4107
  if (rest.includes("--help") || rest.includes("-h")) {
@@ -3860,10 +4124,17 @@ async function main(argv) {
3860
4124
  function leave(code) {
3861
4125
  node_process_1.default.exitCode = code;
3862
4126
  }
3863
- (0, network_js_1.tuneNetwork)();
3864
- main(node_process_1.default.argv.slice(2))
3865
- .then(leave)
3866
- .catch((error) => {
3867
- console.error(red((0, network_js_1.describeError)(error)));
3868
- leave(1);
3869
- });
4127
+ /*
4128
+ Run only when started as the program. A test loads this file to read the
4129
+ command table — that every command is listed once, and fits — and must not
4130
+ find itself running a command with the test runner's own arguments.
4131
+ */
4132
+ if (require.main === module) {
4133
+ (0, network_js_1.tuneNetwork)();
4134
+ main(node_process_1.default.argv.slice(2))
4135
+ .then(leave)
4136
+ .catch((error) => {
4137
+ console.error(red((0, network_js_1.describeError)(error)));
4138
+ leave(1);
4139
+ });
4140
+ }