@rness/cli 0.22.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.
@@ -15,7 +15,7 @@ import {
15
15
  recordNotice,
16
16
  resolveScope,
17
17
  statusTabs
18
- } from "./chunk-XCO5ZT2H.js";
18
+ } from "./chunk-OUZQGG6V.js";
19
19
 
20
20
  // src/commands/note.ts
21
21
  import { relative, resolve, sep } from "path";
@@ -173,7 +173,7 @@ async function postNote(input) {
173
173
  const row = (await statusTabs(c.rnessDir)).find((t) => t.name === "plans")?.rows.find((r) => r.path === plan);
174
174
  target = await fromGithub(
175
175
  c.provider.createJournalIssue(repo.owner, repo.name, plan, {
176
- title: `Implement ${row === void 0 ? plan : `${row.id} \u2014 ${row.title}`}`,
176
+ title: `Implement ${row === void 0 ? plan : `${row.id} - ${row.title}`}`,
177
177
  body: await implementationBody(c, plan, parent.number)
178
178
  })
179
179
  );
@@ -197,7 +197,7 @@ async function postNote(input) {
197
197
  }
198
198
  }
199
199
  if (why !== null)
200
- await recordNotice(`journal \u2014 ${why}, notes go to the plan's issue`);
200
+ await recordNotice(`journal: ${why}, notes go to the plan's issue`);
201
201
  const where = clone?.dir ?? input.cwd;
202
202
  const [branch, head] = await Promise.all([branchOf(where), headOf(where)]);
203
203
  const id = session.split(" \xB7 ").pop() ?? session;
@@ -260,4 +260,4 @@ export {
260
260
  postNote,
261
261
  noteCommand
262
262
  };
263
- //# sourceMappingURL=chunk-AEL2W76O.js.map
263
+ //# sourceMappingURL=chunk-PW5RMU2G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/note.ts"],"sourcesContent":["import { relative, resolve, sep } from 'node:path'\n\nimport {\n notePosted,\n notesPosted,\n recordNotice,\n} from '../board/journal-state.ts'\nimport { blobUrl, issueUrl } from '../board/urls.ts'\nimport type { BoardAction } from '../core/board-declaration.ts'\nimport { parseFrontMatter } from '../core/frontmatter.ts'\nimport { branchOf, headOf } from '../core/git.ts'\nimport { JournalRefused } from '../core/github-journal.ts'\nimport type { JournalIssue } from '../core/github-journal.ts'\nimport { cloneHolding } from '../core/repos.ts'\nimport { resolveScope } from '../core/scope.ts'\nimport { plansInProgress, statusTabs } from '../core/status.ts'\nimport {\n type Context,\n type Declared,\n context,\n declaredBoards,\n fromGithub,\n} from './board.ts'\n\n/**\n * `rness note` and `rness_note` (spec 0030 §4, §5): a short note of\n * the agent's on the plan it implements — on the plan's issue in `.rness`,\n * or on an implementation issue in the repository the session works in, a\n * sub-issue of the plan's (§3). Loaded through `import()` only.\n */\n\nexport const KINDS = ['approach', 'deviation', 'blocker', 'done'] as const\nexport type Kind = (typeof KINDS)[number]\nconst TITLE: Readonly<Record<Kind, string>> = {\n approach: 'Approach',\n deviation: 'Deviation',\n blocker: 'Blocker',\n done: 'Done',\n}\nconst MAX = 4000\n/** What a credential looks like; a note that matches is refused, never redacted. */\nconst SECRETS = [\n /ghp_/,\n /gho_/,\n /github_pat_/,\n /AKIA[0-9A-Z]{16}/,\n /-----BEGIN [A-Z ]*PRIVATE KEY/,\n /xox[abpr]-/,\n /sk-[A-Za-z0-9]{20,}/,\n]\n\n/** A refusal said to the agent in one line: the note is not posted. */\nexport class NoteRefused extends Error {}\n\nexport interface NoteInput {\n /** The session's directory. */\n cwd: string\n text: string\n kind?: string\n /** `.rness/`-relative: `plans/0021-x.md`; absent, the one plan in progress. */\n plan?: string\n /** `claude · 1a2b3c4d`, or a session id; absent, `CLAUDE_CODE_SESSION_ID`. */\n session?: string\n env?: NodeJS.ProcessEnv\n /** Internal (tests): GitHub API base. */\n githubApi?: string\n}\n\n/** Where a note went: `acme/api#87`, the reference a pull request uses. */\nexport interface Posted {\n reference: string\n to: 'plan' | 'repo'\n}\n\n/** The session as the hooks name it: `claude · 1a2b3c4d`; null without one. */\nexport function sessionFrom(\n given: string | undefined,\n env: NodeJS.ProcessEnv\n): string | null {\n const raw = given ?? env['CLAUDE_CODE_SESSION_ID'] ?? ''\n if (raw.trim() === '') return null\n // Claude Code's Bash tool carries `CLAUDE_CODE_SESSION_ID` (read\n // 2026-10-06, 2.1.291); a session already named is kept as named.\n return raw.includes(' · ') ? raw : `claude · ${raw.slice(0, 8)}`\n}\n\n/** The text, its kind and the session, checked before anything is read. */\nfunction checked(input: NoteInput): { kind: Kind; session: string } {\n const length = input.text.trim().length\n if (length < 1 || length > MAX)\n throw new NoteRefused(\n `a note holds 1 to ${MAX.toLocaleString('en')} characters (this one ${length})`\n )\n if (SECRETS.some((s) => s.test(input.text)))\n throw new NoteRefused('the note looks like it holds a credential')\n const kind = KINDS.find((k) => k === (input.kind ?? 'approach'))\n if (kind === undefined)\n throw new NoteRefused(\n `--kind is one of ${KINDS.slice(0, -1).join(', ')} or ${KINDS.at(-1)}`\n )\n const session = sessionFrom(input.session, input.env ?? process.env)\n if (session === null)\n throw new NoteRefused(\n 'no session: write it from a Claude Code session, or pass --session'\n )\n return { kind, session }\n}\n\nexport type Journal = Extract<BoardAction, { action: 'journal' }>\n\n/** The board that keeps the journal: the first whose session start declares `journal`. */\nexport function journalOf(\n declared: readonly Declared[]\n): { board: Declared; journal: Journal } | null {\n for (const d of declared)\n for (const a of d.declaration.hooks['session-start'] ?? [])\n if (a.action === 'journal') return { board: d, journal: a }\n return null\n}\n\n/** `git@github.com:acme/api.git` or `https://github.com/acme/api` → `acme`, `api`; null on another host. */\nexport function githubRepo(\n url: string\n): { owner: string; name: string } | null {\n const m =\n /^(?:git@github\\.com:|ssh:\\/\\/git@github\\.com\\/|https:\\/\\/github\\.com\\/)([^/]+)\\/(.+?)(?:\\.git)?\\/?$/.exec(\n url.trim()\n )\n return m === null || m[1] === undefined || m[2] === undefined\n ? null\n : { owner: m[1], name: m[2] }\n}\n\n/** The plan the note is on (spec 0030 §2). */\nasync function planOf(\n c: Context,\n cwd: string,\n given?: string\n): Promise<string> {\n const tabs = await statusTabs(c.rnessDir)\n const plans = tabs.find((t) => t.name === 'plans')?.rows ?? []\n if (given !== undefined) {\n const path = given.replace(/^\\.rness\\//, '')\n if (!plans.some((r) => r.path === path))\n throw new NoteRefused(`${given} is no plan of .rness`)\n return path\n }\n const scope = resolveScope(\n c.manifest,\n relative(c.root, resolve(cwd)).split(sep).join('/')\n )\n const candidates = await plansInProgress(\n { root: c.root, rnessDir: c.rnessDir },\n c.manifest,\n scope\n )\n if (candidates.length === 0)\n throw new NoteRefused(\n `no plan in progress in scope ${scope ?? 'global'}: set one In progress first`\n )\n if (candidates.length > 1)\n throw new NoteRefused(\n `several plans in progress: pass --plan, one of ${candidates.join(', ')}`\n )\n return candidates[0] ?? ''\n}\n\n/** A plan's issue in `.rness`, found by its card's `Path` on the journal's board. */\nexport async function planIssue(\n c: Context,\n board: Declared,\n plan: string\n): Promise<JournalIssue> {\n const items = await fromGithub(\n c.provider.items(board.board, { bodies: false })\n )\n const number = items.find((i) => i.path === plan)?.issue?.number\n const found =\n number === undefined\n ? null\n : await fromGithub(c.provider.issueOf(c.org, '.rness', number))\n if (found === null)\n throw new NoteRefused(`${plan} has no issue yet: rness board push`)\n return {\n id: found.id,\n number: found.number,\n repository: `${c.org}/.rness`,\n }\n}\n\n/** A GitHub refusal to write (a token or organization policy, spec 0028). */\nconst refusedWrite = (e: unknown): boolean =>\n e instanceof Error &&\n /not accessible|forbidden|permission|must have push access/i.test(e.message)\n\n/** The implementation issue's body (spec 0030 §3.2): the plan, its issue, its specification. */\nasync function implementationBody(\n c: Context,\n plan: string,\n planNumber: number\n): Promise<string> {\n const lines = [\n `Plan [\\`${plan}\\`](${blobUrl(c.org, plan)}) · [plan issue](${issueUrl(c.org, planNumber)})`,\n ]\n try {\n const { readFile } = await import('node:fs/promises')\n const front =\n parseFrontMatter(\n await readFile(resolve(c.rnessDir, ...plan.split('/')), 'utf8')\n ) ?? {}\n const spec = /\\(\\.\\.\\/(specs\\/[^)\\s]+\\.md)\\)/.exec(\n String(front['spec'] ?? '')\n )\n if (spec?.[1] !== undefined)\n lines.push(`Specification [\\`${spec[1]}\\`](${blobUrl(c.org, spec[1])})`)\n } catch {\n // No specification named: the plan alone.\n }\n return `${lines.join('\\n')}\\n\\nThe agent's notes on this implementation follow as comments. The pull request that completes it carries \\`Closes\\` with this issue's reference.`\n}\n\n/** Posts a note; throws {@link NoteRefused} or GitHub's error, in one line. */\nexport async function postNote(input: NoteInput): Promise<Posted> {\n const { kind, session } = checked(input)\n const c = await context({\n cwd: input.cwd,\n ...(input.githubApi === undefined ? {} : { githubApi: input.githubApi }),\n })\n const declared = await declaredBoards(c)\n const kept = journalOf(declared)\n if (kept === null)\n throw new NoteRefused(\n 'no board keeps a journal: add { \"action\": \"journal\", \"to\": \"plan\" } to its session-start hooks'\n )\n const plan = await planOf(c, input.cwd, input.plan)\n if ((await notesPosted(c.rnessDir, session, plan)) >= kept.journal.limit)\n throw new NoteRefused(\n 'journal full for this session: put the rest in the pull request'\n )\n const parent = await planIssue(c, kept.board, plan)\n const clone = cloneHolding(c.root, c.manifest.repos, input.cwd)\n\n let target: JournalIssue = parent\n let why: string | null = null\n if (kept.journal.to === 'repo' && clone !== null) {\n const repo = githubRepo(clone.url)\n if (repo === null || repo.owner.toLowerCase() !== c.org.toLowerCase())\n why = `${clone.name} is not on the workspace's provider`\n else\n try {\n const there = await fromGithub(\n c.provider.journalIssue(repo.owner, repo.name, plan)\n )\n if (there !== null) target = there\n else {\n const row = (await statusTabs(c.rnessDir))\n .find((t) => t.name === 'plans')\n ?.rows.find((r) => r.path === plan)\n target = await fromGithub(\n c.provider.createJournalIssue(repo.owner, repo.name, plan, {\n title: `Implement ${row === undefined ? plan : `${row.id} - ${row.title}`}`,\n body: await implementationBody(c, plan, parent.number),\n })\n )\n try {\n await fromGithub(c.provider.addSubIssue(parent.id, target.id))\n } catch {\n // A link GitHub refuses: the issue named on the plan's instead (§3.3).\n await fromGithub(\n c.provider.comment(\n parent.id,\n `Implementation: ${target.repository}#${target.number}`\n )\n )\n }\n }\n } catch (e) {\n if (e instanceof JournalRefused)\n why =\n e.why === 'issues'\n ? `${repo.owner}/${repo.name} takes no issues`\n : `${repo.owner}/${repo.name} is not on GitHub, or this login cannot see it`\n else if (refusedWrite(e))\n why = `${repo.owner}/${repo.name} refuses this login's write`\n else throw e\n }\n }\n if (why !== null)\n await recordNotice(`journal: ${why}, notes go to the plan's issue`)\n\n const where = clone?.dir ?? input.cwd\n const [branch, head] = await Promise.all([branchOf(where), headOf(where)])\n const id = session.split(' · ').pop() ?? session\n const header = [\n `**${TITLE[kind]}**`,\n session,\n ...(branch === null || head === null\n ? []\n : [`\\`${branch}\\` @ \\`${head.slice(0, 7)}\\``]),\n ].join(' · ')\n const body = [\n ...(why === null\n ? []\n : [`_${why}: this note goes to the plan's issue._`, '']),\n header,\n '',\n input.text.trim(),\n '',\n `<!-- rness note ${id} -->`,\n ].join('\\n')\n await fromGithub(c.provider.comment(target.id, body))\n const reference = `${target.repository}#${target.number}`\n await notePosted(c.rnessDir, session, plan, { id: target.id, reference })\n return {\n reference,\n to: target === parent ? 'plan' : 'repo',\n }\n}\n\n/** `rness note`: the text from the argument, or stdin when it is absent or `-`. */\nexport async function noteCommand(opts: {\n text?: string\n kind?: string\n plan?: string\n session?: string\n cwd?: string\n githubApi?: string\n /** Internal (tests): what stdin holds. */\n stdin?: () => Promise<string>\n}): Promise<number> {\n try {\n const text =\n opts.text === undefined || opts.text === '-'\n ? await (opts.stdin ?? readStdin)()\n : opts.text\n const posted = await postNote({\n cwd: opts.cwd ?? process.cwd(),\n text,\n ...(opts.kind === undefined ? {} : { kind: opts.kind }),\n ...(opts.plan === undefined ? {} : { plan: opts.plan }),\n ...(opts.session === undefined ? {} : { session: opts.session }),\n ...(opts.githubApi === undefined ? {} : { githubApi: opts.githubApi }),\n })\n process.stdout.write(`${posted.reference}\\n`)\n return 0\n } catch (e) {\n process.stderr.write(\n `rness: ${e instanceof Error ? e.message : String(e)}\\n`\n )\n return 1\n }\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = []\n for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk))\n return Buffer.concat(chunks).toString('utf8')\n}\n"],"mappings":"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","names":[]}
@@ -102,7 +102,7 @@ import {
102
102
  workspaceName,
103
103
  writeFileAtomic,
104
104
  writeManifest
105
- } from "./chunk-XCO5ZT2H.js";
105
+ } from "./chunk-OUZQGG6V.js";
106
106
 
107
107
  // src/core/transport.ts
108
108
  import { spawn } from "child_process";
@@ -183,7 +183,7 @@ async function testGithubSsh(transport, interactive, announce) {
183
183
  }
184
184
  var loggedInAs = (login) => login === void 0 || login === null ? "" : `, logged in as ${login}`;
185
185
  function usingSentence(access, login) {
186
- 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)}`;
187
187
  }
188
188
  function isSshUrl(url, hosts) {
189
189
  return url.startsWith(hosts.ssh);
@@ -192,7 +192,7 @@ var CHECKING_LINE = status("checking", "ssh access to github.com\u2026");
192
192
  var CHECKING = [
193
193
  "checking",
194
194
  "ssh access to github.com\u2026",
195
- "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"
196
196
  ];
197
197
  function usingRest(access, login) {
198
198
  return access.ok ? `ssh (github.com as ${access.login})` : `https (ssh to github.com unavailable: ${access.reason}${loggedInAs(login)})`;
@@ -288,7 +288,7 @@ function blockHash(body) {
288
288
  function intro(scope, org, depth) {
289
289
  if (scope === null) {
290
290
  return [
291
- `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/\`:`,
292
292
  "start at its `AGENTS.md`, then task-relevant `adr/`, `specs/`, `plans/`; live: `rness context`.",
293
293
  "Every `org/<repo>/` carries its own block with the rules that apply there."
294
294
  ].join("\n");
@@ -296,7 +296,7 @@ function intro(scope, org, depth) {
296
296
  const rel = `${"../".repeat(depth)}.rness/`;
297
297
  return [
298
298
  `This directory is scope \`${scope}\` of rness workspace \`${org}\`. Full context lives in`,
299
- `\`${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/\`;`,
300
300
  `live: \`rness context --scope ${scope}\`. If \`.rness/\` is not reachable, this is a`,
301
301
  "standalone clone: the rules below are all you have."
302
302
  ].join("\n");
@@ -490,13 +490,13 @@ var allocateStep = (allocate, collection) => `Allocate the file: run \`${allocat
490
490
  \`${collection}/NNNN-untitled.md\` with the next number, the front matter
491
491
  and the opening sections, and prints the path. Rename it to
492
492
  \`NNNN-<slug>.md\`, the slug a few lowercase words of the title joined by
493
- hyphens, and write the title as \`# NNNN \u2014 <title>\`. Never choose the
493
+ hyphens, and write the title as \`# NNNN - <title>\`. Never choose the
494
494
  number yourself.`;
495
495
  var HOOK_LINE = (rness) => `The rness hook checks every edit under \`${rness}/\`: fix what it reports.`;
496
496
  var LIFECYCLE = [
497
497
  {
498
498
  name: "adr",
499
- 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.",
500
500
  hint: "[create <subject> | open NNNN]",
501
501
  tab: "adr",
502
502
  body: (rness, allocate) => `You keep the decisions of this workspace: the ADRs in \`${rness}/adr/\`. The table
@@ -513,7 +513,7 @@ it; a bare reference is \`open\`; any other words are the subject of a
513
513
  Creating:
514
514
 
515
515
  1. If the developer did not ask for an ADR in so many words, propose one in
516
- 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
517
517
  wait for a yes.
518
518
  2. Read \`${rness}/CONVENTIONS.md\` and \`${rness}/adr/0000-template.md\`: they hold the
519
519
  rules and the sections; this skill is only the procedure.
@@ -523,7 +523,7 @@ Creating:
523
523
  4. ${allocateStep(allocate, "adr")}
524
524
  5. Fill it: \`repo\` the repositories under \`org/\` it affects; the template's
525
525
  sections, their guidance lines removed; an ADR it replaces named in
526
- Context \u2014 that one becomes \`Superseded\`, with \`superseded_by:\`, only once
526
+ Context - that one becomes \`Superseded\`, with \`superseded_by:\`, only once
527
527
  the new ADR is \`Accepted\`. Add ${SESSION_LINE}.
528
528
  6. ${HOOK_LINE(rness)}
529
529
 
@@ -541,7 +541,7 @@ ${COMMIT_RULE}
541
541
  },
542
542
  {
543
543
  name: "spec",
544
- 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.",
545
545
  hint: "[create <subject> | open NNNN]",
546
546
  tab: "specs",
547
547
  body: (rness, allocate) => `You keep the specifications of this workspace, in \`${rness}/specs/\`. The table
@@ -565,7 +565,7 @@ Creating:
565
565
  what is in and out of scope, the ADRs it rests on: ask what the
566
566
  conversation does not say, one question at a time.
567
567
  4. ${allocateStep(allocate, "specs")}
568
- 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
569
569
  rationale in the body when none does; the sections it opened with
570
570
  (Summary, Scope, Out of scope, Alternatives considered, To verify,
571
571
  Tests), or the most recent specification's when the team's differ. What
@@ -574,8 +574,8 @@ Creating:
574
574
  question. Add ${SESSION_LINE}.
575
575
  6. ${HOOK_LINE(rness)}
576
576
 
577
- Opening: read the specification and amend what the developer asks \u2014 a
578
- 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
579
579
  line added. A status moves only as the developer says, or by
580
580
  \`/rness:plan from\`.
581
581
 
@@ -590,14 +590,14 @@ ${COMMIT_RULE}
590
590
  },
591
591
  {
592
592
  name: "plan",
593
- 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.",
594
594
  hint: "[create <subject> | from <spec> | open NNNN | check NNNN]",
595
595
  tab: "plans",
596
596
  body: (rness, allocate) => `You keep the plans of this workspace, in \`${rness}/plans/\`. The table above
597
597
  lists the existing ones, newest first. Arguments: \`$ARGUMENTS\`.
598
598
 
599
599
  The first word is the verb, when a reference (\`0037\`, or a path) follows
600
- 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
601
601
  \`open\`; any other words are the subject of a \`create\`:
602
602
 
603
603
  - \`from NNNN\`: a plan from specification NNNN, which this approves.
@@ -615,7 +615,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
615
615
  reopen it rather than write a second.
616
616
  2. The developer typed this command: that is their approval, and the
617
617
  specification moves from \`Draft\` or \`Proposed\` to \`Approved\`, \`updated\`
618
- 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
619
619
  you are proposing it yourself, propose it in a single line and wait for
620
620
  a yes first: the approval is theirs, never yours.
621
621
  3. Read the code and the repositories the specification touches: every
@@ -623,7 +623,7 @@ it \u2014 \`check\` alone means the plan \`In progress\`; a bare reference is
623
623
  4. ${allocateStep(allocate, "plans")}
624
624
  5. Fill it: \`spec:\` linking the specification; tasks in order, as
625
625
  checkboxes, each with the files, what changes, and the command that
626
- 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
627
627
  the work makes inaccurate, then the release when the repository has
628
628
  one; where the plan decides something the specification leaves open, the
629
629
  section it opened with says so. Add ${SESSION_LINE}.
@@ -634,7 +634,7 @@ for a plan in so many words, propose one in a single line and wait for a
634
634
  yes. The body says what the work is and why it needs no specification.
635
635
 
636
636
  \`open\`: read the plan and its specification; amend what the developer
637
- 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\`
638
638
  today, the session line added; move \`Draft\` to \`Ready\` or \`Blocked\` as they
639
639
  say. A \`Completed\` or \`Abandoned\` plan is not reopened: offer a new plan of
640
640
  the same specification.
@@ -652,7 +652,7 @@ the same specification.
652
652
  check has no cache: run twice, it proves twice.
653
653
  5. Every task proven:
654
654
  - the plan: \`status: Completed\`, \`updated\` today, the checkboxes of the
655
- proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` \u2014 what
655
+ proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` - what
656
656
  ran, what it showed, what could not run and why;
657
657
  - the specification: \`Implemented\` once every plan of it is
658
658
  \`Completed\`; \`updated\` today;
@@ -1088,7 +1088,7 @@ async function driftWarning(cwd) {
1088
1088
  if (drift === null) return null;
1089
1089
  const pm = await workspacePackageManager(rnessDir);
1090
1090
  return warn(
1091
- `${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`
1092
1092
  );
1093
1093
  }
1094
1094
  var CHILD_DEADLINE_MS = 12e4;
@@ -1688,7 +1688,7 @@ async function syncCommand(opts, deps = {}) {
1688
1688
  }
1689
1689
  if (check && differences > 0)
1690
1690
  problems.push(
1691
- `${differences} block(s) out of date \u2014 run ${rnessCommand()} sync`
1691
+ `${differences} block(s) out of date: run ${rnessCommand()} sync`
1692
1692
  );
1693
1693
  if (opts.scope === void 0) {
1694
1694
  let stale = 0;
@@ -1704,7 +1704,7 @@ async function syncCommand(opts, deps = {}) {
1704
1704
  }
1705
1705
  if (stale > 0)
1706
1706
  problems.push(
1707
- `${stale} agent file(s) out of date \u2014 run ${rnessCommand()} sync`
1707
+ `${stale} agent file(s) out of date: run ${rnessCommand()} sync`
1708
1708
  );
1709
1709
  if (!check)
1710
1710
  for (const label of await leftoverTargets(ws.root, manifest))
@@ -1766,7 +1766,7 @@ async function addCommand(spec, opts, deps = {}) {
1766
1766
  }
1767
1767
  if (parsed.name === CONTEXT_REPO) {
1768
1768
  process.stderr.write(
1769
- `${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}
1770
1770
  `
1771
1771
  );
1772
1772
  return 2;
@@ -2413,7 +2413,7 @@ async function commitContext(input) {
2413
2413
  ui.line("committed", `${shown}/.rness`);
2414
2414
  } catch (e) {
2415
2415
  ui.warn(
2416
- `${e instanceof Error ? e.message : String(e)} \u2014 commit ${shown}/.rness yourself`
2416
+ `${e instanceof Error ? e.message : String(e)}: commit ${shown}/.rness yourself`
2417
2417
  );
2418
2418
  }
2419
2419
  }
@@ -3024,14 +3024,14 @@ async function createCommand(opts, deps = {}) {
3024
3024
  if (joining)
3025
3025
  ui.line(
3026
3026
  "found",
3027
- `${org}/.rness \u2014 joining`,
3028
- `${org} has a workspace \u2014 joining it`
3027
+ `${org}/.rness - joining`,
3028
+ `${org} has a workspace - joining it`
3029
3029
  );
3030
3030
  else
3031
3031
  ui.line(
3032
3032
  "not found",
3033
- `${org}/.rness (or not visible to you) \u2014 starting a new workspace`,
3034
- `${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`
3035
3035
  );
3036
3036
  let catalogue = {
3037
3037
  contract: 1,
@@ -3159,7 +3159,7 @@ async function createCommand(opts, deps = {}) {
3159
3159
  else process.stdout.write(`
3160
3160
  ${next2.map((l) => ` ${l}`).join("\n")}
3161
3161
  `);
3162
- ui.outro(`You joined ${org} \u2014 your workspace is in ${shown}/`);
3162
+ ui.outro(`You joined ${org}: your workspace is in ${shown}/`);
3163
3163
  return failures2.length > 0 ? 1 : 0;
3164
3164
  }
3165
3165
  const built = await buildContext({
@@ -3461,7 +3461,7 @@ function finish(ui, cwd, rnessDir, label, target, ending) {
3461
3461
  `git -C ${c.dir} add ${c.paths.join(" ")} && git -C ${c.dir} commit -m "${message3}"`
3462
3462
  );
3463
3463
  if (ending.commit !== "nothing")
3464
- next.push("# teammates: git pull \u2014 the next rness command installs it");
3464
+ next.push("# teammates: git pull - the next rness command installs it");
3465
3465
  if (ui.session) {
3466
3466
  if (next.length > 0) ui.note("Next steps", next);
3467
3467
  ui.outro(`${label} runs @rness/cli ${target}`);
@@ -3557,18 +3557,18 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3557
3557
  if (pin.spec === target && installed === target)
3558
3558
  ui.line(
3559
3559
  "scaffold",
3560
- `@rness/cli ${target} \u2014 merging it into ${label}`,
3560
+ `@rness/cli ${target}: merging it into ${label}`,
3561
3561
  `Merging the @rness/cli ${target} scaffold into ${label}`
3562
3562
  );
3563
3563
  else if (pin.spec === target)
3564
3564
  ui.line(
3565
3565
  "install",
3566
- `@rness/cli ${target} in ${label} (${pm}) \u2014 ${installed ?? "nothing"} is installed`
3566
+ `@rness/cli ${target} in ${label} (${pm}): ${installed ?? "nothing"} is installed`
3567
3567
  );
3568
3568
  else {
3569
3569
  ui.line(
3570
3570
  "upgrade",
3571
- `@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? " \u2014 downgrading" : ""}`
3571
+ `@rness/cli ${pin.spec} \u2192 ${target} in ${label} (${pm})${downgrading ? ", downgrading" : ""}`
3572
3572
  );
3573
3573
  ui.line("notes", NOTES, `Release notes: ${NOTES}`);
3574
3574
  }
@@ -3597,7 +3597,7 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3597
3597
  ui.line(
3598
3598
  "adopting",
3599
3599
  `the @rness/cli ${target} scaffold (no scaffold commit in ${label} yet)`,
3600
- `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`
3601
3601
  );
3602
3602
  else
3603
3603
  ui.line(
@@ -3685,12 +3685,12 @@ async function upgradeCommand(version, opts, terminal = defaultTerminal, deps =
3685
3685
  if (committed.kind === "committed")
3686
3686
  ui.line(
3687
3687
  "committed",
3688
- `${label} \u2014 ${message3}`,
3688
+ `${label}: ${message3}`,
3689
3689
  `Committed ${label}: ${message3}`
3690
3690
  );
3691
3691
  if (committed.kind === "refused") {
3692
3692
  ui.error(
3693
- `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`
3694
3694
  );
3695
3695
  for (const line3 of committed.output.split("\n"))
3696
3696
  if (line3.trim() !== "") ui.hint(line3, "stderr");
@@ -3760,7 +3760,7 @@ async function checkBoards(rnessDir, manifest) {
3760
3760
  await readmeDeclarations(rnessDir, collection).catch(() => ({}))
3761
3761
  ))
3762
3762
  problems.push(
3763
- `${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`
3764
3764
  );
3765
3765
  }
3766
3766
  for (const key of ["readme", "updates"]) {
@@ -3954,7 +3954,7 @@ async function docNewCommand(collection, opts) {
3954
3954
  ];
3955
3955
  const sections = name === "adr" ? await adrSections(ws.rnessDir) : SECTIONS[name] ?? [];
3956
3956
  const body = [
3957
- `# ${number} \u2014 ${title}`,
3957
+ `# ${number} - ${title}`,
3958
3958
  // The rule under the title, as the ADR and specification templates draw it.
3959
3959
  ...name === "plans" ? [] : ["", "---"],
3960
3960
  ...sections.flatMap((s) => ["", `## ${s}`])
@@ -4037,7 +4037,7 @@ async function takeModNotice(env) {
4037
4037
  );
4038
4038
  } catch {
4039
4039
  }
4040
- 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`;
4041
4041
  }
4042
4042
 
4043
4043
  // src/core/edit-guard.ts
@@ -4145,13 +4145,13 @@ async function safetyNet(ws, manifest) {
4145
4145
  const drift = await pinDrift(ws.rnessDir);
4146
4146
  if (drift !== null)
4147
4147
  notes.push(
4148
- `.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`
4149
4149
  );
4150
4150
  try {
4151
4151
  const { problems } = await checkWorkspace(ws, manifest);
4152
4152
  if (problems.length > 0)
4153
4153
  notes.push(
4154
- `${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`,
4155
4155
  ...problems.slice(0, SHOWN_PROBLEMS).map((p) => ` ${p}`)
4156
4156
  );
4157
4157
  } catch (e) {
@@ -4211,7 +4211,7 @@ async function documents(rnessDir, only) {
4211
4211
  }
4212
4212
  function line(d, withScope = false) {
4213
4213
  const head = [d.id, d.status].filter((x) => x !== null).join(" ");
4214
- 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}`;
4215
4215
  }
4216
4216
  function isCollection(value) {
4217
4217
  return COLLECTIONS.includes(value);
@@ -4353,7 +4353,7 @@ function mcpTools(cwd) {
4353
4353
  {
4354
4354
  name: "rness_context",
4355
4355
  title: "rness: what applies here",
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 \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.",
4357
4357
  inputSchema: {
4358
4358
  type: "object",
4359
4359
  properties: {
@@ -4449,7 +4449,7 @@ function noteTool(cwd, githubApi) {
4449
4449
  additionalProperties: false
4450
4450
  },
4451
4451
  call: (args) => guard(async () => {
4452
- const { postNote } = await import("./note-XSJ7ASXM.js");
4452
+ const { postNote } = await import("./note-MKUG7GOT.js");
4453
4453
  const given = (key) => {
4454
4454
  const value = args[key];
4455
4455
  return typeof value === "string" ? value : void 0;
@@ -4498,7 +4498,7 @@ async function scopeBanner(ws, manifest, scope) {
4498
4498
  const n = summary.counts[c];
4499
4499
  return n === void 0 ? [] : [count(n, NOUNS[c])];
4500
4500
  });
4501
- 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(", ")}`;
4502
4502
  return { banner: banner2, lines: summary.lines };
4503
4503
  }
4504
4504
  var noteLines = (notes) => notes.map((n) => `rness: ${n}`);
@@ -4682,7 +4682,7 @@ async function sessionStart(input, io) {
4682
4682
  notes = [message2(e)];
4683
4683
  }
4684
4684
  const failure = await takeFailure();
4685
- if (failure !== null) notes.push(`board not updated \u2014 ${failure}`);
4685
+ if (failure !== null) notes.push(`board not updated: ${failure}`);
4686
4686
  notes.push(...await takeNotices());
4687
4687
  const warnings = noteLines(notes);
4688
4688
  const compact = input["source"] === "compact";
@@ -5309,7 +5309,7 @@ function noteCommandOf(parent, state, former) {
5309
5309
  ).addOption(new Option("--github-api <base>").hideHelp()).addOption(new Option("--cwd <dir>").hideHelp()).action(
5310
5310
  async (text, opts) => {
5311
5311
  if (former !== void 0) formerly(former, "rness note");
5312
- const { noteCommand } = await import("./note-XSJ7ASXM.js");
5312
+ const { noteCommand } = await import("./note-MKUG7GOT.js");
5313
5313
  state.code = await noteCommand({
5314
5314
  ...opts,
5315
5315
  ...text === void 0 ? {} : { text }
@@ -5596,4 +5596,4 @@ export {
5596
5596
  OWN_COMMANDS,
5597
5597
  catchUp
5598
5598
  };
5599
- //# sourceMappingURL=chunk-S4NARIQP.js.map
5599
+ //# sourceMappingURL=chunk-SX7D5W43.js.map