kadence 0.7.0 → 0.8.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 +72 -0
- package/README.md +15 -16
- package/dist/chunks/{board-5SQP5RX6.js → board-2HUYLTND.js} +1 -1
- package/dist/chunks/{chunk-MOXGQLKI.js → chunk-E7WLBKNZ.js} +100 -65
- package/dist/chunks/chunk-IP426V3B.js +16 -0
- package/dist/chunks/{ui-O7JSS6KE.js → ui-PATAOGVA.js} +2 -2
- package/dist/cli.js +136 -139
- package/package.json +1 -1
- package/dist/chunks/chunk-CR5YON2J.js +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.8.0] — 2026-09-30
|
|
6
|
+
|
|
7
|
+
**The journal is searched before the agent starts guessing.** Agents told to
|
|
8
|
+
use `kadence search` did not: in natural runs on this repository 1 in 10
|
|
9
|
+
reached for it, and 0 in 10 after the instruction files said "before grep".
|
|
10
|
+
Every one opened with grep over the whole tree. So `kadence init` now installs
|
|
11
|
+
a UserPromptSubmit hook that searches the journal for each prompt and puts up
|
|
12
|
+
to three records next to it — by default, next to the `prime` hook.
|
|
13
|
+
|
|
14
|
+
### ⚠️ `init` now writes `.claude/settings.json`
|
|
15
|
+
|
|
16
|
+
It used to only with `--hooks`. It now installs both hooks unless you pass
|
|
17
|
+
`--no-hooks`, creates the file when there is none, keeps every hook that was
|
|
18
|
+
already there, says what it added, and never rewrites a file it cannot parse.
|
|
19
|
+
`--hooks` is still accepted.
|
|
20
|
+
|
|
21
|
+
Measured on the same ten questions, same prompt, Sonnet agents:
|
|
22
|
+
|
|
23
|
+
| | without the hook | with it |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Used the journal | 1 / 10 | 9 / 10 (6 as the first step) |
|
|
26
|
+
| Right answer | 9 / 10 | 10 / 10 |
|
|
27
|
+
| Context added, median | ~10.9k tokens | ~7.9k tokens |
|
|
28
|
+
| Time, median | 44 s | 25 s |
|
|
29
|
+
| Answered from files a clone does not have | 1 | 0 |
|
|
30
|
+
|
|
31
|
+
One repository, ten questions, one model. The hook's output was placed in the
|
|
32
|
+
prompt by hand, because subagents do not fire hooks, so this measures what the
|
|
33
|
+
records do once they arrive, not the hook firing in a live session. A signal,
|
|
34
|
+
not a benchmark.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- `kadence hook prompt` — run by the hook, not by hand. Reads the
|
|
39
|
+
UserPromptSubmit payload on stdin and prints up to three records (1 KB at
|
|
40
|
+
most), or nothing. A passage is quoted only when its record holds the whole
|
|
41
|
+
question; a note is given whole, since there is no command to open one.
|
|
42
|
+
Always exits 0: exit 2 from this hook erases the prompt.
|
|
43
|
+
- A record is shown once per session: what a session has seen is kept in the
|
|
44
|
+
system temp directory, keyed by session and repository — never in
|
|
45
|
+
`.kadence/`. The lines are offered on a condition ("if this is about why or
|
|
46
|
+
how something was decided"), not as an order. On ten ordinary code tasks
|
|
47
|
+
the hook added ~180 tokens and sent no agent into the journal; same answers,
|
|
48
|
+
same time.
|
|
49
|
+
- `init` installs it next to the SessionStart hook. The command is
|
|
50
|
+
silent where kadence is missing and swallows an older kadence's exit 2, so a
|
|
51
|
+
teammate who has not upgraded does not lose every prompt they type.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- **`task list --search` runs on the search engine.** It was a substring over
|
|
56
|
+
title, description and comments — a second idea of what "matches" means.
|
|
57
|
+
Now it matches words the way `kadence search` does, reads acceptance
|
|
58
|
+
criteria too, returns every matching task rather than the top five, and
|
|
59
|
+
lists the most relevant first unless `--sort` is given. A fragment no longer
|
|
60
|
+
matches: `--search coo` does not find `cookie`. The flag and the `--json`
|
|
61
|
+
fields are unchanged. The TUI `/` filter stays a substring, since it filters
|
|
62
|
+
as a person types.
|
|
63
|
+
- The instruction section and `.kadence/README.md` list the ways to look
|
|
64
|
+
something up cheapest first, with what each costs in tokens — from the
|
|
65
|
+
prompt hook's ~90 to `board --json`'s ~51,000, with grep at ~11,000.
|
|
66
|
+
- `prime` names `kadence search` first under "Go deeper", with when to use it.
|
|
67
|
+
- The instruction section in `AGENTS.md` / `CLAUDE.md` and `.kadence/README.md`
|
|
68
|
+
say when to search — before grep or a list. On their own these changed
|
|
69
|
+
nothing measurable; they stay because they cost one line.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- `search` missed the last word of every sentence. A full stop stayed inside
|
|
74
|
+
the token, so "release steps." was indexed as `steps.` and a search for
|
|
75
|
+
"steps" never found it. Golden-set recall@3 0.64 → 0.68.
|
|
76
|
+
|
|
5
77
|
## [0.7.0] — 2026-09-25
|
|
6
78
|
|
|
7
79
|
**One question over everything written down — and three fixes that had to come
|
package/README.md
CHANGED
|
@@ -113,8 +113,8 @@ The measurement itself is a working paper and is not published (see
|
|
|
113
113
|
**The first ten minutes, for the person who owns `CLAUDE.md`:**
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
|
-
kadence init
|
|
117
|
-
#
|
|
116
|
+
kadence init # .kadence/, a short section in AGENTS.md and CLAUDE.md, and two
|
|
117
|
+
# Claude Code hooks: prime at session start, a journal search per prompt
|
|
118
118
|
kadence task add "Fix login" --type bug --priority high
|
|
119
119
|
kadence decision add "Keep sessions in Redis" \
|
|
120
120
|
--why "Revocation must be instant" --rejected "JWT: cannot revoke before expiry"
|
|
@@ -211,7 +211,7 @@ Everything `init` touched, so you can undo it by hand:
|
|
|
211
211
|
|---|---|
|
|
212
212
|
| The journal | `.kadence/` — yours to keep or delete; kadence never deletes it |
|
|
213
213
|
| The agent section | between `<!-- kadence:begin -->` and `<!-- kadence:end -->` in `AGENTS.md` and `CLAUDE.md` |
|
|
214
|
-
| The
|
|
214
|
+
| The hooks (unless `--no-hooks`) | the `SessionStart` entry that runs `kadence prime` and the `UserPromptSubmit` entry that runs `kadence hook prompt`, in `.claude/settings.json` |
|
|
215
215
|
| The cache entry | the `.kadence/state.json` line in `.gitignore` |
|
|
216
216
|
|
|
217
217
|
Then `npm uninstall -g kadence`. Nothing lives outside the repository and your
|
|
@@ -232,9 +232,12 @@ kadence ready --json # seven fields per task, not the whole record
|
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
`prime` is held to forty lines and three kilobytes by a test, because it is paid
|
|
235
|
-
for on every turn that follows. `kadence init
|
|
236
|
-
`
|
|
237
|
-
|
|
235
|
+
for on every turn that follows. `kadence init` adds it as a `SessionStart` hook,
|
|
236
|
+
and adds a `UserPromptSubmit` hook that searches the journal for each prompt
|
|
237
|
+
and puts up to three records next to it. Both are on by default because agents
|
|
238
|
+
do not reach for search on their own (1 in 10 measured); `--no-hooks` leaves
|
|
239
|
+
`.claude/settings.json` alone. The journal is searched in the words it is
|
|
240
|
+
written in: a prompt in another language finds nothing.
|
|
238
241
|
|
|
239
242
|
```bash
|
|
240
243
|
kadence board --json
|
|
@@ -321,8 +324,8 @@ either moves both or changes nothing. A typo does not leave half a board.
|
|
|
321
324
|
|
|
322
325
|
| | |
|
|
323
326
|
|---|---|
|
|
324
|
-
| Install |
|
|
325
|
-
| Startup |
|
|
327
|
+
| Install | 114 KB packed — 344 KB of kadence, plus 1.8 MB of blessed |
|
|
328
|
+
| Startup | 70 ms (`--version`, 0.8.0, one laptop) |
|
|
326
329
|
| 10,000 events | 21 ms cold with a compacted archive, 12 ms warm — 199 ms cold if every event is still a separate file |
|
|
327
330
|
| Journal on disk | under 5 MB |
|
|
328
331
|
| One task, as an agent reads it | 982 bytes, or 304 with `--summary` — the same however long the task has been worked on |
|
|
@@ -336,24 +339,20 @@ true.
|
|
|
336
339
|
|
|
337
340
|
**Verified.** The merge thesis, on real git branches. Performance and size, by
|
|
338
341
|
tests that fail if they regress. That the conflict problem exists in the wild —
|
|
339
|
-
measured, not assumed.
|
|
342
|
+
measured, not assumed. 1,188 tests in the repository today, including an
|
|
340
343
|
end-to-end run through the installed binary.
|
|
341
344
|
|
|
342
345
|
**Not verified.** That teams and their AI agents actually lose enough context to want
|
|
343
346
|
this. The bet rests on reasoning and on the industry naming the problem out
|
|
344
347
|
loud — not on our own users. That research, Probe B, is
|
|
345
348
|
designed and not yet run: as of
|
|
346
|
-
2026-09-
|
|
349
|
+
2026-09-30, zero conversations and no external users. What happens next, and
|
|
347
350
|
on which dates, is recorded in this repository's own journal — `kadence
|
|
348
351
|
decision list` and `kadence note list`.
|
|
349
352
|
|
|
350
353
|
**Not built, on purpose.** An MCP package — only if someone who cannot run a CLI
|
|
351
354
|
asks for it, not as an inevitability.
|
|
352
355
|
|
|
353
|
-
**In the repository, not yet released.** `report burndown`, `report velocity`,
|
|
354
|
-
`report workload`, `report --list` and `report <name> --html`. `npm install`
|
|
355
|
-
gives you 0.4.1 without them.
|
|
356
|
-
|
|
357
356
|
`kadence context <task>` was dropped: we measured what `task show --json` already
|
|
358
357
|
returns and it is the whole history of one piece of work, under a kilobyte,
|
|
359
358
|
constant.
|
|
@@ -393,9 +392,9 @@ the decision, its reason and the alternatives that lost are in the events.
|
|
|
393
392
|
|
|
394
393
|
```bash
|
|
395
394
|
npm install
|
|
396
|
-
npm test #
|
|
395
|
+
npm test # 1,188 tests; builds dist/cli.js first
|
|
397
396
|
npm run typecheck
|
|
398
|
-
npm run build #
|
|
397
|
+
npm run build # dist/cli.js 135 KB, blessed kept external (82 KB at 0.4.1)
|
|
399
398
|
```
|
|
400
399
|
|
|
401
400
|
`CLAUDE.md` documents the invariants, the boundaries, and the decisions that
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{s as G}from"./chunk-IP426V3B.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(`
|