kadence 0.5.0 → 0.7.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 +197 -11
- package/README.md +35 -16
- package/dist/chunks/{board-6UNW5ISX.js → board-5SQP5RX6.js} +1 -1
- package/dist/chunks/chunk-CR5YON2J.js +10 -0
- package/dist/chunks/chunk-MOXGQLKI.js +251 -0
- package/dist/chunks/{ui-Q53SLKMA.js → ui-O7JSS6KE.js} +2 -2
- package/dist/cli.js +156 -128
- package/package.json +1 -1
- package/dist/chunks/chunk-CDGGOWGY.js +0 -10
- package/dist/chunks/chunk-FCPGSN7D.js +0 -240
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,192 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.7.0] — 2026-09-25
|
|
6
|
+
|
|
7
|
+
**One question over everything written down — and three fixes that had to come
|
|
8
|
+
first.** `kadence search` answers "what do we know about X" across tasks,
|
|
9
|
+
decisions, notes and documents at once. Getting there meant admitting that the
|
|
10
|
+
commands an agent already calls were returning answers it could not use: one
|
|
11
|
+
that could be forged by a note, one that read the whole journal twice on every
|
|
12
|
+
call, and one that returned four thousand tasks into a window that truncates at
|
|
13
|
+
twenty-five thousand tokens.
|
|
14
|
+
|
|
15
|
+
### ⚠️ Upgrading — three defaults changed
|
|
16
|
+
|
|
17
|
+
Nothing was renamed or removed from `kadence schema --json`, so `kadence/v1`
|
|
18
|
+
stands. What a caller gets **by default** changed in three places, and a script
|
|
19
|
+
that assumed otherwise needs one flag:
|
|
20
|
+
|
|
21
|
+
| Was | Is | To get the old answer |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `task list --json` carried `history` | it does not | `--fields id,label,history` |
|
|
24
|
+
| list commands returned everything | one page of 100 | `--limit 0` |
|
|
25
|
+
| `prime --json` carried full note text | capped at 2000 characters | `kadence note list --json` |
|
|
26
|
+
|
|
27
|
+
`history` was never promised there — the schema has always placed it in
|
|
28
|
+
`task show` — but it was emitted, and Hyrum's Law says somebody depended on it.
|
|
29
|
+
It is 61% of that response at 4000 tasks, which put the command past the point
|
|
30
|
+
where an agent's tool output is silently cut in half.
|
|
31
|
+
|
|
32
|
+
### Added — `kadence search`
|
|
33
|
+
|
|
34
|
+
- **One query, every kind of record.** Tasks with their descriptions,
|
|
35
|
+
acceptance criteria and comments; decisions with their reason and the
|
|
36
|
+
alternative they rejected; notes; documents cut at their headings. Most of
|
|
37
|
+
that was unreachable by any command before this: `task list --search` covered
|
|
38
|
+
24% of the journal's prose and only tasks.
|
|
39
|
+
- **Lexical, not semantic, and measured rather than assumed.** BM25,
|
|
40
|
+
hand-rolled, no dependency, over the folded projection — so labels exist
|
|
41
|
+
(I7), a superseded decision does not answer as though it were current, and
|
|
42
|
+
search cannot disagree with `task show`. An embedding model is 200 MB and
|
|
43
|
+
seconds of cold start against a 200 ms budget and a promise to work offline;
|
|
44
|
+
on a vocabulary of `ULID`, `KAD-N` and `FlowEvent` it is also the weaker
|
|
45
|
+
method. 26 ms a query over 829 units; 158 ms end to end (DEC-26).
|
|
46
|
+
- **A hit is something you can cite.** The ULID, never the derived label; the
|
|
47
|
+
lines a document section came from; and a quoted span whose offsets land on
|
|
48
|
+
the quoted text, so an agent quotes the journal instead of paraphrasing it.
|
|
49
|
+
- **`coverage` — how much of the question a record actually holds**, 0 to 1,
|
|
50
|
+
weighted by how rare each word is. Where the first hit is right this is 1.00
|
|
51
|
+
at the median; where it is wrong, 0.62. Below 0.7 the human output says the
|
|
52
|
+
passage answers part of the question. The obvious signal — the gap to the
|
|
53
|
+
second hit — was measured and does not work: 0.10 against 0.08 (DEC-30).
|
|
54
|
+
- **An empty answer, said plainly.** Below the coverage floor the result is
|
|
55
|
+
nothing, and the message says the journal has no answer. A model handed
|
|
56
|
+
passages that merely look relevant fabricates more than one handed none, so
|
|
57
|
+
this is a feature and not a cop-out. Nine of ten questions about things this
|
|
58
|
+
journal has never discussed get silence.
|
|
59
|
+
- **Quality is held by a test, not by hope.** `test/search-relevance.test.ts`
|
|
60
|
+
runs 25 real questions against the repository's own journal and fails below
|
|
61
|
+
recall@3 of 0.64. Three ranking ideas were measured this release and two were
|
|
62
|
+
removed for making it worse (DEC-27, DEC-28).
|
|
63
|
+
|
|
64
|
+
### Fixed — `prime` could be forged, and repainted your terminal
|
|
65
|
+
|
|
66
|
+
- **A note carrying newlines rendered as sections of its own**, and the
|
|
67
|
+
cheapest section to forge is the `Go deeper:` block `prime` ends with. The
|
|
68
|
+
length was capped; the shape was not. An escape sequence went further and
|
|
69
|
+
cleared the screen — `prime` runs from the `SessionStart` hook without being
|
|
70
|
+
asked.
|
|
71
|
+
- **`prime --json` was unbounded.** One 200 KB note made the session preamble
|
|
72
|
+
200,728 bytes. Free text is now capped at 2000 characters with `bytes`
|
|
73
|
+
alongside, the signal `documentation` already gave (DEC-21).
|
|
74
|
+
|
|
75
|
+
### Fixed — a warm command read the whole journal anyway
|
|
76
|
+
|
|
77
|
+
- **`loadState` called `readAll` on every command**, purely to count corrupted
|
|
78
|
+
and unknown events for a warning, after the snapshot had already answered.
|
|
79
|
+
A warm call read all 10,103 files; a cold one read every event twice.
|
|
80
|
+
345 ms to 201 ms end to end at 10k events; 204 ms to 5 ms in process.
|
|
81
|
+
- **The fingerprint counts bytes as well as names**, so a file rewritten in
|
|
82
|
+
place invalidates the cache. That also means `git checkout .kadence/` — the
|
|
83
|
+
remedy the corruption warning itself recommends — finally invalidates the
|
|
84
|
+
cache it needed to, which it never did (DEC-22).
|
|
85
|
+
- Every performance guardrail measured `loadOrBuild`; the CLI calls
|
|
86
|
+
`loadState`. The bug lived in the gap between them. Both are measured now.
|
|
87
|
+
|
|
88
|
+
### Fixed — list commands returned the whole board
|
|
89
|
+
|
|
90
|
+
- **One page of 100, with the real total and the offset beside it.**
|
|
91
|
+
`task list --json` was 1.3M tokens at 4000 tasks against the 25k at which an
|
|
92
|
+
agent's tool output is cut — silently, so the agent answers on a fraction
|
|
93
|
+
while believing it saw everything. Now 50 KB. `--limit 0` returns everything;
|
|
94
|
+
`--offset` walks (DEC-24).
|
|
95
|
+
- 100 rather than 200 because this repository's own tasks run 1100 bytes each,
|
|
96
|
+
where the ceiling is 93.
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
|
|
100
|
+
- Documentation moved into the journal: 65 documents, `DOC-2` through `DOC-66`,
|
|
101
|
+
as `doc.written` events. `docs/` stays on disk as the working draft and links
|
|
102
|
+
are rewritten to `DOC-N` on publication (DEC-25). The npm package is
|
|
103
|
+
unaffected — `.kadence/` is not in `files`.
|
|
104
|
+
|
|
105
|
+
## [0.6.0] — 2026-09-23
|
|
106
|
+
|
|
107
|
+
**Documentation in the journal, and an honest answer when something goes
|
|
108
|
+
wrong.** Two halves of the same session. Documentation stops being a filename
|
|
109
|
+
someone has to know and becomes an entity an agent is handed — `DOC-N`, revised,
|
|
110
|
+
conflict-aware. And the three places where kadence told an agent something that
|
|
111
|
+
was not true — a claim it had already lost, a failure with no JSON, a flag
|
|
112
|
+
written twice — now answer straight. The second half came out of a contract
|
|
113
|
+
stress audit run against 0.5.0; the report is in
|
|
114
|
+
`docs/research/contract-stress-audit-2026-09.md`.
|
|
115
|
+
|
|
116
|
+
### ⚠️ Upgrading — everyone updates before anyone runs `compact`
|
|
117
|
+
|
|
118
|
+
`compact` in 0.5.0 and earlier archives the events it can parse and then removes
|
|
119
|
+
the whole month directory, which **deletes `doc.*` events written by 0.6.0**.
|
|
120
|
+
An older kadence reads the journal fine; it just must not compact it. From this
|
|
121
|
+
release on, `compact` leaves alone any month holding an event it cannot read.
|
|
122
|
+
If someone compacted with an old binary, `git status` shows the deleted event
|
|
123
|
+
files — restore them, do not re-run.
|
|
124
|
+
|
|
125
|
+
### Added — documentation is an entity
|
|
126
|
+
|
|
127
|
+
- **`kadence doc`** — `add`, `edit`, `show`, `list`, `link`. A document is
|
|
128
|
+
`DOC-N`, stored as `doc.written` revisions in the journal rather than as an
|
|
129
|
+
`.md` file beside it (ADR-014, superseding that part of ADR-010). Text comes
|
|
130
|
+
from `--body`, `--file` or `--stdin`; `--file` reads any path and keeps
|
|
131
|
+
nothing (DEC-15).
|
|
132
|
+
- **A revision names its parents.** Two people revising the same version leave a
|
|
133
|
+
conflict that is reported and settled by writing text — never a silent loss.
|
|
134
|
+
`doc edit` with no new text on a conflicted document is refused with
|
|
135
|
+
`conflicting_state`, because otherwise it would keep whichever version ULID
|
|
136
|
+
order happened to show and nobody would have read the other.
|
|
137
|
+
- **Agents reach documentation without a search term.** `task show --json`
|
|
138
|
+
carries `documentation[]` (label, title, bytes, `updatedAt`), `prime` names the
|
|
139
|
+
documentation of the work you hold, and `doc list --json` carries no bodies.
|
|
140
|
+
One body arrives only when you ask for it with `doc show`.
|
|
141
|
+
- **A body past 16 KiB is written with a warning, not refused.** Agents read long
|
|
142
|
+
inputs measurably worse; splitting is the author's call, not ours.
|
|
143
|
+
- **`KADENCE_ACTOR`** names the claimant (DEC-16). Without it, an agent in a
|
|
144
|
+
linked worktree claims as `email#<worktree>`. A person owns what their agents
|
|
145
|
+
hold; an agent owns only its own.
|
|
146
|
+
- **`task claim` reports what actually happened** — `claim: claimed |
|
|
147
|
+
already_yours | contested`, read back out of the journal after the write.
|
|
148
|
+
Additive to `kadence/v1`.
|
|
149
|
+
|
|
150
|
+
### Changed
|
|
151
|
+
|
|
152
|
+
- **`prime` puts contested claims first in *Yours*,** each carrying `claimedBy`
|
|
153
|
+
and `contestedBy`, so an agent holding a task it no longer owns sees that
|
|
154
|
+
before it starts working. When every claim is the person's own agents, it says
|
|
155
|
+
so instead: *N of your agents collided — keep one, release the rest.*
|
|
156
|
+
- **`task doc` stays** for linking files that already exist; new writing goes to
|
|
157
|
+
`kadence doc`.
|
|
158
|
+
- **A repeated single-value flag keeps its last value** (DEC-18). Only
|
|
159
|
+
`--label`, `--add-label`, `--remove-label`, `--rejected` and `--doc`
|
|
160
|
+
accumulate. `--title a --title b` had been storing both and reporting success.
|
|
161
|
+
|
|
162
|
+
### Fixed — the contract, where it was quiet
|
|
163
|
+
|
|
164
|
+
- **A parser failure answers in JSON.** An unknown flag, a missing value or an
|
|
165
|
+
extra argument is thrown by cac before any handler runs, and it used to reach
|
|
166
|
+
stderr as a bare sentence with nothing on stdout — the one failure `--json`
|
|
167
|
+
did not cover. It now goes through `failure()`: `invalid_argument` with
|
|
168
|
+
`received` and `allowed`, exit 2.
|
|
169
|
+
- **An unknown command no longer exits 0 with both streams empty,** and a bare
|
|
170
|
+
`kadence` prints help instead of nothing. An exception that is not a cac error
|
|
171
|
+
prints its stack and exits 1, rather than being mislabelled as usage.
|
|
172
|
+
- **`compact` no longer deletes events it cannot parse** along with their month
|
|
173
|
+
directory — see Upgrading.
|
|
174
|
+
- **`task doc` recorded a URL as the mangled path `https:/…`** and `task doc add`
|
|
175
|
+
created a directory named `https:` (KAD-33).
|
|
176
|
+
- **`--body -` was read as a missing value and `--body 007` became `7`.**
|
|
177
|
+
`--stdin` is its own flag now, and text flags are read raw from argv. Two text
|
|
178
|
+
sources at once are refused rather than one winning silently.
|
|
179
|
+
- **`doc link` returned a partial document;** it returns the full shape, pinned
|
|
180
|
+
in the schema contract.
|
|
181
|
+
|
|
182
|
+
### Measured
|
|
183
|
+
|
|
184
|
+
- `claim` re-reads the journal after writing: ~121 ms median at 400 events,
|
|
185
|
+
against ~105 ms for a plain read. An agent without `KADENCE_ACTOR` pays one
|
|
186
|
+
git spawn (~10 ms) in `ready`, `prime` and `claim` to detect a linked
|
|
187
|
+
worktree.
|
|
188
|
+
- `ready` and `prime` now sit at the edge of the 200 ms budget as this
|
|
189
|
+
repository's own journal grows. Recorded as a note, not yet as a fix.
|
|
190
|
+
|
|
5
191
|
## [0.5.0] — 2026-09-16
|
|
6
192
|
|
|
7
193
|
**The second author.** kadence was built for a team, and until now its first
|
|
@@ -232,7 +418,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
232
418
|
- **`kadence task claim` / `task release`** — take a task, or give it back.
|
|
233
419
|
`claim` with no argument takes the top of `ready`, which is one step instead
|
|
234
420
|
of two. There is **no lock**, and the message says so: two machines can each
|
|
235
|
-
claim before either pushes. See
|
|
421
|
+
claim before either pushes. See ADR-011.
|
|
236
422
|
- **`kadence note "text" [--task KAD-1]`** and `note list` — something learned
|
|
237
423
|
that was never a choice. Deliberately not a decision: no `--why`, no
|
|
238
424
|
`supersedes`, no number. The help says when to reach for `decision add`
|
|
@@ -268,7 +454,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
268
454
|
events fold differently depending on where they were written. A detached HEAD
|
|
269
455
|
and an unknown base both fail by name rather than reporting no work.
|
|
270
456
|
The measurement that justified the flag, including what would make it wrong,
|
|
271
|
-
is in
|
|
457
|
+
is in branch-context-2026-09.md.
|
|
272
458
|
- **Acceptance criteria** — `task ac add|check|uncheck|list`. The number is a
|
|
273
459
|
position in the folded list, assigned like `KAD-N` and never stored, so two
|
|
274
460
|
branches can each add a criterion and merge without renumbering. Moving a task
|
|
@@ -309,7 +495,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
309
495
|
|
|
310
496
|
What the neighbours call reports is, here, a fold over timestamps the journal
|
|
311
497
|
already carries. The reasoning, the sources and the verdict per report are in
|
|
312
|
-
|
|
498
|
+
reports-discovery-2026-09.md.
|
|
313
499
|
Velocity and cycle time stay out of the headline; they are a consequence, served
|
|
314
500
|
to the person who asks.
|
|
315
501
|
|
|
@@ -340,7 +526,7 @@ to the person who asks.
|
|
|
340
526
|
|
|
341
527
|
Each of these was a standing "no". Each is now tried in the shape that survives
|
|
342
528
|
the three constraints, and each has a kill condition written before the code, in
|
|
343
|
-
|
|
529
|
+
feature-adoption-2026-09.md.
|
|
344
530
|
|
|
345
531
|
- **`kadence board export --html`** — the board, the sprint, the burndown,
|
|
346
532
|
milestones and decisions in force, as **one self-contained file**. No script
|
|
@@ -358,7 +544,7 @@ the three constraints, and each has a kill condition written before the code, in
|
|
|
358
544
|
trusts. A marker in the issue body makes a second publish an edit rather than
|
|
359
545
|
a duplicate, and the issue itself says that edits made there are overwritten.
|
|
360
546
|
Nothing is ever read back. See
|
|
361
|
-
|
|
547
|
+
ADR-012, written before the
|
|
362
548
|
code. Every test runs against a recorded `gh`, never the real one.
|
|
363
549
|
- **`kadence task doc add KAD-1 docs/design.md`** — creates the file from a
|
|
364
550
|
four-line template and records the link in one call. It never overwrites: a
|
|
@@ -389,7 +575,7 @@ the three constraints, and each has a kill condition written before the code, in
|
|
|
389
575
|
adding different labels merged without a conflict and one label vanished with
|
|
390
576
|
no warning. Not a merge failure — a fold storing *state* in an event, the
|
|
391
577
|
exact mistake the product exists to avoid. Reasoning in
|
|
392
|
-
|
|
578
|
+
ADR-013.
|
|
393
579
|
- **`labels` in `ready --json`**, the seventh field, and in the guaranteed set.
|
|
394
580
|
|
|
395
581
|
Source for this slice: a tech lead's feedback of 2026-09-10 — drift comes not
|
|
@@ -576,7 +762,7 @@ is additive within `kadence/v1`, which the contract permits at any version.
|
|
|
576
762
|
The journal held what happened. It now holds **why** — and the reasoning cannot
|
|
577
763
|
quietly go stale, because superseding a decision is one event rather than two
|
|
578
764
|
edits somebody has to remember to make. Reasoning in
|
|
579
|
-
|
|
765
|
+
ADR-010.
|
|
580
766
|
|
|
581
767
|
### Added
|
|
582
768
|
|
|
@@ -601,7 +787,7 @@ edits somebody has to remember to make. Reasoning in
|
|
|
601
787
|
explains this task, and that is the only thing recorded. A missing file is a
|
|
602
788
|
warning, not a refusal — it may arrive in a later commit.
|
|
603
789
|
|
|
604
|
-
Measured before building (
|
|
790
|
+
Measured before building (Probe D):
|
|
605
791
|
across five real questions, grep finds the answering document every time and
|
|
606
792
|
buries it among 10–35 candidates. The link saves the sifting, not the search.
|
|
607
793
|
|
|
@@ -672,8 +858,8 @@ published package rather than the source.
|
|
|
672
858
|
The agent contract, made real. `schema: "kadence/v1"` used to be a version
|
|
673
859
|
string that nothing checked; now the contract is published, the failures are
|
|
674
860
|
machine-readable, and the responses can be narrowed to what an agent actually
|
|
675
|
-
reads. Reasoning in
|
|
676
|
-
measurements in
|
|
861
|
+
reads. Reasoning in ADR-009,
|
|
862
|
+
measurements in Probe C.
|
|
677
863
|
|
|
678
864
|
### Added
|
|
679
865
|
|
|
@@ -744,7 +930,7 @@ asked for.
|
|
|
744
930
|
- Developer tooling (`.claude/`, `.serena/`) is no longer committed: 381 files
|
|
745
931
|
and 3.8 MB of it, against 94 files of actual product. What belongs in git and
|
|
746
932
|
what does not is written down in
|
|
747
|
-
|
|
933
|
+
ADR-007, and `.gitignore` now
|
|
748
934
|
also covers `.env`, coverage output and editor leftovers.
|
|
749
935
|
|
|
750
936
|
## [0.1.3] — 2026-09-03
|
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ reads the same thing as JSON.
|
|
|
56
56
|
**And it stays one call.** That answer stays under a kilobyte whether the project
|
|
57
57
|
holds ten tasks or a thousand — while the journal behind it grows from 5 KB to
|
|
58
58
|
528 KB. The cost of asking does not grow with the history that makes the answer
|
|
59
|
-
worth having.
|
|
59
|
+
worth having. Measured at 948 bytes in
|
|
60
60
|
0.2; 982 bytes at 0.4, after claims and acceptance criteria joined every record.
|
|
61
61
|
|
|
62
62
|
## Why events and not files
|
|
@@ -102,7 +102,9 @@ merged in every order. Zero conflicts, every author preserved, identical final
|
|
|
102
102
|
state. That is an [integration test](test/integration/merge.test.ts), not a
|
|
103
103
|
claim.
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
The measurement itself is a working paper and is not published (see
|
|
106
|
+
`.gitignore`); the mechanism it measures is proved here by
|
|
107
|
+
`test/integration/merge.test.ts`.
|
|
106
108
|
|
|
107
109
|
---
|
|
108
110
|
|
|
@@ -187,7 +189,7 @@ kadence task list --branch
|
|
|
187
189
|
|
|
188
190
|
Nothing is stored for that: which tasks belong to a branch lives in git's
|
|
189
191
|
history and is read when you ask. It narrows the answer between three and
|
|
190
|
-
twenty times,
|
|
192
|
+
twenty times, measured on real board
|
|
191
193
|
sizes.
|
|
192
194
|
|
|
193
195
|
### Also in the box
|
|
@@ -198,8 +200,8 @@ columns, reports folded from the same journal (`report flow`, `cfd`,
|
|
|
198
200
|
`attention`; burndown, velocity and workload are in the repository and not yet
|
|
199
201
|
on npm), a self-contained HTML or Markdown export, `compact` for long journals,
|
|
200
202
|
and shell completion. None of it is required, and none of it is the point —
|
|
201
|
-
it is what the journal happens to know.
|
|
202
|
-
|
|
203
|
+
it is what the journal happens to know. `--help` on each command is the
|
|
204
|
+
reference, and `kadence doc list` is what the journal knows about itself.
|
|
203
205
|
|
|
204
206
|
### Removing kadence
|
|
205
207
|
|
|
@@ -257,7 +259,7 @@ documentation can tell an agent what yours are.
|
|
|
257
259
|
|
|
258
260
|
There is no MCP wrapper, and one gets built only as an **optional package**, when
|
|
259
261
|
someone who cannot run a CLI asks for it: it costs about 700 tokens a session
|
|
260
|
-
over the CLI path —
|
|
262
|
+
over the CLI path — we measured it, and it
|
|
261
263
|
is not the saving the industry benchmarks suggest — it would be a second way to
|
|
262
264
|
say the same thing, and it would not work for agents that have no MCP client at
|
|
263
265
|
all.
|
|
@@ -292,9 +294,23 @@ no number, and `prime` shows the latest:
|
|
|
292
294
|
kadence note "The staging clock runs 40 s behind" --task KAD-1
|
|
293
295
|
```
|
|
294
296
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
**Documentation lives in the journal too.** How something works now, revised as
|
|
298
|
+
it changes — an entity, `DOC-N`, not a filename an agent has to guess:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
kadence doc add "How auth works" --file notes/auth.md --task KAD-1
|
|
302
|
+
kadence doc show DOC-1 --json
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
A revision names the revisions it was written on top of, so two people editing
|
|
306
|
+
the same version leave a conflict that is reported and settled by writing text,
|
|
307
|
+
never a silent overwrite. Agents are handed it without searching: `task show`
|
|
308
|
+
carries `documentation[]` and `prime` names the documentation of the work you
|
|
309
|
+
hold — both without bodies, so the body arrives only when asked for.
|
|
310
|
+
|
|
311
|
+
A markdown file that already exists is still linked, not swallowed:
|
|
312
|
+
`kadence task doc add KAD-1 docs/design.md` records the link, which is the part
|
|
313
|
+
git cannot express.
|
|
298
314
|
|
|
299
315
|
Bulk works everywhere and is all or nothing: `kadence task move KAD-1,KAD-2 done`
|
|
300
316
|
either moves both or changes nothing. A typo does not leave half a board.
|
|
@@ -320,16 +336,16 @@ true.
|
|
|
320
336
|
|
|
321
337
|
**Verified.** The merge thesis, on real git branches. Performance and size, by
|
|
322
338
|
tests that fail if they regress. That the conflict problem exists in the wild —
|
|
323
|
-
measured, not assumed.
|
|
339
|
+
measured, not assumed. 1060 tests in the repository today, including an
|
|
324
340
|
end-to-end run through the installed binary.
|
|
325
341
|
|
|
326
342
|
**Not verified.** That teams and their AI agents actually lose enough context to want
|
|
327
343
|
this. The bet rests on reasoning and on the industry naming the problem out
|
|
328
344
|
loud — not on our own users. That research, Probe B, is
|
|
329
|
-
|
|
330
|
-
2026-09-16,
|
|
331
|
-
|
|
332
|
-
and
|
|
345
|
+
designed and not yet run: as of
|
|
346
|
+
2026-09-16, zero conversations and no external users. What happens next, and
|
|
347
|
+
on which dates, is recorded in this repository's own journal — `kadence
|
|
348
|
+
decision list` and `kadence note list`.
|
|
333
349
|
|
|
334
350
|
**Not built, on purpose.** An MCP package — only if someone who cannot run a CLI
|
|
335
351
|
asks for it, not as an inevitability.
|
|
@@ -368,13 +384,16 @@ branches writing at once produce two different files, and git merges them
|
|
|
368
384
|
without a conflict by construction.
|
|
369
385
|
|
|
370
386
|
Design decisions, each recording what was measured and what would make us
|
|
371
|
-
revisit it
|
|
387
|
+
revisit it, are in the journal that ships with this repository — `kadence
|
|
388
|
+
decision list`, or `kadence decision show DEC-3` for one in full. The longer
|
|
389
|
+
write-ups behind them are working papers and are kept out of git on purpose;
|
|
390
|
+
the decision, its reason and the alternatives that lost are in the events.
|
|
372
391
|
|
|
373
392
|
## Contributing
|
|
374
393
|
|
|
375
394
|
```bash
|
|
376
395
|
npm install
|
|
377
|
-
npm test #
|
|
396
|
+
npm test # 1060 tests; builds dist/cli.js first
|
|
378
397
|
npm run typecheck
|
|
379
398
|
npm run build # one 111 KB bundle, blessed kept external (82 KB at 0.4.1)
|
|
380
399
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
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
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
4
|
`)?`{gray-fg}${t.description.split(`
|
|
5
5
|
`).slice(1).join(`
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var F=["backlog","todo","in_progress","blocked","in_review","done","cancelled"],x="done",S="cancelled",$="in_progress",Y="backlog",ot=["task","bug","story","epic"],at=["low","normal","high","urgent"];function lt(t){let e=m(t.data?.title),s=t.data?.body,u=t.data?.parents;return e===null||typeof s!="string"||s.trim().length===0||!Array.isArray(u)?null:{title:e,body:s,parents:u.filter(l=>typeof l=="string")}}function dt(t,e,s){let u=[];for(let[l,a]of t){let r=a.filter((c,h)=>a.findIndex(k=>k.id===c.id)===h).map(c=>({e:c,r:lt(c)})).filter(c=>c.r!==null);if(r.length===0)continue;let d=new Set(r.flatMap(c=>c.r.parents)),i=r.filter(c=>!d.has(c.e.id));i.length===0&&(i=[r[r.length-1]]);let f=i[i.length-1],y=r[0];u.push({id:l,label:"",title:f.r.title,body:f.r.body,tasks:(e.get(l)??[]).filter(c=>s.has(c)),revision:f.e.id,revisions:r.length,conflicts:i.slice(0,-1).map(c=>({revision:c.e.id,title:c.r.title,body:c.r.body,at:c.e.ts,by:c.e.actor,source:c.e.source})),createdAt:y.e.ts,createdBy:y.e.actor,updatedAt:f.e.ts,updatedBy:f.e.actor,source:f.e.source})}return u.sort((l,a)=>l.id<a.id?-1:1),u.forEach((l,a)=>{l.label=`DOC-${a+1}`}),u}function L(t,e){for(let s=t.length-1;s>=0;s--)if(t[s].id<e)return t[s].started;return $}function wt(t){let e=[...t].sort((n,o)=>n.id<o.id?-1:n.id>o.id?1:0),s=new Map,u=new Map,l=new Map,a=new Map,p=new Map,r=[],d=new Map,i=new Map,f=null,y=[],c={started:$,changes:[]},h=[],k=[];for(let n of e)n.type==="task.created"?z(s,n):n.type==="sprint.created"?G(u,n):n.type==="milestone.created"&&J(l,n);for(let n of e){if(n.type==="decision.recorded"){let o=n.data??{},g=A=>typeof o[A]=="string"&&o[A].length>0?o[A]:null,b=g("title"),v=g("why");b!==null&&v!==null&&p.set(n.id,{id:n.id,label:"",title:b,why:v,rejected:g("rejected"),task:g("task"),docs:Array.isArray(o.docs)?o.docs.filter(A=>typeof A=="string"):[],supersedes:g("supersedes"),supersededBy:null,at:n.ts,by:n.actor,source:n.source});continue}if(n.type==="note.recorded"){let o=m(n.data?.text);o!==null&&r.push({id:n.id,text:o,task:m(n.data?.task),at:n.ts,by:n.actor,source:n.source});continue}if(n.type==="doc.written"){let o=d.get(n.entity)??[];o.push(n),d.set(n.entity,o);continue}if(n.type==="doc.linked"){let o=m(n.data?.task);if(o!==null){let g=i.get(n.entity)??[];g.includes(o)||g.push(o),i.set(n.entity,g)}continue}if(n.type==="template.saved"){let o=typeof n.data?.name=="string"?n.data.name:null;o!==null&&a.set(o,{name:o,fields:n.data?.fields??{},author:n.actor});continue}if(n.type==="board.configured"){let o=n.data?.statuses;if(Array.isArray(o)){let v=o.filter(A=>typeof A=="string"&&A.length>0);v.length>0&&(f=v)}let g=n.data?.dod;Array.isArray(g)&&(y=g.filter(v=>typeof v=="string"&&v.length>0));let b=m(n.data?.started);b!==null&&(c.started=b,c.changes.push({id:n.id,started:b}));continue}if(n.type==="template.deleted"){let o=typeof n.data?.name=="string"?n.data.name:null;o!==null&&a.delete(o);continue}ut(n,s,u,l,h,k,c)}let w=k,T=[...s.values()].sort((n,o)=>n.id<o.id?-1:1);T.forEach((n,o)=>{n.label=`KAD-${o+1}`,ft(n),n.criteria.sort((g,b)=>g.id<b.id?-1:1),n.criteria.forEach((g,b)=>{g.n=b+1}),ct(n)});let M=new Set(T.map(n=>n.id));for(let n of T)n.parent!==null&&!M.has(n.parent)&&(n.parent=null),n.blockedBy=n.blockedBy.filter(o=>M.has(o));let B=[...p.values()].sort((n,o)=>n.id<o.id?-1:1);B.forEach((n,o)=>{n.label=`DEC-${o+1}`});for(let n of B){if(n.supersedes===null)continue;let o=p.get(n.supersedes);o!==void 0&&(o.supersededBy=n.id)}let C=[...l.values()].sort((n,o)=>n.id<o.id?-1:1);C.forEach((n,o)=>{n.label=`MS-${o+1}`});let R=new Map;for(let n of T){if(n.milestone===null||!l.has(n.milestone))continue;let o=R.get(n.milestone)??[];o.push(n.id),R.set(n.milestone,o)}for(let n of C){n.taskIds=R.get(n.id)??[];let o=n.taskIds.map(g=>s.get(g)).filter(g=>g!==void 0);n.totalTasks=o.length,n.doneTasks=o.filter(g=>g.status===x).length,n.totalPoints=o.reduce((g,b)=>g+(b.estimate??0),0),n.donePoints=o.filter(g=>g.status===x).reduce((g,b)=>g+(b.estimate??0),0)}for(let n of B)n.task!==null&&!M.has(n.task)&&(n.task=null);for(let n of r)n.task!==null&&!M.has(n.task)&&(n.task=null);let K=dt(d,i,M);return{tasks:T,decisions:B,documents:K,milestones:C,notes:r,sprints:[...u.values()].sort((n,o)=>n.id<o.id?-1:1),statuses:f??[...F],dod:y,started:c.started,startedChanges:[...c.changes],orphanStatuses:[...new Set(T.map(n=>n.status).filter(n=>!(f??F).includes(n)))].sort(),templates:[...a.values()].sort((n,o)=>n.name.localeCompare(o.name)),cycles:pt(T),pending:w,rejected:h}}function z(t,e){if(t.has(e.entity))return;let s=e.data??{};t.set(e.entity,{id:e.entity,label:"",title:typeof s.title=="string"?s.title:"(untitled)",description:m(s.description),type:Q(s.type),priority:V(s.priority),status:Y,labels:X(s.labels),assignee:m(s.assignee),reporter:e.actor,sprint:null,milestone:null,parent:m(s.parent),blockedBy:[],due:m(s.due),claimedBy:null,claimedAt:null,claimedEventId:null,contestedBy:[],criteria:[],comments:[],docs:[],estimate:typeof s.estimate=="number"?s.estimate:null,loggedHours:0,createdAt:e.ts,updatedAt:e.ts,history:[]})}function G(t,e){if(t.has(e.entity))return;let s=e.data??{};t.set(e.entity,{id:e.entity,name:typeof s.name=="string"?s.name:"(untitled)",description:m(s.description),startDate:m(s.startDate),endDate:m(s.endDate),status:"planned",closedBy:null,taskIds:[]})}function J(t,e){if(t.has(e.entity))return;let s=e.data??{};t.set(e.entity,{id:e.entity,label:"",name:typeof s.name=="string"?s.name:"(untitled)",due:m(s.due),status:"open",closedBy:null,taskIds:[],donePoints:0,totalPoints:0,doneTasks:0,totalTasks:0})}function ut(t,e,s,u,l,a,p){let r=t.data??{};if(t.type==="milestone.created")return J(u,t),!0;if(t.type==="milestone.task_added"){let i=m(r.task);if(i===null)return!0;let f=e.get(i);return f===void 0?(a.push(t),!1):(f.milestone=t.entity,!0)}if(t.type==="milestone.closed"){let i=u.get(t.entity);return i===void 0?(a.push(t),!1):(i.closedBy===null?(i.status="closed",i.closedBy=t.id):l.push(t),!0)}if(t.type==="task.created")return z(e,t),H(e.get(t.entity),t),!0;if(t.type==="sprint.created")return G(s,t),!0;if(t.type.startsWith("sprint.")){let i=s.get(t.entity);if(i===void 0)return a.push(t),!1;if(t.type==="sprint.started")return i.status==="planned"&&(i.status="active"),!0;if(t.type==="sprint.updated")return i.status==="closed"?(l.push(t),!0):(typeof r.name=="string"&&(i.name=r.name),r.description!==void 0&&(i.description=m(r.description)),r.startDate!==void 0&&(i.startDate=m(r.startDate)),r.endDate!==void 0&&(i.endDate=m(r.endDate)),!0);if(t.type==="sprint.closed")return i.closedBy===null?(i.status="closed",i.closedBy=t.id):l.push(t),!0;if(t.type==="sprint.cancelled")return i.status==="planned"?i.status="cancelled":l.push(t),!0;if(t.type==="sprint.task_added"){if(i.status==="closed")return l.push(t),!0;let f=typeof r.task=="string"?r.task:null;if(f===null)return!0;let y=e.get(f);return y===void 0?(a.push(t),!1):(y.sprint=i.id,i.taskIds.includes(f)||i.taskIds.push(f),H(y,t),!0)}return!0}let d=e.get(t.entity);if(d===void 0)return a.push(t),!1;if(t.type==="task.deleted")return e.delete(t.entity),!0;switch(t.type){case"task.moved":{let i=r.to;typeof i=="string"&&i.length>0&&(d.status=i);break}case"task.cancelled":d.status=S;break;case"task.reopened":d.status=L(p.changes,t.id);break;case"task.assigned":d.assignee=m(r.assignee);break;case"task.updated":typeof r.title=="string"&&(d.title=r.title),r.description!==void 0&&(d.description=m(r.description)),r.type!==void 0&&(d.type=Q(r.type)),r.priority!==void 0&&(d.priority=V(r.priority)),r.labels!==void 0&&(d.labels=X(r.labels)),r.due!==void 0&&(d.due=m(r.due)),typeof r.estimate=="number"&&(d.estimate=r.estimate);break;case"task.parent_set":d.parent=m(r.parent);break;case"task.blocked_by_added":{let i=m(r.blocker);i!==null&&!d.blockedBy.includes(i)&&d.blockedBy.push(i);break}case"task.blocked_by_removed":{let i=m(r.blocker);i!==null&&(d.blockedBy=d.blockedBy.filter(f=>f!==i));break}case"task.label_added":{let i=m(r.label);i!==null&&!d.labels.includes(i)&&d.labels.push(i);break}case"task.label_removed":{let i=m(r.label);i!==null&&(d.labels=d.labels.filter(f=>f!==i));break}case"task.criterion_added":{let i=m(r.text);i!==null&&d.criteria.push({id:t.id,n:0,text:i,checked:!1,checkedBy:null});break}case"task.criterion_checked":case"task.criterion_unchecked":break;case"task.doc_linked":{let i=m(r.path);i!==null&&!d.docs.includes(i)&&d.docs.push(i);break}case"task.time_logged":{let i=r.hours;typeof i=="number"&&Number.isFinite(i)&&(d.loggedHours=Math.max(0,d.loggedHours+i));break}case"task.commented":{let i=m(r.text);i!==null&&d.comments.push({id:t.id,author:t.actor,ts:t.ts,text:i,source:t.source});break}default:break}return H(d,t),!0}function ct(t){let e=new Map(t.criteria.map(s=>[s.id,s]));for(let s of t.criteria)s.checked=!1,s.checkedBy=null;for(let s of t.history){if(s.type!=="task.criterion_checked"&&s.type!=="task.criterion_unchecked")continue;let u=m(s.data.criterion),l=u===null?void 0:e.get(u);if(l===void 0)continue;let a=s.type==="task.criterion_checked";l.checked=a,l.checkedBy=a?s.actor:null}}function ft(t){let e=null,s=null,u=null,l=[],a=()=>{e=null,s=null,u=null,l=[]};for(let p of t.history)if(p.type==="task.claimed"){let r=m(p.data.by)??p.actor;e===null?(e=r,s=p.ts,u=p.id):r!==e&&!l.includes(r)&&l.push(r)}else if(p.type==="task.released"){let r=m(p.data.by)??p.actor;e===r?a():l=l.filter(d=>d!==r)}else(p.type==="task.cancelled"||p.type==="task.moved"&&p.data.to===x)&&a();t.claimedBy=e,t.claimedAt=s,t.claimedEventId=u,t.contestedBy=l}function H(t,e){t.history.push({id:e.id,type:e.type,actor:e.actor,ts:e.ts,source:e.source,data:e.data??{}}),e.ts>t.updatedAt&&(t.updatedAt=e.ts)}function m(t){return typeof t=="string"&&t.length>0?t:null}function Q(t){return ot.includes(t)?t:"task"}function V(t){return at.includes(t)?t:"normal"}function X(t){return Array.isArray(t)?t.filter(e=>typeof e=="string"&&e.length>0):[]}function pt(t){let e=new Map(t.map(a=>[a.id,a])),s=[],u=new Set,l=(a,p)=>{let r=new Map,d=(i,f)=>{let y=r.get(i);if(y==="done")return;if(y==="visiting"){let h=f.indexOf(i),k=f.slice(h),w=`${a}:${[...k].sort().join(",")}`;u.has(w)||(u.add(w),s.push({kind:a,path:[...k,i]}));return}r.set(i,"visiting");let c=e.get(i);if(c!==void 0)for(let h of p(c))d(h,[...f,i]);r.set(i,"done")};for(let i of t)d(i.id,[])};return l("parent",a=>a.parent===null?[]:[a.parent]),l("blocking",a=>a.blockedBy),s}var D=864e5;function P(t){return new Date(t).toISOString().slice(0,10)}function E(t){return Date.parse(`${t}T00:00:00.000Z`)}function gt(t){let e=new Date(E(t)),s=(e.getUTCDay()+6)%7;return P(e.getTime()-s*D)}function et(t,e){let s=P(t.getTime());return{from:P(E(s)-(e-1)*D),to:s,days:e}}function tt(t,e){let s=t.slice(0,10);return s>=e.from&&s<=e.to}function N(t,e){if(t.length===0)return 0;let s=Math.max(1,Math.ceil(e*t.length));return t[s-1]}var I=t=>Math.round(t*10)/10;function q(t){if(t.length===0)return null;let e=[...t].sort((s,u)=>s-u);return{shown:{n:e.length,p50:I(N(e,.5)),p85:I(N(e,.85)),p95:I(N(e,.95))},rawP85:N(e,.85)}}function j(t,e){let s=t.indexOf(e);return s===-1?null:new Set(t.slice(0,s))}function Z(t,e,s=[],u=[]){let l=j(s,e),a=r=>r===x||r===S?!1:l===null?r===e:r===e||!l.has(r);return t.history.find(r=>r.type==="task.reopened"?a(L(u,r.id)):r.type==="task.moved"&&typeof r.data.to=="string"&&a(r.data.to))?.ts??null}function yt(t,e){if(e.status===x||e.status===S)return!1;let s=j(t.statuses,t.started);return s===null?e.status===t.started:s.has(e.status)?!1:Z(e,t.started,t.statuses,t.startedChanges)!==null}function _(t){if(t.status!==x)return null;for(let e=t.history.length-1;e>=0;e--){let s=t.history[e];if(s.type==="task.moved"&&s.data.to===x)return s.ts}return null}function ht(t){if(t.status!==S)return null;for(let e=t.history.length-1;e>=0;e--){let s=t.history[e];if(s.type==="task.cancelled"||s.type==="task.moved"&&s.data.to===S)return s.ts}return null}function O(t,e){return Math.max(0,(Date.parse(e)-Date.parse(t))/D)}function mt(t,e,s,u){let l=_(t)??ht(t),a=l===null?u:Date.parse(l),p=[],r=new Map;for(let h of t.history){let k=typeof h.data.blocker=="string"?h.data.blocker:null;if(k!==null){if(h.type==="task.blocked_by_added")r.has(k)||r.set(k,Date.parse(h.ts));else if(h.type==="task.blocked_by_removed"){let w=r.get(k);w!==void 0&&(p.push([w,Math.min(Date.parse(h.ts),a)]),r.delete(k))}}}for(let[h,k]of r){let w=Math.min(e.get(h)??u,a);p.push([k,Math.max(k,w)])}let d=E(s.from),i=E(s.to)+D,f=p.map(([h,k])=>[Math.max(h,d),Math.min(k,i)]).filter(([h,k])=>k>h).sort((h,k)=>h[0]-k[0]),y=0,c=null;for(let[h,k]of f)c===null||h>c[1]?(c!==null&&(y+=c[1]-c[0]),c=[h,k]):k>c[1]&&(c[1]=k);return c!==null&&(y+=c[1]-c[0]),y/D}function St(t,e=new Date,s=30){let u=et(e,s),l=e.getTime(),a=[],p=t.tasks.filter(n=>n.status!==S),r=p.filter(n=>{let o=_(n);return o!==null&&tt(o,u)}),d=[],i=[],f=[];for(let n of r){let o=_(n),g=Z(n,t.started,t.statuses,t.startedChanges);i.push(O(n.createdAt,o)),g!==null&&(d.push(O(g,o)),f.push(O(n.createdAt,g)))}let y=q(d),c=y?.shown??null,h=p.filter(n=>yt(t,n)),k=h.map(n=>{let o=O(Z(n,t.started,t.statuses,t.startedChanges),e.toISOString());return{label:n.label,title:n.title,status:n.status,ageDays:I(o),overP85:y!==null&&o>y.rawP85}}).sort((n,o)=>o.ageDays-n.ageDays),w=new Map,T=n=>{let o=gt(n),g=w.get(o);return g===void 0&&(g={week:o,finished:0,created:0},w.set(o,g)),g};for(let n=E(u.from);n<=E(u.to);n+=D)T(P(n));for(let n of r)T(_(n).slice(0,10)).finished+=1;for(let n of p)tt(n.createdAt,u)&&(T(n.createdAt.slice(0,10)).created+=1);let M=[...w.values()].sort((n,o)=>n.week<o.week?-1:1),B=new Map;for(let n of t.tasks){let o=_(n);o!==null&&B.set(n.id,Date.parse(o))}let C=0,R=0;for(let n of p){let o=mt(n,B,u,l);o>0&&(C+=1,R+=o)}t.tasks.length===0?a.push("No tasks yet."):(h.length===0&&r.length===0&&a.push(`Nothing has crossed "${t.started}" yet. If work starts in another column, say so: kadence board config --started <status>`),r.length===0?a.push(`Nothing finished between ${u.from} and ${u.to}; cycle time needs finished work.`):d.length===0&&a.push(`${r.length} item(s) finished without ever entering "${t.started}", so there is no cycle time to measure.`),t.statuses.includes(t.started)||a.push(`"${t.started}" is not one of the board's columns; set one with kadence board config --started.`));let K=c===null?null:`${c.n<10?`From ${c.n} finished items (a small sample): `:""}85% of finished items took ${c.p85} calendar days or less.`;return{window:u,started:t.started,unit:"calendar days",wip:h.length,finished:r.length,perWeek:M,cycleTime:c,leadTime:q(i)?.shown??null,responseTime:q(f)?.shown??null,sle:K,aging:k,blocked:{tasks:C,days:I(R)},notes:a}}function vt(t,e=new Date,s=30){let u=et(e,s),l=[...t.statuses];for(let d of t.tasks)l.includes(d.status)||l.push(d.status);let a=Y;!l.includes(a)&&t.tasks.length>0&&l.unshift(a);let p=t.tasks.map(d=>{let i=[];for(let f of d.history)f.type==="task.moved"&&typeof f.data.to=="string"?i.push({at:Date.parse(f.ts),status:f.data.to}):f.type==="task.cancelled"?i.push({at:Date.parse(f.ts),status:S}):f.type==="task.reopened"&&i.push({at:Date.parse(f.ts),status:L(t.startedChanges,f.id)});return{createdAt:Date.parse(d.createdAt),changes:i,next:0,status:a}}),r=[];for(let d=E(u.from);d<=E(u.to);d+=D){let i=d+D,f={};for(let y of l)f[y]=0;for(let y of p){for(;y.next<y.changes.length&&y.changes[y.next].at<i;)y.status=y.changes[y.next].status,y.next+=1;y.createdAt>=i||(f[y.status]=(f[y.status]??0)+1)}r.push({date:P(d),counts:f})}return{window:u,statuses:l,days:r}}var W={urgent:0,high:1,normal:2,low:3};function nt(t,e){return t!==null&&t.toLowerCase().includes(e)}function Mt(t,e,s=new Date){let u=s.toISOString().slice(0,10),l=e.search?.toLowerCase();return t.filter(a=>{if(l!==void 0&&l.length>0){let p=a.comments.some(r=>r.text.toLowerCase().includes(l));if(!nt(a.title,l)&&!nt(a.description,l)&&!p)return!1}if(e.status!==void 0&&a.status!==e.status||e.type!==void 0&&a.type!==e.type||e.priority!==void 0&&a.priority!==e.priority)return!1;if(e.assignee!==void 0){let p=e.assignee.toLowerCase(),r=(a.assignee??"").toLowerCase();if(p==="none"?r!=="":r!==p)return!1}if(e.label!==void 0){let p=e.label.toLowerCase();if(!a.labels.some(r=>r.toLowerCase()===p))return!1}return!(e.sprint!==void 0&&a.sprint!==e.sprint||e.overdue===!0&&(a.due===null||a.due>=u)||e.dueBefore!==void 0&&(a.due===null||a.due>=e.dueBefore))})}function Bt(t,e){let s=[...t];switch(e){case"priority":return s.sort((u,l)=>W[u.priority]-W[l.priority]);case"due":return s.sort((u,l)=>st(u.due,l.due,(a,p)=>a<p?-1:a>p?1:0));case"estimate":return s.sort((u,l)=>st(u.estimate,l.estimate,(a,p)=>p-a));default:return s.sort((u,l)=>u.id<l.id?-1:u.id>l.id?1:0)}}function st(t,e,s){return t===null&&e===null?0:t===null?1:e===null?-1:s(t,e)}function Ct(t){let e=[];return t.search!==void 0&&e.push(`search="${t.search}"`),t.status!==void 0&&e.push(`status=${t.status}`),t.type!==void 0&&e.push(`type=${t.type}`),t.priority!==void 0&&e.push(`priority=${t.priority}`),t.assignee!==void 0&&e.push(`assignee=${t.assignee}`),t.label!==void 0&&e.push(`label=${t.label}`),t.overdue===!0&&e.push("overdue"),t.dueBefore!==void 0&&e.push(`due before ${t.dueBefore}`),e.length===0?`No tasks yet.
|
|
3
|
+
Create the first one:
|
|
4
|
+
kadence task add "title"`:`No tasks match ${e.join(" and ")}.
|
|
5
|
+
Try fewer filters:
|
|
6
|
+
kadence task list`}function rt(t,e){return t===null||e===null?!1:t===e?!0:!e.includes("#")&&t.startsWith(`${e}#`)}function kt(t){let e=t.indexOf("#");return e===-1?t:t.slice(0,e)}function it(t){return j(t.statuses??F,t.started??$)}function U(t){return t.status===x||t.status===S}function Rt(t,e={}){let s=e.viewer??null,u=new Set(t.filter(U).map(r=>r.id)),l=e.assignee==="me"?s===null?null:kt(s):e.assignee??null,a=it(e);return t.filter(r=>{if(U(r)||a!==null&&!a.has(r.status)||r.blockedBy.some(d=>!u.has(d))||r.claimedBy!==null&&!rt(r.claimedBy,s)&&r.contestedBy.length===0)return!1;if(l!==null){if(l==="none")return r.assignee===null;if(r.assignee!==l)return!1}return!0}).sort((r,d)=>W[r.priority]-W[d.priority]||(r.id<d.id?-1:1))}function _t(t,e,s,u={}){if(t.length===0)return`No tasks yet.
|
|
7
|
+
Create the first one:
|
|
8
|
+
kadence task add "title"`;let l=t.filter(c=>!U(c));if(l.length===0)return"Nothing ready: every task is done or cancelled.";let a=new Set(t.filter(U).map(c=>c.id)),p=it(u),r=p===null?0:l.filter(c=>!p.has(c.status)).length,d=l.filter(c=>c.blockedBy.some(h=>!a.has(h))).length,i=l.filter(c=>c.claimedBy!==null&&!rt(c.claimedBy,e)&&c.contestedBy.length===0).length,f=[];return r>0&&f.push(`${r} already started`),d>0&&f.push(`${d} blocked`),i>0&&f.push(`${i} claimed by someone else`),s!==void 0&&f.push(`filtered to assignee=${s}`),`Nothing ready${f.length>0?` (${f.join(", ")})`:""}.
|
|
9
|
+
See the whole board:
|
|
10
|
+
kadence task list`}var bt=["created","priority","due","estimate"];function It(t){return bt.includes(t)}export{F as a,x as b,S as c,ot as d,at as e,wt as f,Z as g,yt as h,_ as i,St as j,vt as k,Mt as l,Bt as m,Ct as n,rt as o,U as p,Rt as q,_t as r,bt as s,It as t};
|