@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.
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  syncCommand,
27
27
  upgradeCommand,
28
28
  validateCommand
29
- } from "./chunk-T5PINUCP.js";
29
+ } from "./chunk-SX7D5W43.js";
30
30
  import {
31
31
  BoardRefused,
32
32
  COLLECTIONS,
@@ -66,7 +66,7 @@ import {
66
66
  workspaceDirs,
67
67
  writeFileAtomic,
68
68
  writeManifest
69
- } from "./chunk-D3D2WCGW.js";
69
+ } from "./chunk-OUZQGG6V.js";
70
70
 
71
71
  // src/index.ts
72
72
  async function run2(argv) {
@@ -3,20 +3,20 @@ import {
3
3
  NoteRefused,
4
4
  githubRepo,
5
5
  journalOf,
6
+ noteCommand,
6
7
  planIssue,
7
8
  postNote,
8
- pulseNoteCommand,
9
9
  sessionFrom
10
- } from "./chunk-4BM4FUWO.js";
11
- import "./chunk-D3D2WCGW.js";
10
+ } from "./chunk-PW5RMU2G.js";
11
+ import "./chunk-OUZQGG6V.js";
12
12
  export {
13
13
  KINDS,
14
14
  NoteRefused,
15
15
  githubRepo,
16
16
  journalOf,
17
+ noteCommand,
17
18
  planIssue,
18
19
  postNote,
19
- pulseNoteCommand,
20
20
  sessionFrom
21
21
  };
22
- //# sourceMappingURL=note-RBG7OXVI.js.map
22
+ //# sourceMappingURL=note-MKUG7GOT.js.map
@@ -2,7 +2,7 @@ import {
2
2
  githubRepo,
3
3
  journalOf,
4
4
  planIssue
5
- } from "./chunk-4BM4FUWO.js";
5
+ } from "./chunk-PW5RMU2G.js";
6
6
  import {
7
7
  branchOf,
8
8
  commitsBetween,
@@ -12,9 +12,9 @@ import {
12
12
  issuesNoted,
13
13
  plansInProgress,
14
14
  startOf
15
- } from "./chunk-D3D2WCGW.js";
15
+ } from "./chunk-OUZQGG6V.js";
16
16
 
17
- // src/pulse/summary.ts
17
+ // src/board/summary.ts
18
18
  import { resolve } from "path";
19
19
  var SHOWN = 10;
20
20
  function commitsLine(commits) {
@@ -88,4 +88,4 @@ async function postSummary(input) {
88
88
  export {
89
89
  postSummary
90
90
  };
91
- //# sourceMappingURL=summary-UCMFESSA.js.map
91
+ //# sourceMappingURL=summary-5DVUIOJM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/board/summary.ts"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { type Context, type Declared, fromGithub } from '../commands/board.ts'\nimport { githubRepo, journalOf, planIssue } from '../commands/note.ts'\nimport { branchOf, commitsBetween } from '../core/git.ts'\nimport { plansInProgress } from '../core/status.ts'\nimport {\n type NotedIssue,\n forgetNotes,\n forgetStart,\n issuesNoted,\n startOf,\n} from './journal-state.ts'\n\n/**\n * The session-end summary (spec 0030 §6): the commits since the session's\n * start on the current branch, the branch's pull request, the duration; on\n * each issue the session's notes went to, else on the one plan in progress\n * of its scope when there is a commit. No note of the limit. Loaded\n * through `import()` only.\n */\n\nexport interface SummaryInput {\n c: Context\n /** The board that declares `journal-summary`, and so `journal`. */\n board: Declared\n session: string\n /** The session's scope; null, the root's. */\n scope: string | null\n /** The clone the session worked in: a name of `repos`. */\n clone?: string\n}\n\n/** The commits a summary names; the rest are counted. */\nconst SHOWN = 10\n\nfunction commitsLine(commits: readonly string[]): string {\n if (commits.length === 0) return 'no commit'\n const named = commits\n .slice(0, SHOWN)\n .map((s) => `\\`${s}\\``)\n .join(', ')\n const more = commits.length > SHOWN ? ', …' : ''\n return `${commits.length} commit${commits.length === 1 ? '' : 's'} (${named}${more})`\n}\n\n/** The issue of the one plan in progress of the scope: its implementation issue in `repo` mode when there is one. */\nasync function onePlan(\n input: SummaryInput,\n repo: { owner: string; name: string } | null\n): Promise<NotedIssue[]> {\n const { c } = input\n const plans = await plansInProgress(\n { root: c.root, rnessDir: c.rnessDir },\n c.manifest,\n input.scope\n )\n const plan = plans.length === 1 ? plans[0] : undefined\n if (plan === undefined) return []\n if (journalOf([input.board])?.journal.to === 'repo' && repo !== null) {\n const there = await fromGithub(\n c.provider.journalIssue(repo.owner, repo.name, plan)\n )\n if (there !== null)\n return [\n { id: there.id, reference: `${there.repository}#${there.number}` },\n ]\n }\n const issue = await planIssue(c, input.board, plan)\n return [{ id: issue.id, reference: `${issue.repository}#${issue.number}` }]\n}\n\n/** Posts the summary; the issues it went to, none when skipped. The session's records are forgotten either way. */\nexport async function postSummary(input: SummaryInput): Promise<string[]> {\n const { c, session } = input\n const url =\n input.clone === undefined ? undefined : c.manifest.repos[input.clone]?.url\n const dir =\n url === undefined || input.clone === undefined\n ? null\n : resolve(c.root, 'org', input.clone)\n try {\n const start = dir === null ? null : await startOf(dir, session)\n const commits =\n dir === null || start === null\n ? []\n : await commitsBetween(dir, start.head).catch(() => [])\n const found = url === undefined ? null : githubRepo(url)\n // A repository of another owner is not the workspace's (spec 0030 §3.4).\n const repo =\n found !== null && found.owner.toLowerCase() === c.org.toLowerCase()\n ? found\n : null\n const noted = await issuesNoted(c.rnessDir, session)\n const targets =\n noted.length > 0\n ? noted\n : commits.length > 0\n ? await onePlan(input, repo)\n : []\n if (targets.length === 0) return []\n\n const branch = dir === null ? null : await branchOf(dir)\n const pr =\n repo === null || branch === null\n ? null\n : await fromGithub(\n c.provider.pullRequestFor(repo.owner, repo.name, branch)\n )\n const id = session.split(' · ').at(-1) ?? session\n const minutes =\n start === null\n ? null\n : Math.max(1, Math.round((Date.now() - start.at) / 60_000))\n const details = [\n ...(branch === null || start === null\n ? []\n : [`Branch \\`${branch}\\` · ${commitsLine(commits)}`]),\n ...(pr === null || repo === null\n ? []\n : [\n `Pull request ${repo.owner}/${repo.name}#${pr.number} (${pr.state.toLowerCase()})`,\n ]),\n ]\n const body = [\n [\n '**Session summary**',\n session,\n ...(minutes === null ? [] : [`${minutes} min`]),\n ].join(' · '),\n '',\n ...(details.length === 0 ? [] : [...details, '']),\n `<!-- rness note ${id} summary -->`,\n ].join('\\n')\n for (const t of targets) await fromGithub(c.provider.comment(t.id, body))\n return targets.map((t) => t.reference)\n } finally {\n if (dir !== null) await forgetStart(dir, session)\n await forgetNotes(c.rnessDir, session)\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rness/cli",
3
- "version": "0.21.0",
3
+ "version": "0.22.1",
4
4
  "description": "Configuration-plane CLI for rness workspaces: resolve, validate and sync org-level context for AI coding agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,9 +11,9 @@ specifications, plans, standards and skills, resolved per repository by the
11
11
 
12
12
  ## Commands
13
13
 
14
- npm run validate # rness validate — check this tree against the contract
15
- npm run context # rness context — print the resolved context for a scope
16
- npm run sync # rness sync — regenerate blocks (--all clones missing repositories)
14
+ npm run validate # rness validate: check this tree against the contract
15
+ npm run context # rness context: print the resolved context for a scope
16
+ npm run sync # rness sync: regenerate blocks (--all clones missing repositories)
17
17
 
18
18
  The CLI is pinned in `package.json`; any `rness` you run inside the workspace
19
19
  delegates to that copy.
@@ -5,13 +5,13 @@ A rness workspace mirrors one GitHub organisation:
5
5
  ```
6
6
  <org>/
7
7
  ├── AGENTS.md generated global block, not committed
8
- ├── .rness/ this repository — the organisation's context
8
+ ├── .rness/ this repository: the organisation's context
9
9
  └── org/<repo>/ the repositories you work on, cloned; a monorepo is a
10
10
  repository like any other, its parts are declared as scopes
11
11
  ```
12
12
 
13
13
  The workspace root is never a git repository. `rness.json` is the
14
- organisation's catalogue: `repos` (every repository rness knows about — each
14
+ organisation's catalogue: `repos` (every repository rness knows about: each
15
15
  teammate clones the ones they need under `org/`, `rness sync --all` clones
16
16
  them all) and `scopes` (where context resolves: a repository, or a directory
17
17
  inside one, with an optional `extends`).
@@ -2,10 +2,10 @@
2
2
  date: YYYY-MM-DD
3
3
  status: Proposed | Accepted | Rejected | Superseded
4
4
  repo: Repository or scope affected by this decision
5
- superseded_by: '[NNNN](./NNNN-title.md) — only present when status is Superseded'
5
+ superseded_by: '[NNNN](./NNNN-title.md) - only present when status is Superseded'
6
6
  ---
7
7
 
8
- # NNNN — Short decision title
8
+ # NNNN - Short decision title
9
9
 
10
10
  ---
11
11
 
@@ -20,8 +20,8 @@ The chosen approach, in one or two clear sentences.
20
20
 
21
21
  ## Alternatives Considered
22
22
 
23
- - **Option A** — why it was rejected
24
- - **Option B** — why it was rejected
23
+ - **Option A** - why it was rejected
24
+ - **Option B** - why it was rejected
25
25
 
26
26
  ## Consequences
27
27
 
@@ -31,4 +31,4 @@ The chosen approach, in one or two clear sentences.
31
31
 
32
32
  ---
33
33
 
34
- An ADR is never rewritten when the context changes — it is superseded.
34
+ An ADR is never rewritten when the context changes: it is superseded.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pulse/note.ts"],"sourcesContent":["import { relative, resolve, sep } from 'node:path'\n\nimport {\n type Context,\n type Declared,\n context,\n declaredBoards,\n fromGithub,\n} from '../commands/pulse.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 { notePosted, notesPosted, recordNotice } from './journal-state.ts'\nimport { blobUrl, issueUrl } from './urls.ts'\n\n/**\n * `rness pulse 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 pulse sync`)\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 pulse note`: the text from the argument, or stdin when it is absent or `-`. */\nexport async function pulseNoteCommand(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":[]}