@rness/cli 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -118,7 +118,10 @@ the files a given agent needs, for the agents the team declares in
118
118
  The rules stay in `.rness/CONVENTIONS.md`; the skills only add the steps.
119
119
  A new document takes the collection's first status (`Proposed` for an
120
120
  ADR, `Draft` otherwise) and the next number of the local checkout; two
121
- branches can pick the same one. No skill commits.
121
+ branches can pick the same one. Each skill records its session: it adds
122
+ the Claude Code session id to `sessions:` in the front matter of what it
123
+ writes or closes — an edit made without a skill leaves none. No skill
124
+ commits.
122
125
  - rness owns values, not files: what is missing is added, nothing else is
123
126
  touched, and a file it cannot parse is reported, never rewritten.
124
127
  `sync --check` and `validate` report a missing value. Removing an agent
@@ -232,7 +235,11 @@ in its Settings`.
232
235
  `.rness/`, in lifecycle order, at most 50), `Collection` (one option per tab of
233
236
  `rness status`; not `Type`, which is GitHub's own issue-type field and
234
237
  filter), `Agent` (`working`), `Session` (`claude · 1a2b3c4d`, plus the
235
- agent type for a subagent) and `Path`. A board per directory, named as
238
+ agent type for a subagent), `Path` and `Sessions` — the document's
239
+ `sessions:` (see "Agent targets"), joined by `, `, written by sync and
240
+ never cleared: which sessions wrote a specification or implemented a plan,
241
+ after they ended (`claude --resume <id>` reopens one on the machine it ran
242
+ on). A board made before 0.15.0 gains `Sessions` at its next sync. A board per directory, named as
236
243
  `rness status` names its tab, filtered on its `Collection`, its columns
237
244
  that collection's own steps: each collection has its own status field
238
245
  (`ADR status`, `Specs status`, …; a directory without statuses is columned
@@ -287,7 +294,9 @@ added to project`) may change a field of rness's items; the next sync
287
294
  - **Hooks**, with `claude` in `agents` and a pulse declared: session start
288
295
  marks the `In progress` plans of the session's scope `Agent: working`, with
289
296
  the session; an edit of a document of `.rness/` marks it — one the agent has just written, with no item yet, gets its issue first
290
- through a sync, and an edit of any other file of `.rness/` costs no sync;
297
+ through a sync, and so does one whose status the edit changed, so its
298
+ card moves within seconds rather than at the session's end; an edit that
299
+ leaves the status alone, or of any other file of `.rness/`, costs no sync;
291
300
  the hooks' syncs run one at a time, an edit's skipped while another runs,
292
301
  the session end's waiting its turn; session end clears
293
302
  the marks of that session (its subagents' included) and syncs. Each one
@@ -302,7 +311,7 @@ added to project`) may change a field of rness's items; the next sync
302
311
  `cannot reach GitHub: …`. Two sessions marking one plan both write; the
303
312
  last wins.
304
313
  - **Rate**: rness sends one request at a time. A new document costs an
305
- issue, its addition to the board, up to four fields, then its body. An
314
+ issue, its addition to the board, up to five fields, then its body. An
306
315
  unchanged document costs nothing but its share of the listing, which
307
316
  reads every item's body. On one of GitHub's rate limits rness waits as
308
317
  long as GitHub says (`waiting 60 s — GitHub's rate limit`), 10 minutes
@@ -336,7 +345,7 @@ repository, the board).
336
345
  `contract`, `provider`, `org`, `agents`, `pulse`, `repos`, `scopes`.
337
346
  - A provider _written_ in `rness.json` that this version cannot talk to
338
347
  (`gitlab`) is refused by `validate`, `create`, `login` and `pulse`:
339
- `provider "gitlab" is not supported by @rness/cli 0.14.0 (supported:
348
+ `provider "gitlab" is not supported by @rness/cli 0.15.0 (supported:
340
349
  github)`. `add`, `sync` and the local commands never refuse. `null` is not a
341
350
  value: an absent key means none.
342
351
 
@@ -513,6 +522,20 @@ per repository, the files to commit there.
513
522
  Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
514
523
  `RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
515
524
 
525
+ ## 0.15.0 — Agent Pulse follows a status change; the sessions are kept
526
+
527
+ - An edit that changes a document's status syncs Agent Pulse at once: its
528
+ card moves within seconds, not at the session's end. An edit that leaves
529
+ the status alone still costs nothing. See "Pulse".
530
+ - `sessions:` in a document's front matter lists the Claude Code sessions
531
+ that wrote or changed it. The lifecycle skills add theirs; the board
532
+ shows them in a new field, `Sessions`, which a session's end never
533
+ clears. A board gains the field at its first sync with 0.15.0. See
534
+ "Pulse" and "Agent targets".
535
+ - `rness upgrade` rewrites the four lifecycle skills; commit
536
+ `.claude/skills/rness/` in each repository.
537
+ - Blocks are unchanged.
538
+
516
539
  ## 0.14.0 — the lifecycle skills; `/rness:status` names a second terminal
517
540
 
518
541
  - The `rness` plugin of Claude Code gains `/rness:adr`, `/rness:spec`,
package/dist/bin/rness.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  findDelegate,
7
7
  reportError,
8
8
  run
9
- } from "../chunk-AXTFDXN2.js";
9
+ } from "../chunk-HGT7BIWK.js";
10
10
 
11
11
  // src/bin/rness.ts
12
12
  import { pathToFileURL } from "url";
@@ -486,7 +486,7 @@ function parseRepoSpec(spec, org, host) {
486
486
  }
487
487
 
488
488
  // src/version.ts
489
- var VERSION = "0.14.0";
489
+ var VERSION = "0.15.0";
490
490
 
491
491
  // src/core/pm.ts
492
492
  import { execFile as execFile2 } from "child_process";
@@ -1070,15 +1070,25 @@ function statusOf(item) {
1070
1070
  const status2 = item.fields?.["status"];
1071
1071
  return typeof status2 === "string" && status2 !== "" ? status2 : null;
1072
1072
  }
1073
+ function sessionsOf(item) {
1074
+ const listed = item.fields?.["sessions"];
1075
+ if (!Array.isArray(listed)) return [];
1076
+ const ids = listed.filter(
1077
+ (s) => typeof s === "string" && s !== ""
1078
+ );
1079
+ return [...new Set(ids)];
1080
+ }
1073
1081
  function rowOf(dir, item) {
1074
1082
  const base = posix3.basename(item.rel, ".md");
1075
1083
  const date = /^(\d{4}-\d{2}-\d{2})-/.exec(base)?.[1] ?? null;
1076
1084
  const number = date === null ? documentNumber(item.rel) : null;
1085
+ const sessions = sessionsOf(item);
1077
1086
  return {
1078
1087
  id: date ?? number ?? base,
1079
1088
  title: documentTitle(item.title ?? base, number),
1080
1089
  status: statusOf(item),
1081
- path: `${dir}/${item.rel}`
1090
+ path: `${dir}/${item.rel}`,
1091
+ ...sessions.length > 0 ? { sessions } : {}
1082
1092
  };
1083
1093
  }
1084
1094
  function newestFirst(a, b) {
@@ -1399,7 +1409,8 @@ function desiredOf(tabs, org) {
1399
1409
  body: headerOf(row.path, org),
1400
1410
  status: statusOf2(row.status),
1401
1411
  type: tab.label,
1402
- statusField: fields2.get(tab.label)?.name ?? null
1412
+ statusField: fields2.get(tab.label)?.name ?? null,
1413
+ sessions: row.sessions?.join(", ") ?? null
1403
1414
  }))
1404
1415
  );
1405
1416
  }
@@ -2488,6 +2499,7 @@ var GitHubBoards = class {
2488
2499
  const agent = await single("Agent", "Agent", [WORKING]);
2489
2500
  const session = await text("Session");
2490
2501
  const path = await text("Path");
2502
+ const sessions = await text("Sessions");
2491
2503
  const current = await views(cache.projectId, this.#o);
2492
2504
  const first = current[0];
2493
2505
  if (first !== void 0 && first.name === DEFAULT_VIEW && !current.some((v) => v.name === ALL_VIEW)) {
@@ -2556,7 +2568,15 @@ var GitHubBoards = class {
2556
2568
  await linkRepository(cache.projectId, memory.id, this.#o);
2557
2569
  added.push(`link ${repository2}`);
2558
2570
  }
2559
- cache.fields = [status2, collection, ...own.values(), agent, session, path];
2571
+ cache.fields = [
2572
+ status2,
2573
+ collection,
2574
+ ...own.values(),
2575
+ agent,
2576
+ session,
2577
+ path,
2578
+ sessions
2579
+ ];
2560
2580
  return added;
2561
2581
  }
2562
2582
  async items(board, options = {}) {
@@ -2581,7 +2601,8 @@ var GitHubBoards = class {
2581
2601
  collectionStatus: r.values[statusFieldName(r.values[COLLECTION_FIELD] ?? "")] ?? null,
2582
2602
  type: r.values[COLLECTION_FIELD] ?? null,
2583
2603
  agent: r.values["Agent"] ?? null,
2584
- session: r.values["Session"] ?? null
2604
+ session: r.values["Session"] ?? null,
2605
+ sessions: r.values["Sessions"] ?? null
2585
2606
  };
2586
2607
  });
2587
2608
  }
@@ -2695,7 +2716,8 @@ var GitHubBoards = class {
2695
2716
  ["Path", want.path],
2696
2717
  [COLLECTION_FIELD, want.type],
2697
2718
  [STATUS_FIELD, want.status],
2698
- ...want.statusField === null ? [] : [[want.statusField, want.status]]
2719
+ ...want.statusField === null ? [] : [[want.statusField, want.status]],
2720
+ ["Sessions", want.sessions]
2699
2721
  ];
2700
2722
  for (const [name, value] of wanted)
2701
2723
  if ((values2[name] ?? null) !== value)
@@ -3473,6 +3495,8 @@ Writing:
3473
3495
  \`org/\` it affects.
3474
3496
  - An ADR it replaces is named in Context. That one becomes \`Superseded\`,
3475
3497
  with \`superseded_by:\`, only once the new ADR is \`Accepted\`.
3498
+ - Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
3499
+ unless it is already there.
3476
3500
  - The rness hook checks every edit under \`${rness}/\`: fix what it reports.
3477
3501
 
3478
3502
  After writing: give the path and the Decision section, and say the ADR
@@ -3510,6 +3534,8 @@ Writing:
3510
3534
  - What was checked in this session (a document read, a command run) is
3511
3535
  written as verified, with the date; everything else as a proposal or an
3512
3536
  open question.
3537
+ - Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
3538
+ unless it is already there.
3513
3539
  - The rness hook checks every edit under \`${rness}/\`: fix what it reports.
3514
3540
 
3515
3541
  After writing: give the path and the summary. It stays \`Draft\` until the
@@ -3550,6 +3576,8 @@ Writing:
3550
3576
  repository has one.
3551
3577
  - Where the plan decides something the specification leaves open, a
3552
3578
  section says so.
3579
+ - Add \`\${CLAUDE_SESSION_ID}\` at the end of \`sessions:\` in the front matter,
3580
+ unless it is already there.
3553
3581
  - The rness hook checks every edit under \`${rness}/\`: fix what it reports.
3554
3582
 
3555
3583
  After writing: give the path and the list of tasks. It becomes \`Ready\` when
@@ -3579,6 +3607,8 @@ Arguments: \`$ARGUMENTS\`.
3579
3607
  ran, what it showed, what could not run and why;
3580
3608
  - the specification: \`Implemented\` once every plan of it is
3581
3609
  \`Completed\`; \`updated\` today;
3610
+ - the plan and the specification: add \`\${CLAUDE_SESSION_ID}\` at the end
3611
+ of \`sessions:\` in their front matter, unless it is already there;
3582
3612
  - the smallest set of documents the work makes inaccurate: \`${rness}/docs/\`,
3583
3613
  the READMEs of the repositories it changed.
3584
3614
  6. A task not proven: the plan stays \`In progress\` \u2014 or \`Blocked\`, the
@@ -7643,7 +7673,7 @@ async function writeOpened(file, opened) {
7643
7673
  }
7644
7674
 
7645
7675
  // src/pulse/plan.ts
7646
- var differs = (item, w) => item.title !== w.title || item.status !== w.status || w.statusField !== null && item.collectionStatus !== w.status || item.type !== w.type;
7676
+ var differs = (item, w) => item.title !== w.title || item.status !== w.status || w.statusField !== null && item.collectionStatus !== w.status || item.type !== w.type || item.sessions !== w.sessions;
7647
7677
  var rank = (i) => i.issue === null ? 2 : i.issue.open ? 0 : 1;
7648
7678
  var keptFirst = (a, b) => rank(a) - rank(b) || (a.issue?.number ?? 0) - (b.issue?.number ?? 0);
7649
7679
  var gone = (item) => item.issue === null ? { kind: "archive", id: item.id } : { kind: "close", id: item.id };
@@ -8029,13 +8059,16 @@ async function mark(opts) {
8029
8059
  return 0;
8030
8060
  }
8031
8061
  const wanted = new Set(opts.paths);
8032
- const documents2 = new Set(
8033
- (await statusTabs(c.rnessDir)).flatMap((t) => t.rows.map((r) => r.path))
8062
+ const documents2 = new Map(
8063
+ (await statusTabs(c.rnessDir)).flatMap(
8064
+ (t) => t.rows.map((r) => [r.path, r.status])
8065
+ )
8034
8066
  );
8035
- const onBoard = new Set(
8036
- items.flatMap((i) => i.path === null ? [] : [i.path])
8067
+ const onBoard = new Map(
8068
+ items.flatMap((i) => i.path === null ? [] : [[i.path, i.status]])
8037
8069
  );
8038
- if ([...wanted].some((p) => documents2.has(p) && !onBoard.has(p))) {
8070
+ const stale = (path) => documents2.has(path) && (!onBoard.has(path) || onBoard.get(path) !== documents2.get(path));
8071
+ if ([...wanted].some(stale)) {
8039
8072
  const synced = await oneSyncAtATime(
8040
8073
  key,
8041
8074
  () => syncBoard(c, board, plainUi, eachAdded),
@@ -8561,4 +8594,4 @@ export {
8561
8594
  OWN_COMMANDS,
8562
8595
  catchUp
8563
8596
  };
8564
- //# sourceMappingURL=chunk-AXTFDXN2.js.map
8597
+ //# sourceMappingURL=chunk-HGT7BIWK.js.map