@rness/cli 0.21.0 → 0.22.1

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.
@@ -17,6 +17,8 @@ import {
17
17
  approvalUrl,
18
18
  assembleContext,
19
19
  banner,
20
+ boardPushCommand,
21
+ boardRunCommand,
20
22
  boardUrl,
21
23
  bold,
22
24
  canOpenBrowser,
@@ -75,9 +77,6 @@ import {
75
77
  publish,
76
78
  pullFastForward,
77
79
  pulseCreateCommand,
78
- pulseMarkCommand,
79
- pulseRunCommand,
80
- pulseSyncCommand,
81
80
  readAuth,
82
81
  readBoards,
83
82
  readOrNull,
@@ -103,7 +102,7 @@ import {
103
102
  workspaceName,
104
103
  writeFileAtomic,
105
104
  writeManifest
106
- } from "./chunk-D3D2WCGW.js";
105
+ } from "./chunk-OUZQGG6V.js";
107
106
 
108
107
  // src/core/transport.ts
109
108
  import { spawn } from "child_process";
@@ -184,7 +183,7 @@ async function testGithubSsh(transport, interactive, announce) {
184
183
  }
185
184
  var loggedInAs = (login) => login === void 0 || login === null ? "" : `, logged in as ${login}`;
186
185
  function usingSentence(access, login) {
187
- return access.ok ? `SSH works for github.com (as ${access.login}) \u2014 repositories are cloned over SSH` : `No SSH access to github.com (${access.reason}) \u2014 repositories are cloned over HTTPS${loggedInAs(login)}`;
186
+ return access.ok ? `SSH works for github.com (as ${access.login}): repositories are cloned over SSH` : `No SSH access to github.com (${access.reason}): repositories are cloned over HTTPS${loggedInAs(login)}`;
188
187
  }
189
188
  function isSshUrl(url, hosts) {
190
189
  return url.startsWith(hosts.ssh);
@@ -193,7 +192,7 @@ var CHECKING_LINE = status("checking", "ssh access to github.com\u2026");
193
192
  var CHECKING = [
194
193
  "checking",
195
194
  "ssh access to github.com\u2026",
196
- "Checking SSH access to github.com \u2014 ssh may ask for your passphrase"
195
+ "Checking SSH access to github.com: ssh may ask for your passphrase"
197
196
  ];
198
197
  function usingRest(access, login) {
199
198
  return access.ok ? `ssh (github.com as ${access.login})` : `https (ssh to github.com unavailable: ${access.reason}${loggedInAs(login)})`;
@@ -289,7 +288,7 @@ function blockHash(body) {
289
288
  function intro(scope, org, depth) {
290
289
  if (scope === null) {
291
290
  return [
292
- `This is the root of rness workspace \`${org}\`. Full context lives in \`.rness/\` \u2014`,
291
+ `This is the root of rness workspace \`${org}\`. Full context lives in \`.rness/\`:`,
293
292
  "start at its `AGENTS.md`, then task-relevant `adr/`, `specs/`, `plans/`; live: `rness context`.",
294
293
  "Every `org/<repo>/` carries its own block with the rules that apply there."
295
294
  ].join("\n");
@@ -297,7 +296,7 @@ function intro(scope, org, depth) {
297
296
  const rel = `${"../".repeat(depth)}.rness/`;
298
297
  return [
299
298
  `This directory is scope \`${scope}\` of rness workspace \`${org}\`. Full context lives in`,
300
- `\`${rel}\` \u2014 start at its \`AGENTS.md\`, then task-relevant \`adr/\`, \`specs/\`, \`plans/\`;`,
299
+ `\`${rel}\`: start at its \`AGENTS.md\`, then task-relevant \`adr/\`, \`specs/\`, \`plans/\`;`,
301
300
  `live: \`rness context --scope ${scope}\`. If \`.rness/\` is not reachable, this is a`,
302
301
  "standalone clone: the rules below are all you have."
303
302
  ].join("\n");
@@ -491,13 +490,13 @@ var allocateStep = (allocate, collection) => `Allocate the file: run \`${allocat
491
490
  \`${collection}/NNNN-untitled.md\` with the next number, the front matter
492
491
  and the opening sections, and prints the path. Rename it to
493
492
  \`NNNN-<slug>.md\`, the slug a few lowercase words of the title joined by
494
- hyphens, and write the title as \`# NNNN \u2014 <title>\`. Never choose the
493
+ hyphens, and write the title as \`# NNNN - <title>\`. Never choose the
495
494
  number yourself.`;
496
495
  var HOOK_LINE = (rness) => `The rness hook checks every edit under \`${rness}/\`: fix what it reports.`;
497
496
  var LIFECYCLE = [
498
497
  {
499
498
  name: "adr",
500
- description: "Record a decision of the rness workspace as an ADR in .rness/adr/ \u2014 a choice expensive to reverse or that creates a lasting constraint \u2014 or reopen one. Use when the developer asks for an ADR, or when the conversation reaches such a decision.",
499
+ description: "Record a decision of the rness workspace as an ADR in .rness/adr/ - a choice expensive to reverse or that creates a lasting constraint - or reopen one. Use when the developer asks for an ADR, or when the conversation reaches such a decision.",
501
500
  hint: "[create <subject> | open NNNN]",
502
501
  tab: "adr",
503
502
  body: (rness, allocate) => `You keep the decisions of this workspace: the ADRs in \`${rness}/adr/\`. The table
@@ -514,7 +513,7 @@ it; a bare reference is \`open\`; any other words are the subject of a
514
513
  Creating:
515
514
 
516
515
  1. If the developer did not ask for an ADR in so many words, propose one in
517
- a single line \u2014 its title, and why the choice is hard to reverse \u2014 and
516
+ a single line - its title, and why the choice is hard to reverse - and
518
517
  wait for a yes.
519
518
  2. Read \`${rness}/CONVENTIONS.md\` and \`${rness}/adr/0000-template.md\`: they hold the
520
519
  rules and the sections; this skill is only the procedure.
@@ -524,7 +523,7 @@ Creating:
524
523
  4. ${allocateStep(allocate, "adr")}
525
524
  5. Fill it: \`repo\` the repositories under \`org/\` it affects; the template's
526
525
  sections, their guidance lines removed; an ADR it replaces named in
527
- Context \u2014 that one becomes \`Superseded\`, with \`superseded_by:\`, only once
526
+ Context - that one becomes \`Superseded\`, with \`superseded_by:\`, only once
528
527
  the new ADR is \`Accepted\`. Add ${SESSION_LINE}.
529
528
  6. ${HOOK_LINE(rness)}
530
529
 
@@ -542,7 +541,7 @@ ${COMMIT_RULE}
542
541
  },
543
542
  {
544
543
  name: "spec",
545
- description: "Write a specification of the rness workspace in .rness/specs/ \u2014 the outcome wanted and its scope, before any plan \u2014 or reopen one. Use when the developer asks for a spec, or when agreed work is too large to start without one.",
544
+ description: "Write a specification of the rness workspace in .rness/specs/ - the outcome wanted and its scope, before any plan - or reopen one. Use when the developer asks for a spec, or when agreed work is too large to start without one.",
546
545
  hint: "[create <subject> | open NNNN]",
547
546
  tab: "specs",
548
547
  body: (rness, allocate) => `You keep the specifications of this workspace, in \`${rness}/specs/\`. The table
@@ -566,7 +565,7 @@ Creating:
566
565
  what is in and out of scope, the ADRs it rests on: ask what the
567
566
  conversation does not say, one question at a time.
568
567
  4. ${allocateStep(allocate, "specs")}
569
- 5. Fill it: \`repo\`, and \`adr:\` linking the decisions it rests on \u2014 or the
568
+ 5. Fill it: \`repo\`, and \`adr:\` linking the decisions it rests on - or the
570
569
  rationale in the body when none does; the sections it opened with
571
570
  (Summary, Scope, Out of scope, Alternatives considered, To verify,
572
571
  Tests), or the most recent specification's when the team's differ. What
@@ -575,8 +574,8 @@ Creating:
575
574
  question. Add ${SESSION_LINE}.
576
575
  6. ${HOOK_LINE(rness)}
577
576
 
578
- Opening: read the specification and amend what the developer asks \u2014 a
579
- section, a scope, an open question answered \u2014 \`updated\` today, the session
577
+ Opening: read the specification and amend what the developer asks - a
578
+ section, a scope, an open question answered - \`updated\` today, the session
580
579
  line added. A status moves only as the developer says, or by
581
580
  \`/rness:plan from\`.
582
581
 
@@ -591,14 +590,14 @@ ${COMMIT_RULE}
591
590
  },
592
591
  {
593
592
  name: "plan",
594
- description: "The plans of the rness workspace in .rness/plans/ \u2014 a plan from a specification (from, which approves it), from the conversation (create), reopened (open), or closed on evidence (check). Use when the developer asks for a plan, to approve a specification, or to check the work of a plan.",
593
+ description: "The plans of the rness workspace in .rness/plans/ - a plan from a specification (from, which approves it), from the conversation (create), reopened (open), or closed on evidence (check). Use when the developer asks for a plan, to approve a specification, or to check the work of a plan.",
595
594
  hint: "[create <subject> | from <spec> | open NNNN | check NNNN]",
596
595
  tab: "plans",
597
596
  body: (rness, allocate) => `You keep the plans of this workspace, in \`${rness}/plans/\`. The table above
598
597
  lists the existing ones, newest first. Arguments: \`$ARGUMENTS\`.
599
598
 
600
599
  The first word is the verb, when a reference (\`0037\`, or a path) follows
601
- it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
600
+ it - \`check\` alone means the plan \`In progress\`; a bare reference is
602
601
  \`open\`; any other words are the subject of a \`create\`:
603
602
 
604
603
  - \`from NNNN\`: a plan from specification NNNN, which this approves.
@@ -616,7 +615,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
616
615
  reopen it rather than write a second.
617
616
  2. The developer typed this command: that is their approval, and the
618
617
  specification moves from \`Draft\` or \`Proposed\` to \`Approved\`, \`updated\`
619
- today, in the same commit as the plan \u2014 no confirmation question. If
618
+ today, in the same commit as the plan - no confirmation question. If
620
619
  you are proposing it yourself, propose it in a single line and wait for
621
620
  a yes first: the approval is theirs, never yours.
622
621
  3. Read the code and the repositories the specification touches: every
@@ -624,7 +623,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
624
623
  4. ${allocateStep(allocate, "plans")}
625
624
  5. Fill it: \`spec:\` linking the specification; tasks in order, as
626
625
  checkboxes, each with the files, what changes, and the command that
627
- proves it (a test, a build, a run) \u2014 the last tasks the documentation
626
+ proves it (a test, a build, a run) - the last tasks the documentation
628
627
  the work makes inaccurate, then the release when the repository has
629
628
  one; where the plan decides something the specification leaves open, the
630
629
  section it opened with says so. Add ${SESSION_LINE}.
@@ -635,7 +634,7 @@ for a plan in so many words, propose one in a single line and wait for a
635
634
  yes. The body says what the work is and why it needs no specification.
636
635
 
637
636
  \`open\`: read the plan and its specification; amend what the developer
638
- asks \u2014 a task added, split or reworded, a blocker recorded \u2014 \`updated\`
637
+ asks - a task added, split or reworded, a blocker recorded - \`updated\`
639
638
  today, the session line added; move \`Draft\` to \`Ready\` or \`Blocked\` as they
640
639
  say. A \`Completed\` or \`Abandoned\` plan is not reopened: offer a new plan of
641
640
  the same specification.
@@ -653,7 +652,7 @@ the same specification.
653
652
  check has no cache: run twice, it proves twice.
654
653
  5. Every task proven:
655
654
  - the plan: \`status: Completed\`, \`updated\` today, the checkboxes of the
656
- proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` \u2014 what
655
+ proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` - what
657
656
  ran, what it showed, what could not run and why;
658
657
  - the specification: \`Implemented\` once every plan of it is
659
658
  \`Completed\`; \`updated\` today;
@@ -1089,7 +1088,7 @@ async function driftWarning(cwd) {
1089
1088
  if (drift === null) return null;
1090
1089
  const pm = await workspacePackageManager(rnessDir);
1091
1090
  return warn(
1092
- `${basename(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed \u2014 run ${pm} install in .rness`
1091
+ `${basename(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed: run ${pm} install in .rness`
1093
1092
  );
1094
1093
  }
1095
1094
  var CHILD_DEADLINE_MS = 12e4;
@@ -1522,7 +1521,7 @@ async function syncCommand(opts, deps = {}) {
1522
1521
  if (!check && opts.scope === void 0) {
1523
1522
  const boards = await migrateBoards(ws.rnessDir, manifest);
1524
1523
  if (boards.changed) {
1525
- manifest.projects = boards.projects;
1524
+ manifest.boards = boards.boards;
1526
1525
  await writeManifest(ws.rnessDir, manifest);
1527
1526
  for (const [rel, text] of boards.readmes)
1528
1527
  await writeFileAtomic(join6(ws.rnessDir, ...rel.split("/")), text);
@@ -1689,7 +1688,7 @@ async function syncCommand(opts, deps = {}) {
1689
1688
  }
1690
1689
  if (check && differences > 0)
1691
1690
  problems.push(
1692
- `${differences} block(s) out of date \u2014 run ${rnessCommand()} sync`
1691
+ `${differences} block(s) out of date: run ${rnessCommand()} sync`
1693
1692
  );
1694
1693
  if (opts.scope === void 0) {
1695
1694
  let stale = 0;
@@ -1705,7 +1704,7 @@ async function syncCommand(opts, deps = {}) {
1705
1704
  }
1706
1705
  if (stale > 0)
1707
1706
  problems.push(
1708
- `${stale} agent file(s) out of date \u2014 run ${rnessCommand()} sync`
1707
+ `${stale} agent file(s) out of date: run ${rnessCommand()} sync`
1709
1708
  );
1710
1709
  if (!check)
1711
1710
  for (const label of await leftoverTargets(ws.root, manifest))
@@ -1767,7 +1766,7 @@ async function addCommand(spec, opts, deps = {}) {
1767
1766
  }
1768
1767
  if (parsed.name === CONTEXT_REPO) {
1769
1768
  process.stderr.write(
1770
- `${CONTEXT_REPO} is the workspace context, not a member repository \u2014 it is already cloned at ${basename2(ws.root)}/${CONTEXT_REPO}
1769
+ `${CONTEXT_REPO} is the workspace context, not a member repository: it is already cloned at ${basename2(ws.root)}/${CONTEXT_REPO}
1771
1770
  `
1772
1771
  );
1773
1772
  return 2;
@@ -2414,7 +2413,7 @@ async function commitContext(input) {
2414
2413
  ui.line("committed", `${shown}/.rness`);
2415
2414
  } catch (e) {
2416
2415
  ui.warn(
2417
- `${e instanceof Error ? e.message : String(e)} \u2014 commit ${shown}/.rness yourself`
2416
+ `${e instanceof Error ? e.message : String(e)}: commit ${shown}/.rness yourself`
2418
2417
  );
2419
2418
  }
2420
2419
  }
@@ -2527,7 +2526,7 @@ async function createBlank(input) {
2527
2526
  provider: null,
2528
2527
  org: null,
2529
2528
  agents,
2530
- projects: null,
2529
+ boards: null,
2531
2530
  repos: {},
2532
2531
  scopes: {}
2533
2532
  },
@@ -3025,21 +3024,21 @@ async function createCommand(opts, deps = {}) {
3025
3024
  if (joining)
3026
3025
  ui.line(
3027
3026
  "found",
3028
- `${org}/.rness \u2014 joining`,
3029
- `${org} has a workspace \u2014 joining it`
3027
+ `${org}/.rness - joining`,
3028
+ `${org} has a workspace - joining it`
3030
3029
  );
3031
3030
  else
3032
3031
  ui.line(
3033
3032
  "not found",
3034
- `${org}/.rness (or not visible to you) \u2014 starting a new workspace`,
3035
- `${org} has no workspace yet (or none you can see) \u2014 starting one`
3033
+ `${org}/.rness (or not visible to you) - starting a new workspace`,
3034
+ `${org} has no workspace yet (or none you can see) - starting one`
3036
3035
  );
3037
3036
  let catalogue = {
3038
3037
  contract: 1,
3039
3038
  provider: chosenProvider,
3040
3039
  org,
3041
3040
  agents: null,
3042
- projects: null,
3041
+ boards: null,
3043
3042
  repos: {},
3044
3043
  scopes: {}
3045
3044
  };
@@ -3160,7 +3159,7 @@ async function createCommand(opts, deps = {}) {
3160
3159
  else process.stdout.write(`
3161
3160
  ${next2.map((l) => ` ${l}`).join("\n")}
3162
3161
  `);
3163
- ui.outro(`You joined ${org} \u2014 your workspace is in ${shown}/`);
3162
+ ui.outro(`You joined ${org}: your workspace is in ${shown}/`);
3164
3163
  return failures2.length > 0 ? 1 : 0;
3165
3164
  }
3166
3165
  const built = await buildContext({
@@ -3462,7 +3461,7 @@ function finish(ui, cwd, rnessDir, label, target, ending) {
3462
3461
  `git -C ${c.dir} add ${c.paths.join(" ")} && git -C ${c.dir} commit -m "${message3}"`
3463
3462
  );
3464
3463
  if (ending.commit !== "nothing")
3465
- next.push("# teammates: git pull \u2014 the next rness command installs it");
3464
+ next.push("# teammates: git pull - the next rness command installs it");
3466
3465
  if (ui.session) {
3467
3466
  if (next.length > 0) ui.note("Next steps", next);
3468
3467
  ui.outro(`${label} runs @rness/cli ${target}`);
@@ -3558,18 +3557,18 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3558
3557
  if (pin.spec === target && installed === target)
3559
3558
  ui.line(
3560
3559
  "scaffold",
3561
- `@rness/cli ${target} \u2014 merging it into ${label}`,
3560
+ `@rness/cli ${target}: merging it into ${label}`,
3562
3561
  `Merging the @rness/cli ${target} scaffold into ${label}`
3563
3562
  );
3564
3563
  else if (pin.spec === target)
3565
3564
  ui.line(
3566
3565
  "install",
3567
- `@rness/cli ${target} in ${label} (${pm}) \u2014 ${installed ?? "nothing"} is installed`
3566
+ `@rness/cli ${target} in ${label} (${pm}): ${installed ?? "nothing"} is installed`
3568
3567
  );
3569
3568
  else {
3570
3569
  ui.line(
3571
3570
  "upgrade",
3572
- `@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? " \u2014 downgrading" : ""}`
3571
+ `@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? ", downgrading" : ""}`
3573
3572
  );
3574
3573
  ui.line("notes", NOTES, `Release notes: ${NOTES}`);
3575
3574
  }
@@ -3598,7 +3597,7 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3598
3597
  ui.line(
3599
3598
  "adopting",
3600
3599
  `the @rness/cli ${target} scaffold (no scaffold commit in ${label} yet)`,
3601
- `Adopting the @rness/cli ${target} scaffold \u2014 ${label} has no scaffold commit yet`
3600
+ `Adopting the @rness/cli ${target} scaffold: ${label} has no scaffold commit yet`
3602
3601
  );
3603
3602
  else
3604
3603
  ui.line(
@@ -3686,12 +3685,12 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3686
3685
  if (committed.kind === "committed")
3687
3686
  ui.line(
3688
3687
  "committed",
3689
- `${label} \u2014 ${message3}`,
3688
+ `${label}: ${message3}`,
3690
3689
  `Committed ${label}: ${message3}`
3691
3690
  );
3692
3691
  if (committed.kind === "refused") {
3693
3692
  ui.error(
3694
- `the commit of ${label} was refused; everything is staged \u2014 deal with what git said, then commit`
3693
+ `the commit of ${label} was refused; everything is staged: deal with what git said, then commit`
3695
3694
  );
3696
3695
  for (const line3 of committed.output.split("\n"))
3697
3696
  if (line3.trim() !== "") ui.hint(line3, "stderr");
@@ -3728,9 +3727,19 @@ async function checkBoards(rnessDir, manifest) {
3728
3727
  const problems = (manifest.refused ?? []).map((r) => r.reason);
3729
3728
  const holders = /* @__PURE__ */ new Map();
3730
3729
  const all = [];
3731
- for (const [name, entry] of Object.entries(manifest.projects ?? {})) {
3730
+ const isCollection2 = async (dir) => !NEVER.has(dir) && (contractOf(dir) !== void 0 || await isDirectory(join16(rnessDir, dir)));
3731
+ for (const [name, entry] of Object.entries(manifest.boards ?? {})) {
3732
3732
  if (typeof entry === "number") continue;
3733
- const at = `projects.${name}`;
3733
+ const at = `boards.${name}`;
3734
+ if (typeof entry === "string") {
3735
+ if (name === PULSE) all.push(name);
3736
+ else if (!await isCollection2(name))
3737
+ problems.push(
3738
+ `"${at}" names no collection of .rness: a collection's board is named after its directory`
3739
+ );
3740
+ else holders.set(name, name);
3741
+ continue;
3742
+ }
3734
3743
  if (entry.collections === "all") all.push(name);
3735
3744
  else
3736
3745
  for (const collection of Object.keys(entry.collections)) {
@@ -3751,7 +3760,7 @@ async function checkBoards(rnessDir, manifest) {
3751
3760
  await readmeDeclarations(rnessDir, collection).catch(() => ({}))
3752
3761
  ))
3753
3762
  problems.push(
3754
- `${collection}/README.md: "${k}" is declared in rness.json now \u2014 rness sync moves it`
3763
+ `${collection}/README.md: "${k}" is declared in rness.json now: rness sync moves it`
3755
3764
  );
3756
3765
  }
3757
3766
  for (const key of ["readme", "updates"]) {
@@ -3768,7 +3777,7 @@ async function checkBoards(rnessDir, manifest) {
3768
3777
  }
3769
3778
  if (all.length > 1)
3770
3779
  problems.push(
3771
- `${all.map((n) => `"projects.${n}"`).join(" and ")} each take every collection ("all"): a collection is on one board at most`
3780
+ `${all.map((n) => `"boards.${n}"`).join(" and ")} each take every collection ("all"): a collection is on one board at most`
3772
3781
  );
3773
3782
  return problems;
3774
3783
  }
@@ -3945,7 +3954,7 @@ async function docNewCommand(collection, opts) {
3945
3954
  ];
3946
3955
  const sections = name === "adr" ? await adrSections(ws.rnessDir) : SECTIONS[name] ?? [];
3947
3956
  const body = [
3948
- `# ${number} \u2014 ${title}`,
3957
+ `# ${number} - ${title}`,
3949
3958
  // The rule under the title, as the ADR and specification templates draw it.
3950
3959
  ...name === "plans" ? [] : ["", "---"],
3951
3960
  ...sections.flatMap((s) => ["", `## ${s}`])
@@ -4028,7 +4037,7 @@ async function takeModNotice(env) {
4028
4037
  );
4029
4038
  } catch {
4030
4039
  }
4031
- return `rness: Claude Code ${version} shows no rness band, footer label or pane; ${MOD_FLOOR} or later does \u2014 claude update`;
4040
+ return `rness: Claude Code ${version} shows no rness band, footer label or pane; ${MOD_FLOOR} or later does: claude update`;
4032
4041
  }
4033
4042
 
4034
4043
  // src/core/edit-guard.ts
@@ -4136,13 +4145,13 @@ async function safetyNet(ws, manifest) {
4136
4145
  const drift = await pinDrift(ws.rnessDir);
4137
4146
  if (drift !== null)
4138
4147
  notes.push(
4139
- `.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed \u2014 run ${await workspacePackageManager(ws.rnessDir)} install in .rness`
4148
+ `.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed: run ${await workspacePackageManager(ws.rnessDir)} install in .rness`
4140
4149
  );
4141
4150
  try {
4142
4151
  const { problems } = await checkWorkspace(ws, manifest);
4143
4152
  if (problems.length > 0)
4144
4153
  notes.push(
4145
- `${count(problems.length, ["problem", "problems"])} in the workspace context \u2014 run rness validate`,
4154
+ `${count(problems.length, ["problem", "problems"])} in the workspace context: run rness validate`,
4146
4155
  ...problems.slice(0, SHOWN_PROBLEMS).map((p) => ` ${p}`)
4147
4156
  );
4148
4157
  } catch (e) {
@@ -4202,7 +4211,7 @@ async function documents(rnessDir, only) {
4202
4211
  }
4203
4212
  function line(d, withScope = false) {
4204
4213
  const head = [d.id, d.status].filter((x) => x !== null).join(" ");
4205
- return `- ${head === "" ? "" : `${head} \u2014 `}${d.title}${withScope ? ` \u2014 ${d.scope ?? "global"}` : ""} \u2014 ${d.path}`;
4214
+ return `- ${head === "" ? "" : `${head} - `}${d.title}${withScope ? ` \xB7 ${d.scope ?? "global"}` : ""} \xB7 ${d.path}`;
4206
4215
  }
4207
4216
  function isCollection(value) {
4208
4217
  return COLLECTIONS.includes(value);
@@ -4344,7 +4353,7 @@ function mcpTools(cwd) {
4344
4353
  {
4345
4354
  name: "rness_context",
4346
4355
  title: "rness: what applies here",
4347
- description: "The rness scope of the current repository (or the one named) and what applies to it: the standards, decisions (ADRs), specifications and plans of that scope and of the scopes it extends \u2014 ids, statuses, titles and paths, no bodies. Start here, then read a document with rness_read.",
4356
+ description: "The rness scope of the current repository (or the one named) and what applies to it: the standards, decisions (ADRs), specifications and plans of that scope and of the scopes it extends: ids, statuses, titles and paths, no bodies. Start here, then read a document with rness_read.",
4348
4357
  inputSchema: {
4349
4358
  type: "object",
4350
4359
  properties: {
@@ -4440,7 +4449,7 @@ function noteTool(cwd, githubApi) {
4440
4449
  additionalProperties: false
4441
4450
  },
4442
4451
  call: (args) => guard(async () => {
4443
- const { postNote } = await import("./note-RBG7OXVI.js");
4452
+ const { postNote } = await import("./note-MKUG7GOT.js");
4444
4453
  const given = (key) => {
4445
4454
  const value = args[key];
4446
4455
  return typeof value === "string" ? value : void 0;
@@ -4489,7 +4498,7 @@ async function scopeBanner(ws, manifest, scope) {
4489
4498
  const n = summary.counts[c];
4490
4499
  return n === void 0 ? [] : [count(n, NOUNS[c])];
4491
4500
  });
4492
- const banner2 = `rness ${VERSION} \xB7 ${workspaceName(manifest, ws.root)} \xB7 ${scope === null ? "global scope" : `scope ${scope}`} \u2014 ${counts.length === 0 ? "nothing applies yet" : counts.join(", ")}`;
4501
+ const banner2 = `rness ${VERSION} \xB7 ${workspaceName(manifest, ws.root)} \xB7 ${scope === null ? "global scope" : `scope ${scope}`} \xB7 ${counts.length === 0 ? "nothing applies yet" : counts.join(", ")}`;
4493
4502
  return { banner: banner2, lines: summary.lines };
4494
4503
  }
4495
4504
  var noteLines = (notes) => notes.map((n) => `rness: ${n}`);
@@ -4499,7 +4508,7 @@ function statusLine(scope, inProgress, notes) {
4499
4508
  }
4500
4509
  async function boardsOf(manifest, rnessDir) {
4501
4510
  const boards = [];
4502
- for (const [name, entry] of Object.entries(manifest.projects ?? {}))
4511
+ for (const [name, entry] of Object.entries(manifest.boards ?? {}))
4503
4512
  try {
4504
4513
  boards.push({
4505
4514
  name,
@@ -4516,8 +4525,9 @@ var SHIPPED_COLORS = presetTemplate(currentPreset("agent-pulse"), {
4516
4525
  collection: PULSE
4517
4526
  })["colors"];
4518
4527
  function pulseOf(org, boards) {
4519
- const main = boards.find((b) => b.declaration.collections === "all") ?? boards[0];
4520
- return org === null || main === void 0 ? null : boardUrl(org, main.declaration.number);
4528
+ const created = boards.filter((b) => b.declaration.number !== null);
4529
+ const main = created.find((b) => b.declaration.collections === "all") ?? created[0];
4530
+ return org === null || main?.declaration.number == null ? null : boardUrl(org, main.declaration.number);
4521
4531
  }
4522
4532
  function snapshotTabs(tabs, org, boards) {
4523
4533
  return tabs.map((tab) => {
@@ -4529,7 +4539,7 @@ function snapshotTabs(tabs, org, boards) {
4529
4539
  rows: tab.rows.map((row) => ({
4530
4540
  ...row,
4531
4541
  color: row.status === null ? "red" : optionColor(colors, "status", row.status) ?? "gray",
4532
- link: org === null || holder === void 0 ? null : itemUrl(org, holder.declaration.number, row.path)
4542
+ link: org === null || holder?.declaration.number == null ? null : itemUrl(org, holder.declaration.number, row.path)
4533
4543
  }))
4534
4544
  };
4535
4545
  });
@@ -4593,7 +4603,7 @@ async function runDetached(ws, input, io, event, rest) {
4593
4603
  if (boards.length === 0) return;
4594
4604
  const args = await rest(session, boards);
4595
4605
  if (args !== null)
4596
- (io.spawn ?? detached)(["pulse", "run", event, ...args], ws.root);
4606
+ (io.spawn ?? detached)(["board", "run", event, ...args], ws.root);
4597
4607
  } catch {
4598
4608
  }
4599
4609
  }
@@ -4615,7 +4625,7 @@ async function journalStart(ws, manifest, scope, cwd, input) {
4615
4625
  const which = plans.length === 1 ? plans.join("") : `${plans.join(" or ")} (pass --plan)`;
4616
4626
  return [
4617
4627
  [
4618
- `Journal: post a note with \`rness pulse note\` (or ${tool}) when you choose an approach, deviate from plan ${which}, are blocked, and when done.`,
4628
+ `Journal: post a note with \`rness note\` (or ${tool}) when you choose an approach, deviate from plan ${which}, are blocked, and when done.`,
4619
4629
  `At most ${a.limit}: decisions and their reasons, not steps.`,
4620
4630
  ...a.to === "repo" ? [
4621
4631
  "The first note prints the issue to reference; the pull request that completes this plan here carries `Closes <issue>`, an earlier one `Refs <issue>`."
@@ -4672,7 +4682,7 @@ async function sessionStart(input, io) {
4672
4682
  notes = [message2(e)];
4673
4683
  }
4674
4684
  const failure = await takeFailure();
4675
- if (failure !== null) notes.push(`pulse not updated \u2014 ${failure}`);
4685
+ if (failure !== null) notes.push(`board not updated: ${failure}`);
4676
4686
  notes.push(...await takeNotices());
4677
4687
  const warnings = noteLines(notes);
4678
4688
  const compact = input["source"] === "compact";
@@ -5286,6 +5296,44 @@ async function writtenFilesCommand(opts) {
5286
5296
  }
5287
5297
 
5288
5298
  // src/cli.ts
5299
+ function formerly(was, now) {
5300
+ process.stderr.write(`${was} is now ${now}
5301
+ `);
5302
+ }
5303
+ function noteCommandOf(parent, state, former) {
5304
+ parent.command("note [text]").description(
5305
+ "A note on the plan in progress: an approach, a deviation, a blocker, done (the text, or stdin)"
5306
+ ).option("--plan <path>", "the plan, when several are in progress").option("--kind <kind>", "approach, deviation, blocker or done").option(
5307
+ "--session <session>",
5308
+ "the session, when CLAUDE_CODE_SESSION_ID is not set"
5309
+ ).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5310
+ async (text, opts) => {
5311
+ if (former !== void 0) formerly(former, "rness note");
5312
+ const { noteCommand } = await import("./note-MKUG7GOT.js");
5313
+ state.code = await noteCommand({
5314
+ ...opts,
5315
+ ...text === void 0 ? {} : { text }
5316
+ });
5317
+ }
5318
+ );
5319
+ }
5320
+ function runCommand(parent, state, former) {
5321
+ parent.command("run <event>", { hidden: true }).requiredOption("--session <id>").option(
5322
+ "--path <path>",
5323
+ "the document edited (repeatable)",
5324
+ (value, previous = []) => [...previous, value]
5325
+ ).option("--scope <scope>", "the session's scope; absent, the root's").option("--clone <name>", "the clone the session worked in").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5326
+ async (event, opts) => {
5327
+ if (former !== void 0) formerly(former, "rness board run");
5328
+ const { path, ...rest } = opts;
5329
+ state.code = await boardRunCommand({
5330
+ ...rest,
5331
+ event,
5332
+ paths: path ?? []
5333
+ });
5334
+ }
5335
+ );
5336
+ }
5289
5337
  function buildProgram(state) {
5290
5338
  const program = new Command().name("rness").description("Configuration-plane CLI for rness workspaces").version(VERSION, "-v, --version", "print the version").exitOverride().showHelpAfterError().configureOutput({
5291
5339
  writeOut: (s) => {
@@ -5342,60 +5390,29 @@ function buildProgram(state) {
5342
5390
  ).option("-y, --yes", "do not ask for confirmation").addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
5343
5391
  state.code = await syncCommand(opts);
5344
5392
  });
5345
- const pulse = program.command("pulse").description("Show the agent's work on the organization's board");
5346
- pulse.command("create").description(
5347
- "Create the organization's Agent Pulse board, or a collection's own project, and sync"
5348
- ).argument(
5349
- "[collection]",
5350
- "a directory of .rness/ whose documents get a project of their own"
5351
- ).option("-y, --yes", "do not ask for confirmation").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (collection, opts) => {
5352
- state.code = await pulseCreateCommand(
5353
- collection === void 0 ? opts : { ...opts, collection }
5354
- );
5393
+ const board = program.command("board").description(
5394
+ "The boards of rness.json: the documents of .rness/ on the provider"
5395
+ );
5396
+ board.command("push").description(
5397
+ "Create the boards rness.json declares and the provider lacks, then bring every board up to date with .rness/"
5398
+ ).option("-y, --yes", "create the boards not created yet without asking").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
5399
+ state.code = await boardPushCommand(opts);
5355
5400
  });
5356
- pulse.command("sync").description(
5357
- "Bring every declared project up to date with the documents of .rness/"
5358
- ).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
5359
- state.code = await pulseSyncCommand(opts);
5401
+ runCommand(board, state);
5402
+ noteCommandOf(program, state);
5403
+ const pulse = program.command("pulse", { hidden: true });
5404
+ pulse.command("create").argument("[collection]").option("-y, --yes").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (collection, opts) => {
5405
+ state.code = await pulseCreateCommand(collection, opts);
5406
+ });
5407
+ pulse.command("sync").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
5408
+ formerly("rness pulse sync", "rness board push");
5409
+ state.code = await boardPushCommand(opts);
5410
+ });
5411
+ noteCommandOf(pulse, state, "rness pulse note");
5412
+ runCommand(pulse, state, "rness pulse run");
5413
+ pulse.command("mark").allowUnknownOption().allowExcessArguments().action(() => {
5414
+ state.code = 0;
5360
5415
  });
5361
- pulse.command("mark", { hidden: true }).requiredOption("--session <id>").option(
5362
- "--path <path>",
5363
- "a document of .rness/ (repeatable)",
5364
- (value, previous = []) => [...previous, value]
5365
- ).option("--end", "clear the marks of the session, then sync").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5366
- async (opts) => {
5367
- const { path, ...rest } = opts;
5368
- state.code = await pulseMarkCommand({ ...rest, paths: path ?? [] });
5369
- }
5370
- );
5371
- pulse.command("note [text]").description(
5372
- "a note on the plan in progress: an approach, a deviation, a blocker, done (the text, or stdin)"
5373
- ).option("--plan <path>", "the plan, when several are in progress").option("--kind <kind>", "approach, deviation, blocker or done").option(
5374
- "--session <session>",
5375
- "the session, when CLAUDE_CODE_SESSION_ID is not set"
5376
- ).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5377
- async (text, opts) => {
5378
- const { pulseNoteCommand } = await import("./note-RBG7OXVI.js");
5379
- state.code = await pulseNoteCommand({
5380
- ...opts,
5381
- ...text === void 0 ? {} : { text }
5382
- });
5383
- }
5384
- );
5385
- pulse.command("run <event>", { hidden: true }).requiredOption("--session <id>").option(
5386
- "--path <path>",
5387
- "the document edited (repeatable)",
5388
- (value, previous = []) => [...previous, value]
5389
- ).option("--scope <scope>", "the session's scope; absent, the root's").option("--clone <name>", "the clone the session worked in").addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5390
- async (event, opts) => {
5391
- const { path, ...rest } = opts;
5392
- state.code = await pulseRunCommand({
5393
- ...rest,
5394
- event,
5395
- paths: path ?? []
5396
- });
5397
- }
5398
- );
5399
5416
  program.command("mcp").description(
5400
5417
  "Serve the workspace context to agents over MCP (stdio; read-only but for rness_note, when a board keeps a journal)"
5401
5418
  ).addOption(new Option("--cwd <dir>").hideHelp()).action(async (opts) => {
@@ -5579,4 +5596,4 @@ export {
5579
5596
  OWN_COMMANDS,
5580
5597
  catchUp
5581
5598
  };
5582
- //# sourceMappingURL=chunk-T5PINUCP.js.map
5599
+ //# sourceMappingURL=chunk-SX7D5W43.js.map