kadence 0.4.1 → 0.5.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 +169 -0
- package/README.md +117 -87
- package/dist/chunks/board-6UNW5ISX.js +12 -0
- package/dist/chunks/chunk-FCPGSN7D.js +240 -0
- package/dist/chunks/{ui-BZTPZE22.js → ui-Q53SLKMA.js} +3 -3
- package/dist/cli.js +209 -124
- package/package.json +10 -8
- package/scripts/reference.mjs +120 -0
- package/dist/chunks/board-YUJ6VL5O.js +0 -12
- package/dist/chunks/chunk-FKPFXIL4.js +0 -224
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,174 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.5.0] — 2026-09-16
|
|
6
|
+
|
|
7
|
+
**The second author.** kadence was built for a team, and until now its first
|
|
8
|
+
run spoke to one person with a sprint. This release is the path the second
|
|
9
|
+
person walks: their agent learns to write the why, a machine without kadence
|
|
10
|
+
gets an install hint instead of an error, and the first screens talk about the
|
|
11
|
+
work and its decisions rather than points. Reports are still here; they are
|
|
12
|
+
just no longer the first thing anyone meets.
|
|
13
|
+
|
|
14
|
+
### Added — the teammate path
|
|
15
|
+
|
|
16
|
+
- **The section `init` writes into `AGENTS.md` and `CLAUDE.md` teaches writes,
|
|
17
|
+
not only reads.** `task claim`, `note "…" --task`, and `decision add "…" --why`
|
|
18
|
+
sit beside the read commands, plus one line for an agent on a machine where
|
|
19
|
+
`kadence` is not on PATH: ask the human to install it; `npx` needs the network
|
|
20
|
+
and that is their call. Still 23 lines and 1.2 KB, under a test of 25 lines and
|
|
21
|
+
2 KB; an older section is replaced in place by its version marker.
|
|
22
|
+
- **The `SessionStart` hook survives a machine without kadence.** It runs
|
|
23
|
+
`kadence prime` when the binary is there and otherwise prints one line asking
|
|
24
|
+
the human to install it, exiting 0 (DEC-12: no `npx`, because a hook written by
|
|
25
|
+
`init` must not download code on a teammate's machine). `init --hooks` upgrades
|
|
26
|
+
the old `kadence prime` hook in place instead of adding a second.
|
|
27
|
+
- **`.kadence/README.md` leads to decisions and teammates.** `decision list` and
|
|
28
|
+
`decision add` replace `sprint status` among the top commands, and a new
|
|
29
|
+
"Adding a teammate" section covers install, one `user.email` per person and
|
|
30
|
+
`KADENCE_SOURCE=agent`. Existing READMEs are still never overwritten.
|
|
31
|
+
- **README: the first ten minutes, "Adding a teammate" and "Removing kadence"** —
|
|
32
|
+
the last one lists everything `init` touches, so leaving is a table, not a
|
|
33
|
+
guess. Sprints, reports and exports moved to `docs/reports.md`.
|
|
34
|
+
|
|
35
|
+
### Changed — the first run speaks about the work
|
|
36
|
+
|
|
37
|
+
- **`init`** suggests a first task *and* a first decision, names what to commit
|
|
38
|
+
so a teammate's agent finds it, and mentions `--hooks` when `.claude/` exists.
|
|
39
|
+
- **`prime`** no longer opens with "No active sprint." when there is none; with
|
|
40
|
+
no decision in force it shows one line on how to record one. `--json` unchanged.
|
|
41
|
+
- **`task add` without `--estimate`** says nothing outside a sprint; inside one it
|
|
42
|
+
names the sprint instead of velocity. `sprint add` says the same.
|
|
43
|
+
- **`kadence --help`** lists commands in the order a session meets them: `init,
|
|
44
|
+
prime, ready, task, decision, note, board, ui, schema`, then planning, reports
|
|
45
|
+
and maintenance.
|
|
46
|
+
- **The TUI header** without a sprint reads `N open · M ready · K decisions in
|
|
47
|
+
force`; points appear only when something is estimated.
|
|
48
|
+
- **`report --list`** puts `attention` first and groups burndown, velocity and
|
|
49
|
+
workload under "Sprint and team".
|
|
50
|
+
|
|
51
|
+
### Fixed — the contract
|
|
52
|
+
|
|
53
|
+
- **`schema --json` lists every shipped command.** 21 entries were missing,
|
|
54
|
+
among them `sprint add/edit/start/list/burndown`, `task parent/unblock/cancel/delete`,
|
|
55
|
+
`template`, `completion` and `ui` — additive within `kadence/v1`. A test now
|
|
56
|
+
compares the binary's own commands and actions against the contract and fails
|
|
57
|
+
on any gap. Unknown `decision` actions now return `allowed`, and `task` lists
|
|
58
|
+
`doc` in it.
|
|
59
|
+
|
|
60
|
+
### Tooling
|
|
61
|
+
|
|
62
|
+
- **`scripts/north-star.mjs`** counts repositories with two authors fourteen days
|
|
63
|
+
after their first event — `--local` for a checkout, `--search` through `gh` for
|
|
64
|
+
public ones — and appends a weekly row to `docs/research/north-star-log.md`.
|
|
65
|
+
A maintainer script: the product itself still opens no socket. First row: 0,
|
|
66
|
+
with the reason GitHub code search has not indexed even this repository.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
The command reference stops being prose. And the first two bugs found by using
|
|
71
|
+
the product on itself.
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **`kadence report` is the whole catalogue.** `report burndown`, `report
|
|
76
|
+
velocity` and `report workload` join `flow`, `cfd` and `attention`, and
|
|
77
|
+
`report --list` names all six with what each one answers.
|
|
78
|
+
|
|
79
|
+
The folds were already here — the burndown under `sprint`, the workload
|
|
80
|
+
inside `stats` — so an agent reading `schema --json` could not find them and
|
|
81
|
+
`kadence report` was not the catalogue it looked like. `report burndown`
|
|
82
|
+
calls the same function `sprint burndown` does, resolved in one place, so the
|
|
83
|
+
two cannot drift. `report velocity` is new arithmetic over `sprintReport`,
|
|
84
|
+
and it answers with a range rather than an average (DEC-9): the spread
|
|
85
|
+
between sprints is the forecast, and a series shorter than four sprints says
|
|
86
|
+
so. `report workload` counts open tasks, points, work in progress and blocked
|
|
87
|
+
work per owner, with a row for unassigned work — no hours, no capacity, since
|
|
88
|
+
the journal has neither.
|
|
89
|
+
|
|
90
|
+
`--since` on a report that has no window, or `--sprint` on anything but the
|
|
91
|
+
burndown, is now an error rather than a silently ignored flag (DEC-10).
|
|
92
|
+
|
|
93
|
+
- **`kadence report <name> --html`** — a report as one self-contained page, with
|
|
94
|
+
charts. `flow` gets a percentile dot plot, a created-vs-finished column chart
|
|
95
|
+
and an aging-work chart with the p85 cycle time drawn as a reference line;
|
|
96
|
+
`cfd` gets a stacked area chart with the bands named where they are wide
|
|
97
|
+
enough; `attention` gets the idle days against the threshold. `--file` puts it
|
|
98
|
+
where you want it, and with `--json` the response is the path, not the report.
|
|
99
|
+
|
|
100
|
+
The charts are hand-written inline SVG. Every chart library is a script tag,
|
|
101
|
+
and the page's one promise is the one the board export already makes: it opens
|
|
102
|
+
from disk and asks the network for nothing — asserted structurally, down to
|
|
103
|
+
`url(` in the stylesheet and the `xmlns` an inline `<svg>` does not need.
|
|
104
|
+
Measured at 0.1 ms and 14 KB for the flow page, 1.7 ms and 301 KB for a
|
|
105
|
+
two-year cumulative flow diagram. Every chart is followed by the rows it was
|
|
106
|
+
drawn from: three of the eight categorical colours sit below 3:1 against
|
|
107
|
+
white, and the rule that buys them is that colour is never the only channel.
|
|
108
|
+
|
|
109
|
+
Reasoning in DEC-7 (a page per report rather than a Reports section inside the
|
|
110
|
+
board export — a report is a question with a window, and the board export has
|
|
111
|
+
none) and DEC-8 (the charts).
|
|
112
|
+
|
|
113
|
+
- **`kadence schema --json` and every `--help` now have a machine-readable
|
|
114
|
+
sibling.** `npm run reference` writes `dist/reference.json`: every command,
|
|
115
|
+
its usage line, its flags with their descriptions, its examples, and the
|
|
116
|
+
whole agent contract, read out of the binary rather than written about it.
|
|
117
|
+
The release workflow attaches it to the GitHub release of each tag.
|
|
118
|
+
|
|
119
|
+
This exists because the hand-typed CLI page on the site described 0.3 for the
|
|
120
|
+
whole of 0.4 — nine commands and two dozen flags shipped without it noticing,
|
|
121
|
+
and the agents page named ten of the fifteen error codes. A paragraph has no
|
|
122
|
+
test. A test now reads `src/cli/commands/` and fails when a command file has
|
|
123
|
+
no help behind it, which is the only way that gap stays closed.
|
|
124
|
+
|
|
125
|
+
The generator ships in the package rather than its output: measured at 1.9 KB
|
|
126
|
+
packed against 6.2 KB, and 4.9 KB unpacked against 39.7 KB, for the same
|
|
127
|
+
result. Nothing in the data is unavailable from the CLI itself.
|
|
128
|
+
|
|
129
|
+
- **`scripts/kadence.mjs`** — runs the build in this working tree, rebuilding
|
|
130
|
+
when `src/` is newer. For working on kadence with kadence, which is now how
|
|
131
|
+
this repository is run; `CLAUDE.md` says what that means in practice.
|
|
132
|
+
|
|
133
|
+
### Fixed
|
|
134
|
+
|
|
135
|
+
- **`burndown.finalRemaining` was always `null`.** Both branches of
|
|
136
|
+
`sprint.status === 'closed' ? null : null` read the same, so the one number
|
|
137
|
+
the field exists for — what a closed sprint did not finish — was never in the
|
|
138
|
+
response, including in `sprint burndown --json`. It now carries the points
|
|
139
|
+
left on the sprint's last day.
|
|
140
|
+
|
|
141
|
+
- **A repeated flag crashed `decision add`.** `--rejected A --rejected B` threw
|
|
142
|
+
`o.rejected.trim is not a function`: cac hands a single flag back as a string
|
|
143
|
+
and a repeat as an array, and only `--doc` was normalised for it. The four
|
|
144
|
+
single-value flags went into `.trim()` as arrays.
|
|
145
|
+
|
|
146
|
+
Repeats now mean what each flag means. A second `--why`, `--task` or
|
|
147
|
+
`--supersedes` is a correction, so the last wins; a second `--rejected` is a
|
|
148
|
+
second alternative that was turned down — which is what a decision record is
|
|
149
|
+
for — so both are kept, joined rather than stored as an array because
|
|
150
|
+
`rejected` is a string in `kadence/v1` and the contract only ever gains
|
|
151
|
+
fields.
|
|
152
|
+
|
|
153
|
+
Found by recording a real decision about this repository with two rejected
|
|
154
|
+
options, with 898 tests green. The tests for it go through the built binary,
|
|
155
|
+
because calling the command directly is exactly the path that could not see
|
|
156
|
+
it.
|
|
157
|
+
|
|
158
|
+
### Notes
|
|
159
|
+
|
|
160
|
+
Deleting several tasks by `KAD-N` in one loop removes the wrong ones. Labels
|
|
161
|
+
are derived while folding (I7), so removing `KAD-1` renumbers everything after
|
|
162
|
+
it and the next label in the list now belongs to a different task. Working as
|
|
163
|
+
designed, and a sharp edge: delete by ULID, or one at a time. Recorded as a
|
|
164
|
+
note in this repository's own journal rather than fixed, because the fix is not
|
|
165
|
+
obvious — warning on a bulk delete of labels would fire on the common case too.
|
|
166
|
+
|
|
167
|
+
A board-wide Definition of Done is engineering-shaped. `board config --dod`
|
|
168
|
+
copies its criteria into every new task, so "typecheck clean" landed on the
|
|
169
|
+
Probe B interview tasks, where it means nothing, and there is no `task ac
|
|
170
|
+
remove` to take it off. Noted, not yet answered.
|
|
171
|
+
|
|
3
172
|
## [0.4.1] — 2026-09-13
|
|
4
173
|
|
|
5
174
|
`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
|
|
57
|
-
tasks or a thousand — while the journal behind it grows from 5 KB to
|
|
58
|
-
cost of asking does not grow with the history that makes the answer
|
|
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
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
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
|
-
|
|
194
|
-
**And because the journal has the timestamps, the cost comes out of it for free:**
|
|
193
|
+
### Also in the box
|
|
195
194
|
|
|
196
|
-
|
|
197
|
-
|
|
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.
|
|
198
203
|
|
|
199
|
-
|
|
204
|
+
### Removing kadence
|
|
200
205
|
|
|
201
|
-
|
|
202
|
-
Actual: 37h — 1.6h per point
|
|
206
|
+
Everything `init` touched, so you can undo it by hand:
|
|
203
207
|
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
209
|
-
|
|
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 #
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
MCP client at
|
|
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
|
|
258
|
-
|
|
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,16 @@ 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
|
-
|
|
279
|
-
|
|
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
|
+
Documents stay plain markdown — `kadence task doc add KAD-1 docs/design.md`
|
|
296
|
+
records only the link, which is the part git cannot express. If the file does
|
|
297
|
+
not exist it is created from a template; an existing one is never overwritten.
|
|
280
298
|
|
|
281
299
|
Bulk works everywhere and is all or nothing: `kadence task move KAD-1,KAD-2 done`
|
|
282
300
|
either moves both or changes nothing. A typo does not leave half a board.
|
|
@@ -302,24 +320,35 @@ true.
|
|
|
302
320
|
|
|
303
321
|
**Verified.** The merge thesis, on real git branches. Performance and size, by
|
|
304
322
|
tests that fail if they regress. That the conflict problem exists in the wild —
|
|
305
|
-
measured, not assumed.
|
|
306
|
-
installed binary.
|
|
323
|
+
measured, not assumed. 998 tests in the repository today, including an
|
|
324
|
+
end-to-end run through the installed binary.
|
|
307
325
|
|
|
308
326
|
**Not verified.** That teams and their AI agents actually lose enough context to want
|
|
309
327
|
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
|
|
328
|
+
loud — not on our own users. That research, Probe B, is
|
|
329
|
+
[designed](docs/research/interview-script.md) and not yet run: as of
|
|
330
|
+
2026-09-16, [zero conversations](docs/research/probe-b-results.md) and no
|
|
331
|
+
external users. [The strategy](docs/product/strategy.md) says what happens next
|
|
332
|
+
and on which dates.
|
|
333
|
+
|
|
334
|
+
**Not built, on purpose.** An MCP package — only if someone who cannot run a CLI
|
|
335
|
+
asks for it, not as an inevitability.
|
|
312
336
|
|
|
313
|
-
**
|
|
314
|
-
|
|
337
|
+
**In the repository, not yet released.** `report burndown`, `report velocity`,
|
|
338
|
+
`report workload`, `report --list` and `report <name> --html`. `npm install`
|
|
339
|
+
gives you 0.4.1 without them.
|
|
315
340
|
|
|
316
341
|
`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,
|
|
342
|
+
returns and it is the whole history of one piece of work, under a kilobyte,
|
|
343
|
+
constant.
|
|
318
344
|
The only thing left to add was a different format, and nobody has asked for one.
|
|
319
345
|
|
|
320
346
|
**Known limits.** Conflicts are real but rare: roughly one merge in two hundred.
|
|
321
347
|
Terminal interaction is covered by manual testing; only the key router is
|
|
322
|
-
unit-tested.
|
|
348
|
+
unit-tested. Deleting several tasks by `KAD-N` in one loop removes the wrong
|
|
349
|
+
ones, because labels are derived and renumber as earlier tasks go — delete by
|
|
350
|
+
ULID, or one at a time. There is no `task ac remove`, so a board-wide Definition
|
|
351
|
+
of Done lands on every new task unless it is added with `--no-dod`.
|
|
323
352
|
|
|
324
353
|
---
|
|
325
354
|
|
|
@@ -345,8 +374,9 @@ revisit it: [docs/decisions/](docs/decisions/).
|
|
|
345
374
|
|
|
346
375
|
```bash
|
|
347
376
|
npm install
|
|
348
|
-
npm test
|
|
349
|
-
npm run
|
|
377
|
+
npm test # 998 tests; builds dist/cli.js first
|
|
378
|
+
npm run typecheck
|
|
379
|
+
npm run build # one 111 KB bundle, blessed kept external (82 KB at 0.4.1)
|
|
350
380
|
```
|
|
351
381
|
|
|
352
382
|
`CLAUDE.md` documents the invariants, the boundaries, and the decisions that
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{p as G}from"./chunk-CDGGOWGY.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};
|