@rness/cli 0.20.1 → 0.22.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 +308 -86
- package/dist/bin/rness.js +5 -3
- package/dist/bin/rness.js.map +1 -1
- package/dist/chunk-AEL2W76O.js +263 -0
- package/dist/chunk-AEL2W76O.js.map +1 -0
- package/dist/chunk-S4NARIQP.js +5599 -0
- package/dist/chunk-S4NARIQP.js.map +1 -0
- package/dist/chunk-XCO5ZT2H.js +6960 -0
- package/dist/chunk-XCO5ZT2H.js.map +1 -0
- package/dist/index.js +32 -26
- package/dist/index.js.map +1 -1
- package/dist/note-XSJ7ASXM.js +22 -0
- package/dist/note-XSJ7ASXM.js.map +1 -0
- package/dist/summary-47SFWNSQ.js +91 -0
- package/dist/summary-47SFWNSQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2AFAQO5B.js +0 -10305
- package/dist/chunk-2AFAQO5B.js.map +0 -1
package/README.md
CHANGED
|
@@ -29,8 +29,8 @@ Inside a workspace, every `rness` delegates to the copy pinned in
|
|
|
29
29
|
rness logout
|
|
30
30
|
rness context [--scope <name>] [--json]
|
|
31
31
|
rness status [<tab>] [--json]
|
|
32
|
-
rness
|
|
33
|
-
rness
|
|
32
|
+
rness board push [-y]
|
|
33
|
+
rness note [--plan <path>] [--kind approach|deviation|blocker|done] [<text>]
|
|
34
34
|
rness validate
|
|
35
35
|
rness mcp
|
|
36
36
|
|
|
@@ -63,8 +63,8 @@ when dropped, red `?` when missing.
|
|
|
63
63
|
- `--json`, terminal or not: the tabs and their rows — each row with the
|
|
64
64
|
colour of its status on Agent Pulse (`color`, the board's name for it:
|
|
65
65
|
`yellow` for `In progress`; `red` without a status) and its item there
|
|
66
|
-
(`link`, the board filtered on its path; null without a
|
|
67
|
-
board (`pulse`), and what a Claude Code session shows of the workspace,
|
|
66
|
+
(`link`, the board filtered on its path; null without a board, or before
|
|
67
|
+
`board push` creates it) — the board (`pulse`), and what a Claude Code session shows of the workspace,
|
|
68
68
|
worded by the CLI — the session-start banner, the footer's label, the
|
|
69
69
|
scope's plans `In progress` and the notes of the safety net (see
|
|
70
70
|
"Hooks"). The plugin's mod reads it (see
|
|
@@ -197,7 +197,7 @@ the pinned copy, and computes nothing itself:
|
|
|
197
197
|
document is read from `.rness/` without its front matter, as the
|
|
198
198
|
board's card shows it; `q` brings the list back, Esc still closes. An
|
|
199
199
|
edit of the document shows at the next refresh. **Agent
|
|
200
|
-
Pulse is a link** when the workspace
|
|
200
|
+
Pulse is a link** when the workspace has a board: the board from the
|
|
201
201
|
list, the document's item (the board filtered on its path) from the
|
|
202
202
|
document. The terminal opens it as it opens any hyperlink (cmd+click on
|
|
203
203
|
macOS, as a rule), a desktop surface on a click. In `claude -p`, or where
|
|
@@ -244,7 +244,9 @@ workspace root's carry four Claude Code hooks, all run by the pinned copy:
|
|
|
244
244
|
repository or nothing installed there, a `rness.json` rness refuses, a pin
|
|
245
245
|
the installed copy does not match, the problems `rness validate` reports.
|
|
246
246
|
A Claude Code too old for the plugin's mod gets one more line, once (see
|
|
247
|
-
"The mod").
|
|
247
|
+
"The mod"). When a board keeps a journal and the scope has a plan in
|
|
248
|
+
progress, the model gets one more line: how and when to post a note (see
|
|
249
|
+
"Boards"). After a compaction, the context only.
|
|
248
250
|
- **Before an edit** (`PreToolUse` on `Edit|Write`): refused, with the
|
|
249
251
|
reason for the model, when it would change what `sync` generates — a
|
|
250
252
|
line of the block of an `AGENTS.md` or `CLAUDE.md` (the reason names the
|
|
@@ -258,10 +260,13 @@ workspace root's carry four Claude Code hooks, all run by the pinned copy:
|
|
|
258
260
|
- **After an edit** (`PostToolUse` on `Edit|Write`): when the file is under
|
|
259
261
|
`.rness/`, its front-matter problems — or those of `rness.json` — go back
|
|
260
262
|
to the model, which fixes them in the same turn. Any other edit costs one
|
|
261
|
-
path check. Stale blocks are left to `sync`.
|
|
262
|
-
edit is then marked on
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
path check. Stale blocks are left to `sync`. When a board declares
|
|
264
|
+
`mark` and holds the document, the edit is then marked on it, broken or
|
|
265
|
+
not; see "Boards".
|
|
266
|
+
- **At session end** (`SessionEnd`): when a board declares `clear-marks`,
|
|
267
|
+
clears the marks this session set and syncs; when one declares
|
|
268
|
+
`journal-summary`, posts the session's summary; see "Boards". Without
|
|
269
|
+
either, nothing.
|
|
265
270
|
|
|
266
271
|
Each hook is one fixed `sh` line: it runs
|
|
267
272
|
`<.rness>/node_modules/@rness/cli/dist/bin/rness.js hook <event>` when that
|
|
@@ -273,25 +278,97 @@ own hooks stay where they are.
|
|
|
273
278
|
|
|
274
279
|
Claude Code runs hooks from a committed settings file without asking each
|
|
275
280
|
developer, including in `claude -p`. These four read `.rness/`, write
|
|
276
|
-
|
|
281
|
+
no file of the workspace and run no install; with a journal, the session
|
|
282
|
+
start records the clone's `HEAD` in its git directory. Only with a board created do
|
|
277
283
|
they reach the network, through a detached `rness` process that uses your
|
|
278
|
-
login; when that process fails, it writes why to `
|
|
284
|
+
login; when that process fails, it writes why to `board.json` in rness's
|
|
279
285
|
configuration directory (`~/.config/rness/` by default), which the next
|
|
280
|
-
session start reads, says once and deletes.
|
|
286
|
+
session start reads, says once and deletes (0.21 wrote `pulse.json`: read
|
|
287
|
+
once too). See "Boards". Review a change to
|
|
281
288
|
them like code. Verified with Claude Code 2.1.284 on 2026-09-29: in a clone
|
|
282
289
|
and at the root, the model received the context; after an edit that broke a
|
|
283
290
|
status, it received the problem. The `sh` line is not verified on Windows.
|
|
284
291
|
|
|
285
|
-
###
|
|
286
|
-
|
|
287
|
-
rness
|
|
288
|
-
rness
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
### Boards
|
|
293
|
+
|
|
294
|
+
rness board push # every board rness.json declares: created if it is not yet, then brought up to date
|
|
295
|
+
rness note "…" # the agent's journal on the plan in progress
|
|
296
|
+
|
|
297
|
+
A board is a view of the rules the agent applies: the documents of
|
|
298
|
+
`.rness/` — decisions, specifications, plans, a team's own collections —
|
|
299
|
+
and where an agent is at work on them. The provider supplies the tool:
|
|
300
|
+
GitHub Projects today. Each board is declared in `rness.json`, under
|
|
301
|
+
`boards`: first **Agent Pulse** (`pulse`), where the team sees — and reads
|
|
302
|
+
— every document of `.rness/`, and sees when an agent is at work on one.
|
|
303
|
+
rness writes the boards; if it is not in rness, it does not belong there.
|
|
304
|
+
|
|
305
|
+
- **Boards declared in `rness.json`** (0.21.0; `boards` since 0.22.0,
|
|
306
|
+
`projects` before): `boards` maps a name to a board, written whole — its
|
|
307
|
+
`number`, `collections`, `colors`, `fields`, `labels`, `views`, and
|
|
308
|
+
optionally `title`, `description`, `readme` and `updates` (files of
|
|
309
|
+
`.rness/`) — or to a preset not created yet, by name:
|
|
310
|
+
`"boards": { "pulse": "agent-pulse", "marketing": "collection" }`
|
|
311
|
+
(`agent-pulse` for `pulse`, `collection` for a collection's board; see
|
|
312
|
+
"A board created"). What `rness.json` says is
|
|
313
|
+
the board; what it does not declare, the board does not have, but the
|
|
314
|
+
engine's own: one issue of `.rness` per document, found by its `Path`,
|
|
315
|
+
its `Status`, the label `rness`. Nothing knows Agent Pulse by name: it
|
|
316
|
+
is a board like any other, made from the preset `agent-pulse`, and the
|
|
317
|
+
example a team copies for another.
|
|
318
|
+
- `collections`: `"all"` (ADR, specs and plans with the contract's
|
|
319
|
+
statuses, then every other directory `rness status` finds, but those
|
|
320
|
+
another board holds), or directories, each with `statuses` —
|
|
321
|
+
`"contract"`, `"found"` or a list in order — a `label` and an optional
|
|
322
|
+
`field`, a select of its statuses alone.
|
|
323
|
+
- `fields`: each a `type` (`text`, `date`, `select`, `number`) and a
|
|
324
|
+
`from`: a front-matter key, or what rness knows — `$collection`,
|
|
325
|
+
`$status`, `$agent` (`working` while a session marks the card),
|
|
326
|
+
`$session`, `$sessions`, `$id` — or a list, the first present winning.
|
|
327
|
+
`Path`, `Status` and GitHub's own fields cannot be declared.
|
|
328
|
+
- `views`: each a `name` and a `layout` (`board`, `table`, `roadmap`),
|
|
329
|
+
optionally `collection` and `filter`; a board's `columns`, a table's
|
|
330
|
+
`fields`, a roadmap's `date`.
|
|
331
|
+
- `colors`: option → `gray`, `blue`, `green`, `yellow`, `orange`, `red`,
|
|
332
|
+
`pink` or `purple`; an option not named takes its kind's colour (a
|
|
333
|
+
status its tone, a collection pink). A colour changed is set at the
|
|
334
|
+
next sync, every card keeping its value.
|
|
335
|
+
- A board that `rness.json` declares wrongly is refused alone, by its
|
|
336
|
+
full key (`"boards.marketing.views[2].date" must name a date
|
|
337
|
+
field`); the others sync. `validate` reports it, and also a collection
|
|
338
|
+
that is no directory of `.rness/`, one on two boards, a `readme` or
|
|
339
|
+
`updates` not there, a README that still declares (below). `readme`
|
|
340
|
+
and `updates` are paths within `.rness/`: a path out of it, or a file
|
|
341
|
+
that is a link leading out, is refused before anything is read.
|
|
342
|
+
- A view declared and missing is made; one whose filter or fields differ
|
|
343
|
+
is updated in place, keeping its id, sort and widths (GitHub returns a
|
|
344
|
+
filter as given and the fields in the project's order, read on
|
|
345
|
+
2026-10-06); one whose layout or columns differ is made again. A view
|
|
346
|
+
rness made and no longer declared is deleted; one the team made is
|
|
347
|
+
left, and said once per clone (`note view Roadmap is not declared:
|
|
348
|
+
delete it on GitHub if unwanted`), as is a field no longer declared and
|
|
349
|
+
views out of the declared order (GitHub reorders none). A roadmap's
|
|
350
|
+
date is chosen in its settings: GitHub's API does not set it.
|
|
351
|
+
- **Presets and their revisions.** `board push` writes a board from a
|
|
352
|
+
preset, `agent-pulse` or `collection`, recording it (`"preset":
|
|
353
|
+
"agent-pulse/1"`). When a later rness ships a newer revision, `rness
|
|
354
|
+
sync` merges it into the board value by value: a value the team never
|
|
355
|
+
changed takes the new one, one it changed is kept, and said when the
|
|
356
|
+
revision changed it too (`kept boards.pulse.colors.Draft: kept orange,
|
|
357
|
+
agent-pulse/2 gives blue`). Removing `preset` takes a board off the
|
|
358
|
+
merge. An upgrade commits the result, for the team to read before
|
|
359
|
+
pushing.
|
|
360
|
+
- **From 0.20 and before.** A board declared by its number
|
|
361
|
+
(`"pulse": 4`) is read as its preset, and `rness sync` — which `rness
|
|
362
|
+
upgrade` runs — writes it whole; nothing changes on GitHub. A
|
|
363
|
+
collection's `README.md` that declared `description`, `statuses`,
|
|
364
|
+
`fields` or `labels` has them moved into its board and out of its front
|
|
365
|
+
matter (a value declared otherwise in both is refused, naming both).
|
|
366
|
+
Until then, `board push` skips a board whose README still declares.
|
|
367
|
+
- **From 0.21 and before.** `projects`, and the older
|
|
368
|
+
`"pulse": { "project": <number> }`, still read as `boards`; more than
|
|
369
|
+
one of the three at once is refused. `rness sync` renames the key
|
|
370
|
+
(`renamed projects to boards in .rness/rness.json`), the boards as they
|
|
371
|
+
were, and every write of `rness.json` writes `boards`.
|
|
295
372
|
|
|
296
373
|
- **Items**: one per document of `rness status`, an issue of
|
|
297
374
|
`<org>/.rness` added to the project. GitHub shows it only to people who
|
|
@@ -327,10 +404,9 @@ status, …`) and its body the document (see **Body**). It carries the
|
|
|
327
404
|
on `main`, and branches of it are rare). The project is linked to
|
|
328
405
|
`.rness`, so Agent Pulse shows in its Projects tab. Comments are the
|
|
329
406
|
team's: a spec's discussion lives on its issue, and rness never writes
|
|
330
|
-
or deletes one. `
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
in its Settings`.
|
|
407
|
+
or deletes one. `board push` needs Issues on `.rness`. Without them it
|
|
408
|
+
stops before writing anything: `boards need Issues on <org>/.rness: turn
|
|
409
|
+
them on in its Settings`.
|
|
334
410
|
- **Body**: the document, the same bytes for the same document. It starts
|
|
335
411
|
with a first line: the document's path and a link to the file. Then comes
|
|
336
412
|
the document without its front matter (the status is a field) and
|
|
@@ -363,35 +439,46 @@ Session → Working session`). A board per directory, named as
|
|
|
363
439
|
`rness status` names its tab, filtered on its `Collection`, its columns
|
|
364
440
|
that collection's own steps: each collection has its own status field
|
|
365
441
|
(`ADR status`, `Specs status`, …; a directory without statuses is columned
|
|
366
|
-
by `Status`, which holds them all for the `All` table). `
|
|
442
|
+
by `Status`, which holds them all for the `All` table). `board push`
|
|
367
443
|
remakes a board built by an earlier version (its URL changes once); a `Working` table, filtered on `Agent: working`. A first view named `View 1` (GitHub's default) becomes `All` when no `All` exists, on create and on sync, showing Title, Collection, Status and Working session. Options are coloured (statuses by lifecycle: blue proposed, purple approved, yellow in progress, red blocked or rejected, yellow superseded, green done, gray abandoned; collections and `working` too); a sync recolours rness's options and leaves other options' colours alone. rness does
|
|
368
444
|
not set the project's visibility: the project gets GitHub's default for a
|
|
369
445
|
new organization project, which is private (`public: false`). Verified
|
|
370
446
|
with Claude Code 2.1.284 on 2026-09-29.
|
|
371
|
-
- **Login**:
|
|
372
|
-
when the workspace declares a
|
|
373
|
-
terminal it offers to log in; with `-y` or off a terminal it stops
|
|
374
|
-
`
|
|
375
|
-
`
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
scope, so
|
|
447
|
+
- **Login**: boards need the `project` scope. `rness login` asks for it
|
|
448
|
+
when the workspace declares a board, and `board push` when it creates one
|
|
449
|
+
(in a terminal it offers to log in; with `-y` or off a terminal it stops
|
|
450
|
+
with `boards need a GitHub login: run rness login` or
|
|
451
|
+
`boards need the project scope: run rness login`). A developer who never
|
|
452
|
+
uses boards grants nothing more than `repo read:org`. When GitHub cannot
|
|
453
|
+
be asked, rness says so (`cannot reach GitHub: …`, or GitHub's own
|
|
454
|
+
answer) instead of asking for a login. A classic `GITHUB_TOKEN` works if
|
|
455
|
+
it carries the scope; a fine-grained or GitHub App token reports no
|
|
456
|
+
scope, so boards refuse it whatever its permissions. An organization
|
|
381
457
|
that restricts OAuth apps must approve "Rness", as for its private
|
|
382
458
|
repositories.
|
|
383
|
-
-
|
|
384
|
-
|
|
385
|
-
`
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
459
|
+
- **A board created** (0.22.0): a board of `boards` without a `number` —
|
|
460
|
+
a preset's name, or a declaration that leaves it out — is not on GitHub
|
|
461
|
+
yet, and `board push` creates it. Its name is `pulse` or a collection of
|
|
462
|
+
`.rness/`, else it is refused before GitHub is asked anything (`validate`
|
|
463
|
+
says so too). In a terminal push asks once
|
|
464
|
+
(`Create Agent Pulse (pulse) on GitHub, in acme?`); `-y` does not ask.
|
|
465
|
+
Off a terminal without `-y`, or declined, it creates none, pushes the
|
|
466
|
+
others and exits 1: `not created: pulse — rness board push in a terminal,
|
|
467
|
+
or with --yes, creates it`. Then, in order: the login and its `project`
|
|
468
|
+
scope, Issues on `.rness`, the project, and at once its `number` in
|
|
469
|
+
`rness.json` — a preset's name is written whole from that preset, a
|
|
470
|
+
declaration gets its `number` and nothing else — with the `provider`;
|
|
471
|
+
then the fields, options and views, and a first push. Its `created` lines
|
|
472
|
+
say what it added, and the last line what to commit
|
|
473
|
+
(`git -C .rness commit -am "chore: board pulse"`). If a step after the
|
|
474
|
+
project fails, it exits 1 with the number written, and the next
|
|
475
|
+
`board push` completes the layout. A project deleted on GitHub is not
|
|
476
|
+
made again: push stops on `GitHub has no project 4 in acme`; removing the
|
|
477
|
+
`number` asks for a new one. A workspace needs an `org` (a blank one is
|
|
478
|
+
refused); one without a `provider` whose repositories look like GitLab
|
|
479
|
+
is refused before anything is created: write `"provider": "github"` if
|
|
480
|
+
the organization is on GitHub.
|
|
481
|
+
- **`board push`** works in two passes. First every document gets its
|
|
395
482
|
issue — created, converted from a 0.12.0 draft, or reopened — with its
|
|
396
483
|
title, label and fields. Then the bodies whose digest differs are
|
|
397
484
|
written, since a body links to other documents' issues by number. It
|
|
@@ -411,15 +498,18 @@ unchanged`.
|
|
|
411
498
|
as the team's item. A workflow someone turns on (`Item closed`, `Item
|
|
412
499
|
added to project`) may change a field of rness's items; the next sync
|
|
413
500
|
writes it back.
|
|
414
|
-
- **A collection's own
|
|
415
|
-
gives a directory of `.rness/` whose
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
holds them. `
|
|
421
|
-
Pulse. The project is written from the collection's files, one way:
|
|
422
|
-
- `<collection>/README.md` is its README
|
|
501
|
+
- **A collection's own board** (0.17.0): `"marketing": "collection"` in
|
|
502
|
+
`boards`, then `rness board push`, gives a directory of `.rness/` whose
|
|
503
|
+
documents carry a status — a tab of `rness status` — a project of its
|
|
504
|
+
own, named after it, written whole from the preset `collection` into
|
|
505
|
+
`boards.marketing`. Agent Pulse keeps every other collection and the
|
|
506
|
+
`Working` table; the collection's items leave it (`deleteProjectV2Item`,
|
|
507
|
+
their issues untouched) once its board holds them. `board push` pushes
|
|
508
|
+
the collections' boards, then Agent Pulse. The project is written from the collection's files, one way:
|
|
509
|
+
- `<collection>/README.md` is its README (`readme` in its board since
|
|
510
|
+
0.21.0, where `description`, `statuses`, `fields` and `labels` are
|
|
511
|
+
declared too: what follows is how a README declared them before,
|
|
512
|
+
which `rness sync` moves); its front matter may give
|
|
423
513
|
`description:` (the short description), `statuses:` (the columns, in
|
|
424
514
|
order, each there even when empty), `fields:` (each a name, a `type` —
|
|
425
515
|
`text`, `date`, `select`, `number` — and `from`, the front-matter key
|
|
@@ -438,9 +528,25 @@ added to project`) may change a field of rness's items; the next sync
|
|
|
438
528
|
none of this reaches Agent Pulse: a workspace that declares no collection
|
|
439
529
|
keeps its board as 0.16 made it.
|
|
440
530
|
|
|
441
|
-
- **Hooks**, with `claude` in `agents
|
|
442
|
-
|
|
443
|
-
|
|
531
|
+
- **Hooks**, with `claude` in `agents`: what a session does to a board is
|
|
532
|
+
declared in its `hooks` (spec 0032, 0.21.0), each event — `session-start`,
|
|
533
|
+
`edit`, `session-end` — listing actions from a fixed catalogue:
|
|
534
|
+
`mark-in-progress` (the documents of the session's scope in the given
|
|
535
|
+
`collections` and `statuses`, `plans` and `In progress` by default),
|
|
536
|
+
`mark` (the document edited, on a board that holds it) and `clear-marks`
|
|
537
|
+
(the session's marks, then a sync). Marks are written through the
|
|
538
|
+
board's select from `$agent` and its text from `$session`, whatever their
|
|
539
|
+
names. A hook never runs a command `rness.json` names: the file is the
|
|
540
|
+
organization's and the hooks run on every developer's machine. The
|
|
541
|
+
preset `agent-pulse` declares all three, which is 0.20's behaviour;
|
|
542
|
+
removing `hooks` from a board turns its marking off, and a board without
|
|
543
|
+
them is only what `board push` makes of the documents. For each event,
|
|
544
|
+
one detached `rness board run <event>` does every board's actions, in
|
|
545
|
+
the order of `boards`; a failure is recorded naming the board and the
|
|
546
|
+
action (`mark on Marketing failed: …`). A board not created yet runs
|
|
547
|
+
none. With Agent Pulse's preset:
|
|
548
|
+
session start marks the `In progress` plans of the session's scope
|
|
549
|
+
`Agent: working`, with 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
|
|
444
550
|
through a sync, and so does one whose status the edit changed, so its
|
|
445
551
|
card moves within seconds rather than at the session's end; an edit that
|
|
446
552
|
leaves the status alone, or of any other file of `.rness/`, costs no sync;
|
|
@@ -453,11 +559,45 @@ added to project`) may change a field of rness's items; the next sync
|
|
|
453
559
|
its file 3 s after `/exit`. It uses your login: with none, without the
|
|
454
560
|
scope, or when GitHub cannot be reached, nothing is sent, and the next
|
|
455
561
|
session start's banner says why, once:
|
|
456
|
-
`rness:
|
|
457
|
-
`
|
|
562
|
+
`rness: board not updated — <reason>`, such as
|
|
563
|
+
`boards need the project scope: run rness login` or
|
|
458
564
|
`cannot reach GitHub: …`. Two sessions marking one plan both write; the
|
|
459
565
|
last wins.
|
|
460
|
-
- **
|
|
566
|
+
- **Agent journal** (spec 0030, 0.21.0): how a plan was implemented, in
|
|
567
|
+
the agent's words. A board that holds `plans` declares
|
|
568
|
+
`{ "action": "journal", "to": "plan" | "repo", "limit": 5 }` at
|
|
569
|
+
`session-start`, and `journal-summary` at `session-end`. With a plan
|
|
570
|
+
`In progress` in the session's scope, the session start tells the model
|
|
571
|
+
to post a note — `rness note`, or `rness_note` — when it chooses an
|
|
572
|
+
approach, deviates from the plan, is blocked, and when done: decisions
|
|
573
|
+
and their reasons, not steps. A note is a comment headed
|
|
574
|
+
`**Approach** · claude · 1a2b3c4d · \`feat/limits\` @ \`9f8e7d6\``
|
|
575
|
+
(`--kind`titles it; the branch and commit are those of the session's
|
|
576
|
+
repository), then the text, from the argument or stdin. With`"plan"`it goes to the plan's issue in`.rness`. With `"repo"`, to the plan's
|
|
577
|
+
implementation issue in the repository the session works in: labelled
|
|
578
|
+
`rness:plan`, found again by the last line of its body, made by the
|
|
579
|
+
first note and made a sub-issue of the plan's. The note prints where it
|
|
580
|
+
went (`acme/api#87`), for the pull request that completes the plan there
|
|
581
|
+
to carry `Closes acme/api#87`and an earlier one`Refs acme/api#87`.
|
|
582
|
+
GitHub closes the issue when a person merges that pull request into the
|
|
583
|
+
default branch; rness closes nothing. A repository with its issues off,
|
|
584
|
+
that refuses this login's write, or not under the organization on GitHub
|
|
585
|
+
sends the note to the plan's issue, its first line saying why, and the
|
|
586
|
+
next session start says so once. A session in `.rness/`or at the root
|
|
587
|
+
writes on the plan's issue. With several plans in progress,`--plan`names one. Each note holds 1 to 4,000 characters; a session posts at most`limit` per plan (`journal full for this session: put the rest in the
|
|
588
|
+
pull request`); a note that looks like it holds a credential (`ghp_`,
|
|
589
|
+
`gho_`, `github_pat_`, `AKIA…`, a private key, `xox…-`, `sk-…`) is
|
|
590
|
+
refused, never redacted. The counts stay in the `.rness` clone's git
|
|
591
|
+
directory (`rness/journal`), never pushed. At the session's end,
|
|
592
|
+
`journal-summary`posts`**Session summary** · claude · 1a2b3c4d ·
|
|
593
|
+
47 min`, the branch and its commits since the session started (its
|
|
594
|
+
`HEAD`, recorded in the clone's git directory, `rness/sessions/<id>`)
|
|
595
|
+
and the branch's pull request: to each issue the notes went to, else to
|
|
596
|
+
the one plan in progress when there is a commit; with neither, nothing.
|
|
597
|
+
It counts toward no limit. Not verified against GitHub yet (2026-10-06):
|
|
598
|
+
a sub-issue across repositories, and `Closes` on a pull request merged
|
|
599
|
+
into the default branch.
|
|
600
|
+
- **One issue per document**: before making an issue, `board push` reads
|
|
461
601
|
the open issues of `.rness` labelled `rness` (one request per 100, and
|
|
462
602
|
only when it has one to make). One whose body starts with the document's
|
|
463
603
|
first line was made by an earlier sync, whose item the board's listing
|
|
@@ -474,10 +614,16 @@ added to project`) may change a field of rness's items; the next sync
|
|
|
474
614
|
documents, 2026-09-30): the migration from 0.12.0 took 169 s with no
|
|
475
615
|
wait; a sync with nothing to change, 4 s; the listing, one page of
|
|
476
616
|
852 KB in about 1 s.
|
|
477
|
-
- **Not yet**: GitLab and Atlassian. `create` lists
|
|
478
|
-
workspace whose `rness.json` names one is refused by
|
|
479
|
-
and `Review` statuses, several agents on one
|
|
480
|
-
other than Claude Code are not built.
|
|
617
|
+
- **Not yet**: GitLab and Atlassian, and their own boards. `create` lists
|
|
618
|
+
them, disabled; a workspace whose `rness.json` names one is refused by
|
|
619
|
+
`board push`. `Waiting` and `Review` statuses, several agents on one
|
|
620
|
+
board and hooks for agents other than Claude Code are not built.
|
|
621
|
+
- **`rness pulse`**, the name of all this until 0.21: hidden, each of its
|
|
622
|
+
commands still runs as its new one and says so once on stderr
|
|
623
|
+
(`rness pulse sync is now rness board push`); `rness pulse create
|
|
624
|
+
[<collection>]` adds the preset's name to `boards` when it is not there,
|
|
625
|
+
then pushes without asking. `rness pulse mark`, which 0.20's hooks
|
|
626
|
+
started, exits 0 and does nothing. The alias goes in a later minor.
|
|
481
627
|
|
|
482
628
|
### Provider
|
|
483
629
|
|
|
@@ -496,13 +642,16 @@ repository, the board).
|
|
|
496
642
|
names.
|
|
497
643
|
- A workspace without the key is read from its first repository URL: a
|
|
498
644
|
GitLab host reads as `gitlab`, any other host — or no repository — as
|
|
499
|
-
`github`. Nothing to change: `
|
|
500
|
-
detected provider this version cannot talk to. The
|
|
501
|
-
`contract`, `provider`, `org`, `agents`, `
|
|
502
|
-
|
|
503
|
-
`"
|
|
645
|
+
`github`. Nothing to change: `board push` writes it when it creates a
|
|
646
|
+
board, and refuses a detected provider this version cannot talk to. The
|
|
647
|
+
order of keys is `contract`, `provider`, `org`, `agents`, `boards`,
|
|
648
|
+
`repos`, `scopes`. The former `projects` and
|
|
649
|
+
`"pulse": { "project": <number> }` still read, as `boards`; more than one
|
|
650
|
+
of them at once is refused. A board in `boards` is written whole, on
|
|
651
|
+
several lines, once created; a number still reads, as its preset, until
|
|
652
|
+
`rness sync` writes it whole.
|
|
504
653
|
- A provider _written_ in `rness.json` that this version cannot talk to
|
|
505
|
-
(`gitlab`) is refused by `validate`, `create`, `login` and `
|
|
654
|
+
(`gitlab`) is refused by `validate`, `create`, `login` and `board`:
|
|
506
655
|
`provider "gitlab" is not supported by @rness/cli 0.17.1 (supported:
|
|
507
656
|
github)`. `add`, `sync` and the local commands never refuse. `null` is not a
|
|
508
657
|
value: an absent key means none.
|
|
@@ -511,22 +660,26 @@ github)`. `add`, `sync` and the local commands never refuse. `null` is not a
|
|
|
511
660
|
|
|
512
661
|
rness mcp # started by the agent over stdio, not by hand
|
|
513
662
|
|
|
514
|
-
A local
|
|
515
|
-
|
|
516
|
-
|
|
663
|
+
A local MCP server over the workspace's `.rness/`, for an agent to find what
|
|
664
|
+
applies to the repository it works in and where a subject was decided. It
|
|
665
|
+
is read-only but for `rness_note`, listed only when a board keeps a journal
|
|
666
|
+
as the server starts (Claude Code starts it with the session):
|
|
517
667
|
|
|
518
|
-
| Tool
|
|
519
|
-
|
|
|
520
|
-
| `rness_context({ scope? })`
|
|
521
|
-
| `rness_list({ collection, status? })`
|
|
522
|
-
| `rness_read({ path })`
|
|
523
|
-
| `rness_search({ query, collection? })`
|
|
668
|
+
| Tool | Returns |
|
|
669
|
+
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
670
|
+
| `rness_context({ scope? })` | the scope of the working directory (or the one named) and what applies to it: standards, decisions, specifications, plans — id, status, title, path |
|
|
671
|
+
| `rness_list({ collection, status? })` | every document of a collection, across scopes, optionally of one status |
|
|
672
|
+
| `rness_read({ path })` | one file of `.rness/`, 256 KiB at most; nothing outside it |
|
|
673
|
+
| `rness_search({ query, collection? })` | the documents that match, most matching first, with the matching lines |
|
|
674
|
+
| `rness_note({ text, session, kind?, plan? })` | a note of the agent's journal posted to GitHub, as `rness note` posts it; the issue it went to (see "Boards") |
|
|
524
675
|
|
|
525
676
|
- MCP over stdio, one message per line: the `2026-07-28` revision and the
|
|
526
677
|
earlier ones that open with `initialize` (`2025-11-25` back to
|
|
527
678
|
`2024-11-05`). No MCP SDK, no added dependency.
|
|
528
679
|
- `.rness/` is read again on each call, so an edit shows at once. Nothing is
|
|
529
|
-
written.
|
|
680
|
+
written, but by `rness_note`, which posts with your login. It takes the
|
|
681
|
+
session as an argument (`claude · 1a2b3c4d`, as the session start spells
|
|
682
|
+
it): the server's environment names none.
|
|
530
683
|
- With `claude` in `agents`, `sync` registers it in each clone:
|
|
531
684
|
`.mcp.json` gets `mcpServers.rness`, which runs the pinned copy
|
|
532
685
|
(`node ../../.rness/node_modules/@rness/cli/dist/bin/rness.js mcp`). A
|
|
@@ -558,7 +711,7 @@ anonymously.
|
|
|
558
711
|
it — CI needs no login.
|
|
559
712
|
- rness asks for `repo` and `read:org`: GitHub has no read-only scope for
|
|
560
713
|
private repositories. It only lists and clones. Where the workspace
|
|
561
|
-
declares a
|
|
714
|
+
declares a board it asks for `project` too; see "Boards".
|
|
562
715
|
- A new workspace has to reach GitHub before teammates can join it. Logged
|
|
563
716
|
in, the `create` wizard offers to do it: it creates the private repository
|
|
564
717
|
`<org>/.rness` and pushes the context with `git`. Declined, refused by
|
|
@@ -695,6 +848,75 @@ per repository, the files to commit there.
|
|
|
695
848
|
Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
|
|
696
849
|
`RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
|
|
697
850
|
|
|
851
|
+
## 0.22.0 — `board`, not `pulse`: `rness board push`, `rness note`, `boards` in rness.json
|
|
852
|
+
|
|
853
|
+
- One word for the view, whatever the provider (spec 0033, see "Boards"):
|
|
854
|
+
`rness board push` replaces `rness pulse sync`, `rness note` replaces
|
|
855
|
+
`rness pulse note`, and the hooks start `rness board run`. `rness.json`
|
|
856
|
+
names its boards `boards`; `projects` and the older `pulse` still read,
|
|
857
|
+
and `rness sync` (which `rness upgrade` runs) renames the key. `pulse`
|
|
858
|
+
stays the name of the board rness ships, Agent Pulse.
|
|
859
|
+
- A board comes to exist by its declaration and a push: there is no
|
|
860
|
+
`create`. A board of `boards` without a `number`, or a preset by name
|
|
861
|
+
(`"pulse": "agent-pulse"`, `"marketing": "collection"`), is created by
|
|
862
|
+
`rness board push` once asked (`-y` off a terminal), its number then
|
|
863
|
+
written into `rness.json`.
|
|
864
|
+
- `rness pulse …` still runs, hidden, as its new command, and says so on
|
|
865
|
+
stderr; it goes in a later minor. `rness pulse mark`, kept through
|
|
866
|
+
0.21.x for 0.20's hooks, now exits 0 and does nothing. Spec 0031's
|
|
867
|
+
`eject` is not built and will not be: every board is written whole.
|
|
868
|
+
- The session-start notice is `rness: board not updated — …`, its record
|
|
869
|
+
`board.json` (one 0.21 left in `pulse.json` is said once), and messages
|
|
870
|
+
name boards: `boards need a GitHub login: run rness login`.
|
|
871
|
+
- Upgrade with `npx @rness/cli@latest upgrade`, which runs the new copy
|
|
872
|
+
throughout: a 0.21 copy cannot read `boards` (`unknown key "boards"`).
|
|
873
|
+
- For the package's API: `Manifest.projects` is `Manifest.boards`
|
|
874
|
+
(`Boards`, a record of `BoardEntry`: a number, a preset's name, or a
|
|
875
|
+
`BoardDeclaration`, whose `number` is null until the board is created).
|
|
876
|
+
|
|
877
|
+
## 0.21.0 — boards declared in rness.json; what a session does to a board, declared; the agent's journal
|
|
878
|
+
|
|
879
|
+
- The agent journal (spec 0030, see "Pulse"): a board declares `journal`
|
|
880
|
+
at `session-start` and `journal-summary` at `session-end`. The agent
|
|
881
|
+
posts notes on the plan it implements — `rness pulse note`, or
|
|
882
|
+
`rness_note` of `rness mcp` — to the plan's issue in `.rness`, or to an
|
|
883
|
+
implementation issue in the repository it works in, a sub-issue of the
|
|
884
|
+
plan's, which the pull request closes. The session's end posts a summary:
|
|
885
|
+
its commits, its pull request, its duration. The preset `agent-pulse`
|
|
886
|
+
declares neither: nothing changes until a board does.
|
|
887
|
+
- Boards are declared in `rness.json` (spec 0031, see "Pulse"): each one's
|
|
888
|
+
collections, statuses, colours, fields, labels and views, written whole.
|
|
889
|
+
Agent Pulse is the preset `agent-pulse`, no longer a special case of the
|
|
890
|
+
code. `pulse create` writes the board it makes; `rness sync` (which
|
|
891
|
+
`rness upgrade` runs) writes a board declared by its number whole, moves
|
|
892
|
+
a collection's README declarations into its board, and merges a newer
|
|
893
|
+
revision of a preset value by value. Views are updated in place where
|
|
894
|
+
GitHub allows; a view rness made and no longer declared is deleted, the
|
|
895
|
+
team's are said once. Nothing changes on GitHub for a board 0.20 made.
|
|
896
|
+
For the package's API: `Projects` is `Record<string, number |
|
|
897
|
+
BoardDeclaration>`; `BoardDeclaration` and `parseBoard` are exported.
|
|
898
|
+
- A board's `readme` and `updates` stay within `.rness/`: a path out of
|
|
899
|
+
it, or a link leading out, is refused before anything is read.
|
|
900
|
+
- What a session does to a board is declared in its `hooks` (spec 0032):
|
|
901
|
+
`mark-in-progress`, `mark` and `clear-marks`, from a fixed catalogue; a
|
|
902
|
+
hook never runs a command `rness.json` names. The preset `agent-pulse`
|
|
903
|
+
declares today's three, so nothing changes on GitHub. The hooks start
|
|
904
|
+
`rness pulse run <event>`; `rness pulse mark` stays, hidden, through
|
|
905
|
+
0.21.x, for sessions started before an upgrade.
|
|
906
|
+
- `upgrade` run by a workspace's pinned copy installed with pnpm no longer
|
|
907
|
+
ends on `mod directory not found next to the @rness/cli package`. After
|
|
908
|
+
its commit it lists the files to commit in the clones, and that list read
|
|
909
|
+
the plugin's mod from the folder of the copy running it, which the install
|
|
910
|
+
had just removed. The list now takes the paths alone. The upgrade itself
|
|
911
|
+
was complete: 0.20.0 to 0.20.1 printed the error after its commit.
|
|
912
|
+
- An upgrade to 0.21.0 run by a 0.20 copy (`pnpm rness upgrade` from
|
|
913
|
+
`.rness/`) ends, after its commit, on `rness.json: "projects" must map
|
|
914
|
+
names to distinct project numbers`: the old copy, finishing, cannot read
|
|
915
|
+
the boards the new version has just written. The upgrade is complete, and
|
|
916
|
+
`rness validate` passes. `npx @rness/cli@latest upgrade` runs the new
|
|
917
|
+
copy throughout; `pnpm dlx @rness/cli` takes the previous version for a
|
|
918
|
+
day after a release, pnpm refusing a version younger than 24 hours.
|
|
919
|
+
|
|
698
920
|
## 0.20.1 — the workspace's line in the prompt footer, without a warning sign; the mod never installs the pin
|
|
699
921
|
|
|
700
922
|
- The workspace's line in Claude Code moves from the pinned status line to
|
package/dist/bin/rness.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
OWN_COMMANDS,
|
|
4
|
-
VERSION,
|
|
5
4
|
catchUp,
|
|
6
5
|
findDelegate,
|
|
7
|
-
reportError,
|
|
8
6
|
run
|
|
9
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-S4NARIQP.js";
|
|
8
|
+
import {
|
|
9
|
+
VERSION,
|
|
10
|
+
reportError
|
|
11
|
+
} from "../chunk-XCO5ZT2H.js";
|
|
10
12
|
|
|
11
13
|
// src/bin/rness.ts
|
|
12
14
|
import { pathToFileURL } from "url";
|
package/dist/bin/rness.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { OWN_COMMANDS, catchUp } from '../core/catch-up.ts'\nimport { findDelegate } from '../core/delegate.ts'\nimport { MIN_NODE_LABEL, isSupportedNode } from '../core/node-version.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_LABEL} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n const skipDelegation =\n OWN_COMMANDS.includes(argv[0] ?? '') ||\n process.env['RNESS_NO_DELEGATE'] === '1'\n // A pin that moved is installed first, and the fresh copy runs the command\n // as its own process (spec 0008 §4).\n const handedOff = await catchUp(argv)\n if (handedOff !== null) return handedOff\n const delegate = skipDelegation\n ? null\n : await findDelegate(process.cwd(), VERSION)\n if (delegate !== null) {\n const broken = (reason: string): Error =>\n new Error(\n `@rness/cli ${delegate.version} pinned in ${delegate.root}/.rness is not installed correctly (${reason}); reinstall in .rness/`\n )\n if (process.env['RNESS_DEBUG'] === '1') {\n process.stderr.write(\n `rness: delegating to @rness/cli ${delegate.version} (${delegate.entry})\\n`\n )\n }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(delegate.entry).href)) as Record<\n string,\n unknown\n >\n } catch (e) {\n throw broken(e instanceof Error ? e.message : String(e))\n }\n if (typeof mod['run'] !== 'function')\n throw broken('dist/index.js does not export run')\n const delegateRun = mod['run'] as (argv: string[]) => Promise<unknown>\n const code = await delegateRun(argv)\n return typeof code === 'number' ? code : 1\n }\n return run(argv)\n}\n\nmain()\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n process.exitCode = reportError(e)\n })\n","/** The runtime floor of the published CLI (ADR 0010): Node 22.17, the line where `fs.glob` is stable. */\nexport const MIN_NODE = { major: 22, minor: 17 } as const\nexport const MIN_NODE_LABEL = `${MIN_NODE.major}.${MIN_NODE.minor}`\n\nfunction component(version: string, index: number): number {\n const n = Number.parseInt(version.split('.')[index] ?? '', 10)\n return Number.isNaN(n) ? -1 : n\n}\n\nexport function nodeMajor(version: string): number {\n return Math.max(component(version, 0), 0)\n}\n\n/** True from `MIN_NODE` on: a newer major, or the same major from its minor. */\nexport function isSupportedNode(version: string): boolean {\n const major = component(version, 0)\n const minor = component(version, 1)\n if (major < 0 || minor < 0) return false\n if (major !== MIN_NODE.major) return major > MIN_NODE.major\n return minor >= MIN_NODE.minor\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { OWN_COMMANDS, catchUp } from '../core/catch-up.ts'\nimport { findDelegate } from '../core/delegate.ts'\nimport { MIN_NODE_LABEL, isSupportedNode } from '../core/node-version.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_LABEL} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n const skipDelegation =\n OWN_COMMANDS.includes(argv[0] ?? '') ||\n process.env['RNESS_NO_DELEGATE'] === '1'\n // A pin that moved is installed first, and the fresh copy runs the command\n // as its own process (spec 0008 §4).\n const handedOff = await catchUp(argv)\n if (handedOff !== null) return handedOff\n const delegate = skipDelegation\n ? null\n : await findDelegate(process.cwd(), VERSION)\n if (delegate !== null) {\n const broken = (reason: string): Error =>\n new Error(\n `@rness/cli ${delegate.version} pinned in ${delegate.root}/.rness is not installed correctly (${reason}); reinstall in .rness/`\n )\n if (process.env['RNESS_DEBUG'] === '1') {\n process.stderr.write(\n `rness: delegating to @rness/cli ${delegate.version} (${delegate.entry})\\n`\n )\n }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(delegate.entry).href)) as Record<\n string,\n unknown\n >\n } catch (e) {\n throw broken(e instanceof Error ? e.message : String(e))\n }\n if (typeof mod['run'] !== 'function')\n throw broken('dist/index.js does not export run')\n const delegateRun = mod['run'] as (argv: string[]) => Promise<unknown>\n const code = await delegateRun(argv)\n return typeof code === 'number' ? code : 1\n }\n return run(argv)\n}\n\nmain()\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n process.exitCode = reportError(e)\n })\n","/** The runtime floor of the published CLI (ADR 0010): Node 22.17, the line where `fs.glob` is stable. */\nexport const MIN_NODE = { major: 22, minor: 17 } as const\nexport const MIN_NODE_LABEL = `${MIN_NODE.major}.${MIN_NODE.minor}`\n\nfunction component(version: string, index: number): number {\n const n = Number.parseInt(version.split('.')[index] ?? '', 10)\n return Number.isNaN(n) ? -1 : n\n}\n\nexport function nodeMajor(version: string): number {\n return Math.max(component(version, 0), 0)\n}\n\n/** True from `MIN_NODE` on: a newer major, or the same major from its minor. */\nexport function isSupportedNode(version: string): boolean {\n const major = component(version, 0)\n const minor = component(version, 1)\n if (major < 0 || minor < 0) return false\n if (major !== MIN_NODE.major) return major > MIN_NODE.major\n return minor >= MIN_NODE.minor\n}\n"],"mappings":";;;;;;;;;;;;;AACA,SAAS,qBAAqB;;;ACAvB,IAAM,WAAW,EAAE,OAAO,IAAI,OAAO,GAAG;AACxC,IAAM,iBAAiB,GAAG,SAAS,KAAK,IAAI,SAAS,KAAK;AAEjE,SAAS,UAAU,SAAiB,OAAuB;AACzD,QAAM,IAAI,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,KAAK,KAAK,IAAI,EAAE;AAC7D,SAAO,OAAO,MAAM,CAAC,IAAI,KAAK;AAChC;AAOO,SAAS,gBAAgB,SAA0B;AACxD,QAAM,QAAQ,UAAU,SAAS,CAAC;AAClC,QAAM,QAAQ,UAAU,SAAS,CAAC;AAClC,MAAI,QAAQ,KAAK,QAAQ,EAAG,QAAO;AACnC,MAAI,UAAU,SAAS,MAAO,QAAO,QAAQ,SAAS;AACtD,SAAO,SAAS,SAAS;AAC3B;;;ADNA,QAAQ,OAAO,GAAG,SAAS,CAAC,MAA6B;AACvD,MAAI,EAAE,SAAS,QAAS,SAAQ,KAAK,CAAC;AACtC,QAAM;AACR,CAAC;AAKD,eAAe,OAAwB;AACrC,MAAI,CAAC,gBAAgB,QAAQ,SAAS,IAAI,GAAG;AAC3C,YAAQ,OAAO;AAAA,MACb,oBAAoB,cAAc,sBAAsB,QAAQ,OAAO;AAAA;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,iBACJ,aAAa,SAAS,KAAK,CAAC,KAAK,EAAE,KACnC,QAAQ,IAAI,mBAAmB,MAAM;AAGvC,QAAM,YAAY,MAAM,QAAQ,IAAI;AACpC,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,WAAW,iBACb,OACA,MAAM,aAAa,QAAQ,IAAI,GAAG,OAAO;AAC7C,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,CAAC,WACd,IAAI;AAAA,MACF,cAAc,SAAS,OAAO,cAAc,SAAS,IAAI,uCAAuC,MAAM;AAAA,IACxG;AACF,QAAI,QAAQ,IAAI,aAAa,MAAM,KAAK;AACtC,cAAQ,OAAO;AAAA,QACb,mCAAmC,SAAS,OAAO,KAAK,SAAS,KAAK;AAAA;AAAA,MACxE;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,YAAO,MAAM,OAAO,cAAc,SAAS,KAAK,EAAE;AAAA,IAIpD,SAAS,GAAG;AACV,YAAM,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACzD;AACA,QAAI,OAAO,IAAI,KAAK,MAAM;AACxB,YAAM,OAAO,mCAAmC;AAClD,UAAM,cAAc,IAAI,KAAK;AAC7B,UAAM,OAAO,MAAM,YAAY,IAAI;AACnC,WAAO,OAAO,SAAS,WAAW,OAAO;AAAA,EAC3C;AACA,SAAO,IAAI,IAAI;AACjB;AAEA,KAAK,EACF,KAAK,CAAC,SAAS;AACd,UAAQ,WAAW;AACrB,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,UAAQ,WAAW,YAAY,CAAC;AAClC,CAAC;","names":[]}
|