kadence 0.4.1 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,260 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [0.6.0] — 2026-09-23
6
+
7
+ **Documentation in the journal, and an honest answer when something goes
8
+ wrong.** Two halves of the same session. Documentation stops being a filename
9
+ someone has to know and becomes an entity an agent is handed — `DOC-N`, revised,
10
+ conflict-aware. And the three places where kadence told an agent something that
11
+ was not true — a claim it had already lost, a failure with no JSON, a flag
12
+ written twice — now answer straight. The second half came out of a contract
13
+ stress audit run against 0.5.0; the report is in
14
+ `docs/research/contract-stress-audit-2026-09.md`.
15
+
16
+ ### ⚠️ Upgrading — everyone updates before anyone runs `compact`
17
+
18
+ `compact` in 0.5.0 and earlier archives the events it can parse and then removes
19
+ the whole month directory, which **deletes `doc.*` events written by 0.6.0**.
20
+ An older kadence reads the journal fine; it just must not compact it. From this
21
+ release on, `compact` leaves alone any month holding an event it cannot read.
22
+ If someone compacted with an old binary, `git status` shows the deleted event
23
+ files — restore them, do not re-run.
24
+
25
+ ### Added — documentation is an entity
26
+
27
+ - **`kadence doc`** — `add`, `edit`, `show`, `list`, `link`. A document is
28
+ `DOC-N`, stored as `doc.written` revisions in the journal rather than as an
29
+ `.md` file beside it (ADR-014, superseding that part of ADR-010). Text comes
30
+ from `--body`, `--file` or `--stdin`; `--file` reads any path and keeps
31
+ nothing (DEC-15).
32
+ - **A revision names its parents.** Two people revising the same version leave a
33
+ conflict that is reported and settled by writing text — never a silent loss.
34
+ `doc edit` with no new text on a conflicted document is refused with
35
+ `conflicting_state`, because otherwise it would keep whichever version ULID
36
+ order happened to show and nobody would have read the other.
37
+ - **Agents reach documentation without a search term.** `task show --json`
38
+ carries `documentation[]` (label, title, bytes, `updatedAt`), `prime` names the
39
+ documentation of the work you hold, and `doc list --json` carries no bodies.
40
+ One body arrives only when you ask for it with `doc show`.
41
+ - **A body past 16 KiB is written with a warning, not refused.** Agents read long
42
+ inputs measurably worse; splitting is the author's call, not ours.
43
+ - **`KADENCE_ACTOR`** names the claimant (DEC-16). Without it, an agent in a
44
+ linked worktree claims as `email#<worktree>`. A person owns what their agents
45
+ hold; an agent owns only its own.
46
+ - **`task claim` reports what actually happened** — `claim: claimed |
47
+ already_yours | contested`, read back out of the journal after the write.
48
+ Additive to `kadence/v1`.
49
+
50
+ ### Changed
51
+
52
+ - **`prime` puts contested claims first in *Yours*,** each carrying `claimedBy`
53
+ and `contestedBy`, so an agent holding a task it no longer owns sees that
54
+ before it starts working. When every claim is the person's own agents, it says
55
+ so instead: *N of your agents collided — keep one, release the rest.*
56
+ - **`task doc` stays** for linking files that already exist; new writing goes to
57
+ `kadence doc`.
58
+ - **A repeated single-value flag keeps its last value** (DEC-18). Only
59
+ `--label`, `--add-label`, `--remove-label`, `--rejected` and `--doc`
60
+ accumulate. `--title a --title b` had been storing both and reporting success.
61
+
62
+ ### Fixed — the contract, where it was quiet
63
+
64
+ - **A parser failure answers in JSON.** An unknown flag, a missing value or an
65
+ extra argument is thrown by cac before any handler runs, and it used to reach
66
+ stderr as a bare sentence with nothing on stdout — the one failure `--json`
67
+ did not cover. It now goes through `failure()`: `invalid_argument` with
68
+ `received` and `allowed`, exit 2.
69
+ - **An unknown command no longer exits 0 with both streams empty,** and a bare
70
+ `kadence` prints help instead of nothing. An exception that is not a cac error
71
+ prints its stack and exits 1, rather than being mislabelled as usage.
72
+ - **`compact` no longer deletes events it cannot parse** along with their month
73
+ directory — see Upgrading.
74
+ - **`task doc` recorded a URL as the mangled path `https:/…`** and `task doc add`
75
+ created a directory named `https:` (KAD-33).
76
+ - **`--body -` was read as a missing value and `--body 007` became `7`.**
77
+ `--stdin` is its own flag now, and text flags are read raw from argv. Two text
78
+ sources at once are refused rather than one winning silently.
79
+ - **`doc link` returned a partial document;** it returns the full shape, pinned
80
+ in the schema contract.
81
+
82
+ ### Measured
83
+
84
+ - `claim` re-reads the journal after writing: ~121 ms median at 400 events,
85
+ against ~105 ms for a plain read. An agent without `KADENCE_ACTOR` pays one
86
+ git spawn (~10 ms) in `ready`, `prime` and `claim` to detect a linked
87
+ worktree.
88
+ - `ready` and `prime` now sit at the edge of the 200 ms budget as this
89
+ repository's own journal grows. Recorded as a note, not yet as a fix.
90
+
91
+ ## [0.5.0] — 2026-09-16
92
+
93
+ **The second author.** kadence was built for a team, and until now its first
94
+ run spoke to one person with a sprint. This release is the path the second
95
+ person walks: their agent learns to write the why, a machine without kadence
96
+ gets an install hint instead of an error, and the first screens talk about the
97
+ work and its decisions rather than points. Reports are still here; they are
98
+ just no longer the first thing anyone meets.
99
+
100
+ ### Added — the teammate path
101
+
102
+ - **The section `init` writes into `AGENTS.md` and `CLAUDE.md` teaches writes,
103
+ not only reads.** `task claim`, `note "…" --task`, and `decision add "…" --why`
104
+ sit beside the read commands, plus one line for an agent on a machine where
105
+ `kadence` is not on PATH: ask the human to install it; `npx` needs the network
106
+ and that is their call. Still 23 lines and 1.2 KB, under a test of 25 lines and
107
+ 2 KB; an older section is replaced in place by its version marker.
108
+ - **The `SessionStart` hook survives a machine without kadence.** It runs
109
+ `kadence prime` when the binary is there and otherwise prints one line asking
110
+ the human to install it, exiting 0 (DEC-12: no `npx`, because a hook written by
111
+ `init` must not download code on a teammate's machine). `init --hooks` upgrades
112
+ the old `kadence prime` hook in place instead of adding a second.
113
+ - **`.kadence/README.md` leads to decisions and teammates.** `decision list` and
114
+ `decision add` replace `sprint status` among the top commands, and a new
115
+ "Adding a teammate" section covers install, one `user.email` per person and
116
+ `KADENCE_SOURCE=agent`. Existing READMEs are still never overwritten.
117
+ - **README: the first ten minutes, "Adding a teammate" and "Removing kadence"** —
118
+ the last one lists everything `init` touches, so leaving is a table, not a
119
+ guess. Sprints, reports and exports moved to `docs/reports.md`.
120
+
121
+ ### Changed — the first run speaks about the work
122
+
123
+ - **`init`** suggests a first task *and* a first decision, names what to commit
124
+ so a teammate's agent finds it, and mentions `--hooks` when `.claude/` exists.
125
+ - **`prime`** no longer opens with "No active sprint." when there is none; with
126
+ no decision in force it shows one line on how to record one. `--json` unchanged.
127
+ - **`task add` without `--estimate`** says nothing outside a sprint; inside one it
128
+ names the sprint instead of velocity. `sprint add` says the same.
129
+ - **`kadence --help`** lists commands in the order a session meets them: `init,
130
+ prime, ready, task, decision, note, board, ui, schema`, then planning, reports
131
+ and maintenance.
132
+ - **The TUI header** without a sprint reads `N open · M ready · K decisions in
133
+ force`; points appear only when something is estimated.
134
+ - **`report --list`** puts `attention` first and groups burndown, velocity and
135
+ workload under "Sprint and team".
136
+
137
+ ### Fixed — the contract
138
+
139
+ - **`schema --json` lists every shipped command.** 21 entries were missing,
140
+ among them `sprint add/edit/start/list/burndown`, `task parent/unblock/cancel/delete`,
141
+ `template`, `completion` and `ui` — additive within `kadence/v1`. A test now
142
+ compares the binary's own commands and actions against the contract and fails
143
+ on any gap. Unknown `decision` actions now return `allowed`, and `task` lists
144
+ `doc` in it.
145
+
146
+ ### Tooling
147
+
148
+ - **`scripts/north-star.mjs`** counts repositories with two authors fourteen days
149
+ after their first event — `--local` for a checkout, `--search` through `gh` for
150
+ public ones — and appends a weekly row to `docs/research/north-star-log.md`.
151
+ A maintainer script: the product itself still opens no socket. First row: 0,
152
+ with the reason GitHub code search has not indexed even this repository.
153
+
154
+ ---
155
+
156
+ The command reference stops being prose. And the first two bugs found by using
157
+ the product on itself.
158
+
159
+ ### Added
160
+
161
+ - **`kadence report` is the whole catalogue.** `report burndown`, `report
162
+ velocity` and `report workload` join `flow`, `cfd` and `attention`, and
163
+ `report --list` names all six with what each one answers.
164
+
165
+ The folds were already here — the burndown under `sprint`, the workload
166
+ inside `stats` — so an agent reading `schema --json` could not find them and
167
+ `kadence report` was not the catalogue it looked like. `report burndown`
168
+ calls the same function `sprint burndown` does, resolved in one place, so the
169
+ two cannot drift. `report velocity` is new arithmetic over `sprintReport`,
170
+ and it answers with a range rather than an average (DEC-9): the spread
171
+ between sprints is the forecast, and a series shorter than four sprints says
172
+ so. `report workload` counts open tasks, points, work in progress and blocked
173
+ work per owner, with a row for unassigned work — no hours, no capacity, since
174
+ the journal has neither.
175
+
176
+ `--since` on a report that has no window, or `--sprint` on anything but the
177
+ burndown, is now an error rather than a silently ignored flag (DEC-10).
178
+
179
+ - **`kadence report <name> --html`** — a report as one self-contained page, with
180
+ charts. `flow` gets a percentile dot plot, a created-vs-finished column chart
181
+ and an aging-work chart with the p85 cycle time drawn as a reference line;
182
+ `cfd` gets a stacked area chart with the bands named where they are wide
183
+ enough; `attention` gets the idle days against the threshold. `--file` puts it
184
+ where you want it, and with `--json` the response is the path, not the report.
185
+
186
+ The charts are hand-written inline SVG. Every chart library is a script tag,
187
+ and the page's one promise is the one the board export already makes: it opens
188
+ from disk and asks the network for nothing — asserted structurally, down to
189
+ `url(` in the stylesheet and the `xmlns` an inline `<svg>` does not need.
190
+ Measured at 0.1 ms and 14 KB for the flow page, 1.7 ms and 301 KB for a
191
+ two-year cumulative flow diagram. Every chart is followed by the rows it was
192
+ drawn from: three of the eight categorical colours sit below 3:1 against
193
+ white, and the rule that buys them is that colour is never the only channel.
194
+
195
+ Reasoning in DEC-7 (a page per report rather than a Reports section inside the
196
+ board export — a report is a question with a window, and the board export has
197
+ none) and DEC-8 (the charts).
198
+
199
+ - **`kadence schema --json` and every `--help` now have a machine-readable
200
+ sibling.** `npm run reference` writes `dist/reference.json`: every command,
201
+ its usage line, its flags with their descriptions, its examples, and the
202
+ whole agent contract, read out of the binary rather than written about it.
203
+ The release workflow attaches it to the GitHub release of each tag.
204
+
205
+ This exists because the hand-typed CLI page on the site described 0.3 for the
206
+ whole of 0.4 — nine commands and two dozen flags shipped without it noticing,
207
+ and the agents page named ten of the fifteen error codes. A paragraph has no
208
+ test. A test now reads `src/cli/commands/` and fails when a command file has
209
+ no help behind it, which is the only way that gap stays closed.
210
+
211
+ The generator ships in the package rather than its output: measured at 1.9 KB
212
+ packed against 6.2 KB, and 4.9 KB unpacked against 39.7 KB, for the same
213
+ result. Nothing in the data is unavailable from the CLI itself.
214
+
215
+ - **`scripts/kadence.mjs`** — runs the build in this working tree, rebuilding
216
+ when `src/` is newer. For working on kadence with kadence, which is now how
217
+ this repository is run; `CLAUDE.md` says what that means in practice.
218
+
219
+ ### Fixed
220
+
221
+ - **`burndown.finalRemaining` was always `null`.** Both branches of
222
+ `sprint.status === 'closed' ? null : null` read the same, so the one number
223
+ the field exists for — what a closed sprint did not finish — was never in the
224
+ response, including in `sprint burndown --json`. It now carries the points
225
+ left on the sprint's last day.
226
+
227
+ - **A repeated flag crashed `decision add`.** `--rejected A --rejected B` threw
228
+ `o.rejected.trim is not a function`: cac hands a single flag back as a string
229
+ and a repeat as an array, and only `--doc` was normalised for it. The four
230
+ single-value flags went into `.trim()` as arrays.
231
+
232
+ Repeats now mean what each flag means. A second `--why`, `--task` or
233
+ `--supersedes` is a correction, so the last wins; a second `--rejected` is a
234
+ second alternative that was turned down — which is what a decision record is
235
+ for — so both are kept, joined rather than stored as an array because
236
+ `rejected` is a string in `kadence/v1` and the contract only ever gains
237
+ fields.
238
+
239
+ Found by recording a real decision about this repository with two rejected
240
+ options, with 898 tests green. The tests for it go through the built binary,
241
+ because calling the command directly is exactly the path that could not see
242
+ it.
243
+
244
+ ### Notes
245
+
246
+ Deleting several tasks by `KAD-N` in one loop removes the wrong ones. Labels
247
+ are derived while folding (I7), so removing `KAD-1` renumbers everything after
248
+ it and the next label in the list now belongs to a different task. Working as
249
+ designed, and a sharp edge: delete by ULID, or one at a time. Recorded as a
250
+ note in this repository's own journal rather than fixed, because the fix is not
251
+ obvious — warning on a bulk delete of labels would fire on the common case too.
252
+
253
+ A board-wide Definition of Done is engineering-shaped. `board config --dod`
254
+ copies its criteria into every new task, so "typecheck clean" landed on the
255
+ Probe B interview tasks, where it means nothing, and there is no `task ac
256
+ remove` to take it off. Noted, not yet answered.
257
+
3
258
  ## [0.4.1] — 2026-09-13
4
259
 
5
260
  `0.4.0` was tagged and never published: these three were found by using it
package/README.md CHANGED
@@ -53,10 +53,11 @@ That is the whole state of a piece of work, in one call, with no server to ask
53
53
  and no context to rebuild. A human reads it in `kadence task show`. An AI agent
54
54
  reads the same thing as JSON.
55
55
 
56
- **And it stays one call.** That answer is 948 bytes whether the project holds ten
57
- tasks or a thousand — while the journal behind it grows from 5 KB to 528 KB. The
58
- cost of asking does not grow with the history that makes the answer worth having.
59
- [Measured](docs/research/probe-c-agent-cost.md).
56
+ **And it stays one call.** That answer stays under a kilobyte whether the project
57
+ holds ten tasks or a thousand — while the journal behind it grows from 5 KB to
58
+ 528 KB. The cost of asking does not grow with the history that makes the answer
59
+ worth having. [Measured](docs/research/probe-c-agent-cost.md) at 948 bytes in
60
+ 0.2; 982 bytes at 0.4, after claims and acceptance criteria joined every record.
60
61
 
61
62
  ## Why events and not files
62
63
 
@@ -76,7 +77,7 @@ journal is append-only, one file per event.
76
77
  keeps every step, so «how did we get here» has an answer.
77
78
 
78
79
  State is still there when you want it — it is folded from the journal on read,
79
- which is why the board can never drift from the journal. No one maintains a
80
+ which is why the board cannot drift from the journal. No one maintains a
80
81
  column by hand, so no column can be stale in the way a task file can.
81
82
 
82
83
  **What that does not buy you.** A journal records what was written to it. If a
@@ -107,22 +108,53 @@ Full data: [probe-a-results.md](docs/research/probe-a-results.md).
107
108
 
108
109
  ## In practice
109
110
 
111
+ **The first ten minutes, for the person who owns `CLAUDE.md`:**
112
+
110
113
  ```bash
111
- kadence init
114
+ kadence init --hooks # .kadence/, a short section in AGENTS.md and CLAUDE.md,
115
+ # and a Claude Code hook that runs `kadence prime` at session start
116
+ kadence task add "Fix login" --type bug --priority high
117
+ kadence decision add "Keep sessions in Redis" \
118
+ --why "Revocation must be instant" --rejected "JWT: cannot revoke before expiry"
119
+ ```
120
+
121
+ Open a new agent session. The hook runs `kadence prime`, and the agent starts
122
+ knowing what is open, what is ready and **DEC-1 with its reason** — ask it how
123
+ sessions should be stored and it answers from the journal, not from a guess.
112
124
 
113
- kadence sprint create "Sprint 14"
114
- kadence task add "Fix login" -d "Broken since 2.3" --type bug --priority high --estimate 3
115
- kadence task ac add KAD-1 "tests green"
116
- kadence task comment KAD-1 "Session cookie is fine — the redirect drops it."
117
- kadence task move KAD-1 done
118
- kadence sprint close
125
+ ```bash
126
+ git add .kadence AGENTS.md CLAUDE.md .claude/settings.json .gitignore
127
+ git commit -m "Keep the team's work next to the code"
119
128
  ```
120
129
 
130
+ kadence never commits for you. Once that commit is pushed, the journal is the
131
+ team's, not yours.
132
+
133
+ ### Adding a teammate
134
+
135
+ 1. **They install it:** `npm install -g kadence` (Node 20 or newer). Nothing is
136
+ configured per person.
137
+ 2. **They pull.** Their agent reads the same section in `CLAUDE.md` or `AGENTS.md`
138
+ and, through the hook, runs `kadence prime` in its first session. On a machine
139
+ where kadence is not installed yet, the hook prints one line asking for the
140
+ install instead of failing.
141
+ 3. **One identity per person.** Authorship is `git config user.email`. The same
142
+ person on two machines with two addresses reads as two people — set the same
143
+ address everywhere.
144
+ 4. **Agents say so.** Put `KADENCE_SOURCE=agent` in the agent's environment; its
145
+ writes then carry `[agent]` next to the same email, so a person and their agent
146
+ stay distinguishable.
147
+
148
+ What you should see afterwards: `kadence task show KAD-1` lists their comment,
149
+ note or move with their address. That second author is the moment the journal
150
+ starts doing its job.
151
+
121
152
  **When several people — or several agents — work the same board:**
122
153
 
123
154
  ```bash
124
155
  kadence ready # open, unblocked, nobody else's
125
156
  kadence task claim # take the top of that list, in one step
157
+ kadence note "Redirect drops the cookie, not the session" --task KAD-1
126
158
  kadence task release KAD-1
127
159
  ```
128
160
 
@@ -131,38 +163,21 @@ either pushes; the merge keeps both claims and the task reads `contested` with
131
163
  both names. Refusing the second one would make the owner depend on which branch
132
164
  merged first, and that is the property the whole design rests on.
133
165
 
134
- **Grouping, and the evidence behind "done":**
135
-
136
- ```bash
137
- kadence milestone create "1.0" --due 2026-12-01
138
- kadence milestone add KAD-1 --milestone 1.0
139
- kadence board config --dod "tests green,docs updated" # every new task starts with these
140
- kadence task ac check KAD-1 1
141
- ```
142
-
143
- Moving a task to `done` with unchecked criteria **warns and carries on**. The
144
- checklist is evidence, not a gate: what `done` costs is the team's call, not the
145
- tool's.
146
-
147
- **A snapshot somebody can open, without running anything:**
166
+ **The board, when you want to look at it:**
148
167
 
149
- ```bash
150
- kadence board export --html # one self-contained file: no server, no network
151
- kadence board export --md --readme
152
168
  ```
169
+ $ kadence ui
153
170
 
154
- **When someone asks how long things take** — the answer is a fold over the same
155
- journal, in the Kanban Guide's own terms:
156
-
157
- ```bash
158
- kadence board config --started doing # the column cycle time counts from, if it is not in_progress
159
- kadence report flow # p50 / p85 / p95 in calendar days, WIP, aging work, blocked days
160
- kadence report cfd # tasks per column, per day
171
+ kadence 6 open · 2 ready · 1 decision in force
172
+ +- backlog (2) -------++- in_progress (1) --++- in_review (1) ----++- done (3) ---------+
173
+ | ^# KAD-1 Auth epic || . KAD-4 Tokens @dev||!! KAD-7 Crash [] || v KAD-2 Export |
174
+ | * KAD-3 Login form || || || v KAD-5 Docs |
175
+ +---------------------++--------------------++--------------------++--------------------+
176
+ arrows move enter details m status a assign e edit s sprint R ready b branch q quit
161
177
  ```
162
178
 
163
- No averages, on purpose. Every line names the window and the column it measured
164
- from. Velocity is not the pitch here and neither is cycle time; they are what the
165
- journal happens to know.
179
+ Keyboard, mouse, drag between columns, every field editable in place. It calls
180
+ the same commands the CLI does, so the two can never disagree.
166
181
 
167
182
  **And what the branch you are on is actually about:**
168
183
 
@@ -175,38 +190,30 @@ history and is read when you ask. It narrows the answer between three and
175
190
  twenty times, [measured](docs/research/branch-context-2026-09.md) on real board
176
191
  sizes.
177
192
 
178
- **The board, when you want to look at it:**
179
-
180
- ```
181
- $ kadence ui
182
-
183
- kadence Sprint 14 9 tasks, 28 points
184
- +- backlog (2) -------++- in_progress (1) --++- in_review (1) ----++- done (3) ---------+
185
- | ^# KAD-1 Auth epic || . KAD-4 Tokens @dev||!! KAD-7 Crash [] || v KAD-2 Export |
186
- | * KAD-3 Login form || || || v KAD-5 Docs |
187
- +---------------------++--------------------++--------------------++--------------------+
188
- arrows move enter details m status a assign e edit s sprint R ready b branch q quit
189
- ```
190
-
191
- Keyboard, mouse, drag between columns, every field editable in place. It calls
192
- the same commands the CLI does, so the two can never disagree.
193
+ ### Also in the box
193
194
 
194
- **And because the journal has the timestamps, the cost comes out of it for free:**
195
+ Sprints (`sprint create/close`, with points and hours derived from moves),
196
+ milestones, acceptance criteria and a definition of done, templates, custom
197
+ columns, reports folded from the same journal (`report flow`, `cfd`,
198
+ `attention`; burndown, velocity and workload are in the repository and not yet
199
+ on npm), a self-contained HTML or Markdown export, `compact` for long journals,
200
+ and shell completion. None of it is required, and none of it is the point —
201
+ it is what the journal happens to know. Commands and caveats:
202
+ [docs/reports.md](docs/reports.md), and `--help` on each command.
195
203
 
196
- ```
197
- $ kadence sprint close
204
+ ### Removing kadence
198
205
 
199
- Sprint "Sprint 14" closed.
206
+ Everything `init` touched, so you can undo it by hand:
200
207
 
201
- Velocity: 23 of 28 points
202
- Actual: 37h — 1.6h per point
203
-
204
- Carried over (2):
205
- · KAD-12 Auth refactor
206
- ```
208
+ | What | Where |
209
+ |---|---|
210
+ | The journal | `.kadence/` — yours to keep or delete; kadence never deletes it |
211
+ | The agent section | between `<!-- kadence:begin -->` and `<!-- kadence:end -->` in `AGENTS.md` and `CLAUDE.md` |
212
+ | The hook (only with `--hooks`) | the `SessionStart` entry that runs `kadence prime` in `.claude/settings.json` |
213
+ | The cache entry | the `.kadence/state.json` line in `.gitignore` |
207
214
 
208
- Nobody fills in a form. Nobody can forget to update it. The number is derived
209
- from state changes the team already made.
215
+ Then `npm uninstall -g kadence`. Nothing lives outside the repository and your
216
+ global `node_modules`.
210
217
 
211
218
  ---
212
219
 
@@ -218,8 +225,8 @@ Files first. Every command speaks `--json`, every response carries
218
225
  Start a session with one command:
219
226
 
220
227
  ```bash
221
- kadence prime # active sprint, your work, what is ready, decisions in force
222
- kadence ready --json # five fields per task, not the whole record
228
+ kadence prime # active sprint, your work, what is ready, decisions in force, recent notes
229
+ kadence ready --json # seven fields per task, not the whole record
223
230
  ```
224
231
 
225
232
  `prime` is held to forty lines and three kilobytes by a test, because it is paid
@@ -248,16 +255,19 @@ A failure carries `error.code` and, where the valid set is knowable, `allowed`
248
255
  which matters most for statuses, because they are configured per project and no
249
256
  documentation can tell an agent what yours are.
250
257
 
251
- An MCP wrapper stays on the roadmap as an **optional package**: it costs about
252
- 700 tokens a session over the CLI path — [we measured it](docs/research/probe-c-agent-cost.md),
253
- and it is not the saving the industry benchmarks suggest — but it would be a
254
- second way to say the same thing, and it would not work for agents that have no
255
- MCP client at all.
258
+ There is no MCP wrapper, and one gets built only as an **optional package**, when
259
+ someone who cannot run a CLI asks for it: it costs about 700 tokens a session
260
+ over the CLI path — [we measured it](docs/research/probe-c-agent-cost.md), and it
261
+ is not the saving the industry benchmarks suggest — it would be a second way to
262
+ say the same thing, and it would not work for agents that have no MCP client at
263
+ all.
256
264
 
257
- Ask for only what you need — a board of a thousand tasks is 803 KB in full, and
258
- a tenth of that with the fields an agent actually reads:
265
+ Ask for only what you need — a board of a thousand tasks is 855 KB in full,
266
+ 275 KB with `--summary`, and 104 KB with the three fields an agent actually
267
+ reads:
259
268
 
260
269
  ```bash
270
+ kadence board --json --summary
261
271
  kadence board --json --fields label,status,assignee
262
272
  ```
263
273
 
@@ -275,8 +285,30 @@ one; that is how a reversed decision keeps looking authoritative.
275
285
  `decision list` returns what is still in force, `--all` adds the history, and
276
286
  `task show --json` carries the decisions made about that task.
277
287
 
278
- Documents stay plain markdown — `kadence task doc KAD-1 docs/design.md` records
279
- only the link, which is the part git cannot express.
288
+ Something learned that was never a choice is a note, not a decision — no `--why`,
289
+ no number, and `prime` shows the latest:
290
+
291
+ ```bash
292
+ kadence note "The staging clock runs 40 s behind" --task KAD-1
293
+ ```
294
+
295
+ **Documentation lives in the journal too.** How something works now, revised as
296
+ it changes — an entity, `DOC-N`, not a filename an agent has to guess:
297
+
298
+ ```bash
299
+ kadence doc add "How auth works" --file notes/auth.md --task KAD-1
300
+ kadence doc show DOC-1 --json
301
+ ```
302
+
303
+ A revision names the revisions it was written on top of, so two people editing
304
+ the same version leave a conflict that is reported and settled by writing text,
305
+ never a silent overwrite. Agents are handed it without searching: `task show`
306
+ carries `documentation[]` and `prime` names the documentation of the work you
307
+ hold — both without bodies, so the body arrives only when asked for.
308
+
309
+ A markdown file that already exists is still linked, not swallowed:
310
+ `kadence task doc add KAD-1 docs/design.md` records the link, which is the part
311
+ git cannot express.
280
312
 
281
313
  Bulk works everywhere and is all or nothing: `kadence task move KAD-1,KAD-2 done`
282
314
  either moves both or changes nothing. A typo does not leave half a board.
@@ -302,24 +334,35 @@ true.
302
334
 
303
335
  **Verified.** The merge thesis, on real git branches. Performance and size, by
304
336
  tests that fail if they regress. That the conflict problem exists in the wild —
305
- measured, not assumed. 898 tests, including an end-to-end run through the
306
- installed binary.
337
+ measured, not assumed. 1060 tests in the repository today, including an
338
+ end-to-end run through the installed binary.
307
339
 
308
340
  **Not verified.** That teams and their AI agents actually lose enough context to want
309
341
  this. The bet rests on reasoning and on the industry naming the problem out
310
- loud — not on our own users. That research is
311
- [designed](docs/research/interview-script.md) and not yet run.
342
+ loud — not on our own users. That research, Probe B, is
343
+ [designed](docs/research/interview-script.md) and not yet run: as of
344
+ 2026-09-16, [zero conversations](docs/research/probe-b-results.md) and no
345
+ external users. [The strategy](docs/product/strategy.md) says what happens next
346
+ and on which dates.
347
+
348
+ **Not built, on purpose.** An MCP package — only if someone who cannot run a CLI
349
+ asks for it, not as an inevitability.
312
350
 
313
- **On the roadmap, not shipped.** The optional MCP package, kept as a response to
314
- someone who cannot use the CLI rather than as an inevitability.
351
+ **In the repository, not yet released.** `report burndown`, `report velocity`,
352
+ `report workload`, `report --list` and `report <name> --html`. `npm install`
353
+ gives you 0.4.1 without them.
315
354
 
316
355
  `kadence context <task>` was dropped: we measured what `task show --json` already
317
- returns and it is the whole history of one piece of work, 948 bytes, constant.
356
+ returns and it is the whole history of one piece of work, under a kilobyte,
357
+ constant.
318
358
  The only thing left to add was a different format, and nobody has asked for one.
319
359
 
320
360
  **Known limits.** Conflicts are real but rare: roughly one merge in two hundred.
321
361
  Terminal interaction is covered by manual testing; only the key router is
322
- unit-tested.
362
+ unit-tested. Deleting several tasks by `KAD-N` in one loop removes the wrong
363
+ ones, because labels are derived and renumber as earlier tasks go — delete by
364
+ ULID, or one at a time. There is no `task ac remove`, so a board-wide Definition
365
+ of Done lands on every new task unless it is added with `--no-dod`.
323
366
 
324
367
  ---
325
368
 
@@ -345,8 +388,9 @@ revisit it: [docs/decisions/](docs/decisions/).
345
388
 
346
389
  ```bash
347
390
  npm install
348
- npm test # 898 tests
349
- npm run build # 35 KB bundle
391
+ npm test # 1060 tests; builds dist/cli.js first
392
+ npm run typecheck
393
+ npm run build # one 111 KB bundle, blessed kept external (82 KB at 0.4.1)
350
394
  ```
351
395
 
352
396
  `CLAUDE.md` documents the invariants, the boundaries, and the decisions that
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import{q as G}from"./chunk-CR5YON2J.js";import S from"blessed";var c={border:"gray",borderFocus:"cyan",headerFg:"white",headerBg:"blue",selectedFg:"black",selectedBg:"cyan",dim:"gray",hint:"gray",warn:"yellow",danger:"red"},he={backlog:"gray",todo:"white",in_progress:"blue",doing:"blue",blocked:"red",in_review:"magenta",review:"magenta",done:"green",shipped:"green"};function ne(n){return he[n]??"white"}var pe={urgent:"\u203C",high:"\u2191",normal:" ",low:"\u2193"},me={urgent:"red",high:"yellow",normal:"white",low:"gray"},ye={bug:"\u2716",story:"\u25C6",epic:"\u2B22",task:"\xB7"};function k(n,s){return`{${s}-fg}${n}{/}`}function W(n,s){let d=k(pe[n.priority],me[n.priority]),p=k(ye[n.type]??"\xB7","gray"),h=k(n.label,"cyan"),g=[];n.blockedBy.length>0&&g.push(k("\u2298","red")),n.contestedBy.length>0?g.push(k("\u2691","magenta")):n.claimedBy!==null&&g.push(k("\u2713","green"));let E=n.criteria.filter(O=>!O.checked).length;if(E>0?g.push(k(`${n.criteria.length-E}/${n.criteria.length}`,"yellow")):n.criteria.length>0&&g.push(k("\u2611","green")),n.comments.length>0&&g.push(k("\u{1F4AC}","gray")),n.due!==null){let O=n.due<new Date().toISOString().slice(0,10);g.push(k(O?"\u23F0":"\u{1F4C5}",O?"red":"gray"))}let C=[n.assignee!==null?k(`@${n.assignee.split("@")[0]}`,"gray"):"",n.estimate!==null?k(String(n.estimate),"yellow"):"",g.join("")].filter(O=>O.length>0).join(" "),m=`${Y(d)}${Y(p)} ${Y(h)} `,b=C.length>0?` ${Y(C)}`:"",T=Math.max(4,s-m.length-b.length),F=[...n.title],q=F.length>T?`${F.slice(0,T-1).join("")}\u2026`:n.title;return`${d}${p} ${h} ${q}${C.length>0?` ${C}`:""}`}function z(n,s){return s?`{cyan-bg}{black-fg}${Y(n)}{/}`:` ${n}`}function J(n,s,d,p=12){let h=`${n.padEnd(p)} ${s}`;return d?`{cyan-bg}{black-fg}\u25B8 ${h}{/}`:` ${h}`}function Y(n){return n.replace(/\{[^}]*\}/g,"")}var re=["\u2190\u2192\u2191\u2193 move","enter details","[ ] shift","m status","a assign","c comment","e edit","n new","s sprint","/ filter","R ready","b branch","M milestone","C claim","? help","q quit (Ctrl-C forces)"].join(" ");function se(n){let s=[],d=!1;function p(){d=!0,setImmediate(()=>{d=!1})}return{dispatch(h){if(d)return;let g=s[s.length-1];g!==void 0?g(h):n(h)},push(h){s.push(h),p();let g=!1;return()=>{if(g)return;g=!0;let E=s.lastIndexOf(h);E!==-1&&s.splice(E,1),p()}},isDialogOpen:()=>s.length>0,depth:()=>s.length}}function oe(n){if(n.ch==="")return!1;let s=n.ch.charCodeAt(0);return s<32||s===127}var be=["up","down","pageup","pagedown","home","end"],ie=["escape","q"];function Q(n){return be.includes(n.name)}function le(n){return ie.includes(n.name)||ie.includes(n.ch)}function _(n,s,d){return d===0?0:(n+s+d)%d}var ae="cancelled",we="done";function ve(n){let s=[`${n.open} open`,`${n.ready} ready`,`${n.decisions} ${n.decisions===1?"decision":"decisions"} in force`,...n.points===null?[]:[`${n.points} points`]];return`kadence ${n.sprint===null?"":`${n.sprint} `}${s.join(" \xB7 ")}${n.filterNote}`}function Ie(n){let s=S.screen({smartCSR:!0,title:"kadence",fullUnicode:!0,mouse:!0}),{state:d}=n.reload(),p=n.branchEventIds(),h="",g=!1,E=!1,C="",m=[],b=0,T=se(t=>ge(t));function F(t=0){try{s.destroy()}catch{}process.exit(t)}process.on("SIGINT",()=>F(0)),process.on("SIGTERM",()=>F(0)),s.program.on("keypress",(t,r)=>{let i={ch:t??"",name:r?.name??""};(i.name==="C-c"||i.ch==="")&&F(0),!(oe(i)&&i.name!=="enter"&&i.name!=="escape")&&T.dispatch(i)});let q=S.box({parent:s,top:0,height:1,width:"100%",tags:!0,style:{fg:c.headerFg,bg:c.headerBg}}),O=S.box({parent:s,bottom:0,height:1,width:"100%",tags:!0,content:` ${re}`,style:{fg:c.hint}}),V=S.box({parent:s,bottom:1,height:1,width:"100%",tags:!0,style:{fg:c.warn}});function w(t,r=c.warn){V.setContent(` ${t}`),V.style.fg=r,s.render()}function A(){let t=d.statuses.filter(i=>i!==ae),r=d.orphanStatuses.filter(i=>i!==ae);return[...t,...r]}function de(t){let r=h.toLowerCase(),i=g?new Set(G(d.tasks,{viewer:n.actor,statuses:d.statuses,started:d.started}).map(a=>a.id)):null,e=E&&!("reason"in p)?p:null,o=e===null?null:a=>e.ids.has(a.id)||a.history.some(l=>e.ids.has(l.id)),u=C===""?null:d.milestones.find(a=>a.label===C)?.id??null;return d.tasks.filter(a=>a.status===t&&(i===null||i.has(a.id))&&(o===null||o(a))&&(u===null||a.milestone===u)&&(r===""||a.title.toLowerCase().includes(r)||(a.assignee??"").toLowerCase().includes(r)||a.labels.some(l=>l.toLowerCase().includes(r))))}function X(){for(let i of m)i.box.destroy();m=[];let t=A(),r=Math.max(Math.floor(100/Math.max(t.length,1)),12);t.forEach((i,e)=>{let o=S.box({parent:s,top:1,left:`${e*r}%`,width:`${r}%`,bottom:2,label:` ${i} `,border:{type:"line"},style:{border:{fg:c.border},label:{fg:ne(i)}}}),u=S.list({parent:o,top:0,left:0,right:0,bottom:0,keys:!1,mouse:!1,interactive:!1,tags:!0,scrollable:!0,style:{selected:{fg:c.selectedFg,bg:c.selectedBg},item:{fg:"white"}}});m.push({status:i,box:o,list:u,tasks:[],cursor:0})})}function y(t=!1){t&&(d=n.reload().state,p=n.branchEventIds()),m.length!==A().length&&X();let r=0,i=0,e=!1;m.forEach((l,N)=>{l.tasks=de(l.status),l.status!==we&&(r+=l.tasks.length,i+=l.tasks.reduce((R,M)=>R+(M.estimate??0),0)),l.tasks.some(R=>R.estimate!==null)&&(e=!0);let U=l.box.width-4;l.cursor=Math.min(l.cursor,Math.max(0,l.tasks.length-1)),l.list.setItems(l.tasks.map((R,M)=>z(W(R,U),N===b&&M===l.cursor)));let L=l.tasks.reduce((R,M)=>R+(M.estimate??0),0);l.box.setLabel(` ${l.status} (${l.tasks.length}${L>0?`, ${L}`:""}) `),l.box.style.border.fg=N===b?c.borderFocus:c.border});let o=d.sprints.find(l=>l.status==="active"),u=(h===""?"":` filter: "${h}"`)+(g?" ready only":"")+(E&&!("reason"in p)?` branch: ${p.name}`:"")+(C===""?"":` milestone: ${C}`),a=G(d.tasks,{viewer:n.actor,statuses:d.statuses,started:d.started}).length;q.setContent(` ${ve({sprint:o===void 0?null:o.name,open:r,ready:a,decisions:d.decisions.filter(l=>l.supersededBy===null).length,points:e?i:null,filterNote:u})}`),d.cycles.length>0&&w(`${d.cycles.length} dependency cycle(s) \u2014 see kadence task list`,c.danger),s.render()}function I(){let t=m[b];return t?.tasks[t.cursor]}function Z(){m.forEach((t,r)=>{let i=t.box.width-4;t.list.setItems(t.tasks.map((e,o)=>z(W(e,i),r===b&&o===t.cursor))),t.box.style.border.fg=r===b?c.borderFocus:c.border}),s.render()}function x(t){t!==null?w(t,c.warn):w(""),y(!0)}function K(t,r,i){let e=T.push(()=>{}),o=S.prompt({parent:s,top:"center",left:"center",width:"60%",height:7,border:{type:"line"},style:{border:{fg:c.borderFocus}},keys:!0,mouse:!0});o.input(t,r,(u,a)=>{o.destroy(),e(),s.render(),typeof a=="string"&&i(a.trim())})}function ue(t){let r=S.box({parent:s,top:"center",left:"center",width:"75%",height:"80%",border:{type:"line"},label:` ${t.label} `,style:{border:{fg:c.borderFocus}},tags:!0,keys:!0,mouse:!0}),i=[{key:"title",label:"title",value:()=>t.title,hint:"Title:"},{key:"description",label:"description",value:()=>(t.description??"\u2014").split(`
3
+ `)[0]??"\u2014",hint:"Description (one line here, e for $EDITOR):"},{key:"status",label:"status",value:()=>t.status,hint:`Status (${A().join(", ")}):`},{key:"type",label:"type",value:()=>t.type,hint:"Type (task, bug, story, epic):"},{key:"priority",label:"priority",value:()=>t.priority,hint:"Priority (low, normal, high, urgent):"},{key:"assignee",label:"assignee",value:()=>t.assignee??"\u2014",hint:'Assignee (or "none"):'},{key:"estimate",label:"estimate",value:()=>t.estimate===null?"\u2014":String(t.estimate),hint:"Estimate in points:"},{key:"due",label:"due",value:()=>t.due??"\u2014",hint:"Due date YYYY-MM-DD (empty clears):"},{key:"labels",label:"labels",value:()=>t.labels.length>0?t.labels.join(", "):"\u2014",hint:"Labels, comma separated:"}],e=()=>[...i.map((v,f)=>({kind:"field",index:f})),...t.criteria.map(v=>({kind:"criterion",n:v.n}))],o=S.list({parent:r,top:0,left:1,right:1,height:i.length+t.criteria.length,keys:!1,mouse:!1,interactive:!1,tags:!0,style:{selected:{fg:c.selectedFg,bg:c.selectedBg}}}),u=0,a=S.box({parent:r,top:i.length+t.criteria.length+1,left:1,right:1,bottom:0,tags:!0,scrollable:!0});function l(){o.setItems(e().map((f,B)=>f.kind==="field"?J(i[f.index].label,i[f.index].value(),B===u):J(` ${f.n}.`,`[${t.criteria.find($=>$.n===f.n)?.checked===!0?"x":" "}] ${t.criteria.find($=>$.n===f.n)?.text??""}`,B===u)));let v=[t.blockedBy.length>0?`{red-fg}blocked by ${t.blockedBy.length} task(s){/}`:"",t.parent!==null?"{gray-fg}has a parent{/}":"",t.loggedHours>0?`{gray-fg}logged ${t.loggedHours.toFixed(1)}h{/}`:"","",t.description!==null&&t.description.includes(`
4
+ `)?`{gray-fg}${t.description.split(`
5
+ `).slice(1).join(`
6
+ `)}{/}`:"",t.comments.length>0?`{cyan-fg}comments (${t.comments.length}){/}`:"",...t.comments.map(f=>` {gray-fg}${f.author}:{/} ${f.text}`),"",t.criteria.length>0?"{gray-fg}space toggles the criterion under the cursor{/}":"","{gray-fg}\u2191\u2193 field enter edit e description in $EDITOR esc close{/}","{gray-fg}description opens the editor, so it can hold paragraphs{/}"].filter(f=>f!=="");a.setContent(v.join(`
7
+ `)),s.render()}l();let N=T.push(v=>M(v)),U=()=>{N(),r.destroy(),y(!0)};function L(){d=n.reload().state;let v=d.tasks.find(f=>f.id===t.id);if(v===void 0){U();return}Object.assign(t,v),l()}function R(){let v=te(()=>n.edit(t.id));v!==null&&w(v),L()}function M(v){let{ch:f,name:B}=v;if(B==="up"||f==="k")return u=_(u,-1,e().length),l();if(B==="down"||f==="j")return u=_(u,1,e().length),l();if(f===" "||B==="space"){let $=e()[u];if($===void 0||$.kind!=="criterion")return;let j=t.criteria.find(H=>H.n===$.n);if(j===void 0)return;let D=n.toggleCriterion(t.id,$.n,j.checked);return D!==null&&w(D),L()}if(le(v))return U();if(f==="e")return R();if(B==="enter"){let $=e()[u];if($!==void 0&&$.kind==="criterion"){let D=t.criteria.find(fe=>fe.n===$.n);if(D===void 0)return;let H=n.toggleCriterion(t.id,$.n,D.checked);return H!==null&&w(H),L()}let j=i[u];if(j===void 0)return;if(j.key==="description")return R();K(j.hint,j.value()==="\u2014"?"":j.value(),D=>{let H=n.setField(t.id,j.key,D);H!==null&&w(H),L()})}}s.render()}function ce(){let t=["{cyan-fg}Navigation{/}"," \u2190 \u2192 h l move between columns"," \u2191 \u2193 k j move between tasks"," enter task details"," / filter escape clears it"," r reload from the journal"," R show only what can be started now (ready)"," b show only what this branch introduced"," M show only one milestone (empty clears it)"," C claim the selected task, or release it if it is yours","","{cyan-fg}Task actions{/}"," [ ] move one column left or right"," m move to a named status"," a assign c comment"," e edit description in $EDITOR"," p priority t log time"," n new task d delete","","{cyan-fg}Sprint{/}"," s sprint menu: status, start, close, burndown"," S add the selected task to the active sprint","","{cyan-fg}Mouse{/}"," click select a card"," drag move a card to another column","","{gray-fg}press any key to close{/}"],r=S.box({parent:s,top:"center",left:"center",width:60,height:Math.min(t.length+2,30),border:{type:"line"},label:" Keys ",style:{border:{fg:c.borderFocus}},tags:!0,scrollable:!0,keys:!0,mouse:!0,content:t.join(`
8
+ `)}),i=T.push(e=>{Q(e)||(i(),r.destroy(),y())});r.on("click",()=>{i(),r.destroy(),y()}),s.render()}function ee(t,r,i){let e=i.length>0?`
9
+
10
+ {gray-fg}${i.map(a=>`${a.key} ${a.label}`).join(" ")} esc close{/}`:`
11
+
12
+ {gray-fg}press any key to close{/}`,o=S.box({parent:s,top:"center",left:"center",width:"80%",height:"70%",border:{type:"line"},label:` ${t} `,style:{border:{fg:c.borderFocus}},tags:!0,scrollable:!0,mouse:!0,content:r+e}),u=T.push(a=>{if(Q(a))return;let l=i.find(N=>N.key===a.ch);u(),o.destroy(),l!==void 0?l.run():y()});s.render()}function ge(t){let{ch:r,name:i}=t;if(i==="left"||r==="h")return b=Math.max(0,b-1),y();if(i==="right"||r==="l")return b=Math.min(m.length-1,b+1),y();if(i==="up"||r==="k"){let e=m[b];e!==void 0&&(e.cursor=_(e.cursor,-1,e.tasks.length),Z());return}if(i==="down"||r==="j"){let e=m[b];e!==void 0&&(e.cursor=_(e.cursor,1,e.tasks.length),Z());return}if(i==="enter"){let e=I();e!==void 0&&ue(e);return}if(r==="["||r==="]"){let e=I();if(e===void 0)return;let o=r==="]"?1:-1,u=m[b+o];return u===void 0?void 0:(x(n.move(e.id,u.status)),b+=o,y())}if(r==="m"){let e=I();return e===void 0?void 0:K(`Move ${e.label} to (${A().join(", ")}):`,"",o=>x(n.move(e.id,o)))}if(r==="a"){let e=I();return e===void 0?void 0:K(`Assign ${e.label} to (or "none"):`,e.assignee??"",o=>x(n.assign(e.id,o)))}if(r==="c"){let e=I();return e===void 0?void 0:K(`Comment on ${e.label}:`,"",o=>x(n.comment(e.id,o)))}if(r==="t"){let e=I();return e===void 0?void 0:K(`Log time on ${e.label} (2h, 90m, -30m):`,"",o=>x(n.logTime(e.id,o)))}if(r==="p"){let e=I();return e===void 0?void 0:K(`Priority for ${e.label} (low, normal, high, urgent):`,e.priority,o=>x(n.setPriority(e.id,o)))}if(r==="n")return K("New task title:","",e=>x(n.create(e)));if(r==="d"){let e=I();return e===void 0?void 0:K(`Delete ${e.label}? type "yes":`,"",o=>{o.toLowerCase()==="yes"?x(n.remove(e.id)):w("Not deleted.")})}if(r==="e"){let e=I();return e===void 0?void 0:x(te(()=>n.edit(e.id)))}if(r==="S"){let e=I();return e===void 0?void 0:x(n.addToSprint(e.id))}if(r==="s")return ee("Sprint",n.sprintStatus(),[{key:"b",label:"burndown",run:()=>ee("Burndown",n.burndown(),[])},{key:"n",label:"start next sprint",run:()=>x(n.sprintStart())},{key:"x",label:"close sprint",run:()=>x(n.sprintClose())}]);if(r==="/")return K("Filter (title, assignee or label):",h,e=>{h=e==="*"?"":e,y()});if(i==="escape"&&h!=="")return h="",w("Filter cleared."),y();if(r==="r")return w("Reloaded."),y(!0);if(r==="R")return g=!g,w(g?"Showing only what can be started now.":"Showing every task."),y();if(r==="b")return"reason"in p?w(p.reason==="detached"?"HEAD is detached, so there is no branch to filter by.":`There is no branch "${p.base}" to compare against.`,c.warn):(E=!E,w(E?`Showing only what ${p.name} introduced since ${p.base}.`:"Showing every task."),y());if(r==="M"){if(d.milestones.length===0)return w("No milestones yet. Create one with kadence milestone create.",c.warn);let e=d.milestones.map(o=>`${o.label} ${o.name}`).join(", ");return K(`Milestone (${e}; empty for all):`,C,o=>{let u=o.trim();if(u==="")return C="",w("Showing every task."),y();let a=d.milestones.find(l=>l.label.toUpperCase()===u.toUpperCase()||l.name.toLowerCase()===u.toLowerCase());if(a===void 0)return w(`No milestone "${u}".`,c.warn);C=a.label,w(`Showing ${a.label} ${a.name}.`),y()})}if(r==="C"){let e=I();return e===void 0?void 0:x(e.claimedBy===null?n.claim(e.id):n.release(e.id))}if(r==="?")return ce();(r==="q"||i==="C-c")&&F(0)}function te(t){let r=s;r.leave();let i=t();return r.enter(),i}let P=null;m.forEach(()=>{}),s.on("mousedown",t=>{if(T.isDialogOpen())return;let r=m.findIndex(u=>{let a=u.box.left;return t.x>=a&&t.x<a+u.box.width});if(r===-1)return;b=r;let i=m[r],e=t.y-i.box.top-1,o=i.tasks[e];o!==void 0&&(i.cursor=e,P={task:o,from:r}),y()}),s.on("mouseup",t=>{if(T.isDialogOpen()||P===null)return;let r=m.findIndex(i=>{let e=i.box.left;return t.x>=e&&t.x<e+i.box.width});r!==-1&&r!==P.from&&(x(n.move(P.task.id,m[r].status)),b=r,y()),P=null}),X(),y()}export{ve as boardHeader,Ie as runBoardUi};