kadence 0.1.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 ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] — 2026-09-03
4
+
5
+ First release. Tasks, sprints and velocity as plain files inside a git
6
+ repository, with no server, account or network.
7
+
8
+ ### Core
9
+
10
+ - Append-only event journal: one file per event, never rewritten. Two branches
11
+ editing the same task merge without a conflict — verified on real git
12
+ branches, not only in theory.
13
+ - State folded from the journal on every read, so the board cannot drift from
14
+ reality. A snapshot cache makes that cost 7 ms on 10,000 events.
15
+ - ULID identifiers, so event order is a property of the id rather than of how
16
+ far apart machine clocks have drifted.
17
+
18
+ ### Tasks
19
+
20
+ - Title, description, type (task/bug/story/epic), priority, labels, assignee,
21
+ due date, estimate, comments, logged time.
22
+ - Subtasks and blocking dependencies, with cycle detection that **reports** a
23
+ loop instead of rejecting the later edit — rejecting it would make the state
24
+ depend on merge order.
25
+ - Search across titles, descriptions and comments; filters, sorting, and bulk
26
+ operations that apply all-or-nothing.
27
+ - Templates for repeated task shapes.
28
+
29
+ ### Sprints
30
+
31
+ - Plan the next sprint while the current one runs.
32
+ - Velocity and hours-per-point derived from events, so the numbers cannot be
33
+ forgotten or faked.
34
+ - Burndown reconstructed from the journal for any day — including days before
35
+ the feature existed.
36
+
37
+ ### Board
38
+
39
+ - `kadence board` — plain columns for pipes and scripts.
40
+ - `kadence ui` — interactive kanban: keyboard, mouse, drag between columns, and
41
+ every field editable in place. Loads lazily, so `kadence task add` never pays
42
+ for it.
43
+ - Custom columns per team; `done` cannot be removed because every analytic is
44
+ computed from it.
45
+
46
+ ### For agents
47
+
48
+ - `--json` on every command with a stable `schema: "kadence/v1"`.
49
+ - stdout carries JSON only; warnings go to stderr.
50
+ - `init` writes a guide the agent finds on its own.
51
+
52
+ ### Known limits
53
+
54
+ - The velocity bet is not yet validated with users. See README, Honest status.
55
+ - Terminal interaction is covered by manual testing; only the key router is
56
+ unit-tested.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FlowIt contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # kadence
2
+
3
+ **Your team plans sprints on gut feel. kadence counts what it actually delivers — from a journal that lives in your repository.**
4
+
5
+ Tasks, sprints and velocity as plain files inside your git repo. No server, no
6
+ account, no network. Works offline, and works for AI agents because the data is
7
+ just files they can read.
8
+
9
+ ```bash
10
+ npx kadence init
11
+ npx kadence task add "Fix login" -d "Broken since 2.3" --type bug --estimate 3
12
+ npx kadence ui # interactive board, or `kadence board` for a plain list
13
+ ```
14
+
15
+ > **v0.1.0.** The architecture is measured and covered by 383 tests. The product
16
+ > bet — that teams want sprint analytics in their repo — has not been validated
17
+ > with users yet. See [Honest status](#honest-status).
18
+
19
+ ## Why another tracker
20
+
21
+ There are good file-based trackers already:
22
+ [git-bug](https://github.com/git-bug/git-bug),
23
+ [Backlog.md](https://github.com/MrLesk/Backlog.md),
24
+ [git-issues](https://steviee.github.io/git-issues/). kadence differs in two ways.
25
+
26
+ **1. It never conflicts on merge.** The others store a task as a *mutable* file,
27
+ so two branches touching one task collide. kadence stores an append-only journal
28
+ of events: one file per event, never rewritten.
29
+
30
+ We measured this rather than assumed it. Across **8,396 merge commits from 130
31
+ public repositories** using file-based trackers, conflicts in task files occur
32
+ in 15% of repositories — and **89% of them are `CONFLICT (content)`**, exactly
33
+ the type this design eliminates. Full data:
34
+ [probe-a-results.md](docs/research/probe-a-results.md).
35
+
36
+ **2. It computes velocity.** None of the three tracks sprints, velocity, or how
37
+ estimates compare with reality. kadence derives all of it from the journal, so
38
+ the numbers cannot be forgotten or faked — they are a product of the work.
39
+
40
+ ```
41
+ Sprint "Sprint 12" closed.
42
+
43
+ Velocity: 10 of 10 points
44
+ Actual: 16h — 1.6h per point
45
+ ```
46
+
47
+ That last number is the point of the whole tool: what a story point actually
48
+ costs your team.
49
+
50
+ ## Install
51
+
52
+ Requires Node 20 or newer, and a git repository.
53
+
54
+ ```bash
55
+ npx kadence init
56
+ ```
57
+
58
+ No global install needed. `init` creates `.kadence/`, adds the derived cache to
59
+ `.gitignore`, and writes a short guide for AI agents. It does **not** commit
60
+ anything — that call is yours.
61
+
62
+ ## Commands
63
+
64
+ ```
65
+ kadence init set up kadence in this repository
66
+ kadence ui interactive kanban board
67
+
68
+ kadence task add "<title>" create a task
69
+ -d, --description <text> full description
70
+ --type task|bug|story|epic type; an epic is simply a parent task
71
+ --priority low|normal|high|urgent
72
+ -a, --assignee <who> assignee
73
+ --label <name> label; repeat for several
74
+ --due <date> deadline, YYYY-MM-DD
75
+ --parent <task> make it a subtask
76
+ --template <name> pre-fill from a saved template
77
+ --estimate <points> estimate, always last
78
+ kadence task list list tasks
79
+ --search <text> title, description and comments
80
+ --status|--type|--priority|--assignee|--label
81
+ --overdue --due-before <date>
82
+ --sort created|priority|due|estimate
83
+ --tree show parent/child structure
84
+ kadence task show KAD-1 full detail and history
85
+ kadence task edit KAD-1 opens $EDITOR; or pass field flags
86
+ kadence task move KAD-1 done change state
87
+ kadence task assign KAD-1 <who> assign; "none" unassigns
88
+ kadence task comment KAD-1 "text" comment
89
+ kadence task log KAD-1 2h log time; 90m, -30m to correct
90
+ kadence task parent KAD-2 KAD-1 nest under a parent
91
+ kadence task block KAD-2 KAD-1 KAD-2 waits for KAD-1
92
+ kadence task cancel KAD-1 keeps it in history
93
+ kadence task delete KAD-1 drops it from the board
94
+
95
+ kadence board plain board, one column per status
96
+ -a, --assignee me only your tasks
97
+ --sprint only the active sprint
98
+ kadence board config show or change the columns
99
+ --statuses "todo,doing,done" your own workflow
100
+
101
+ kadence sprint create "Sprint 1" first starts now, later ones are planned
102
+ kadence sprint add KAD-1 [--sprint "Sprint 2"]
103
+ kadence sprint start ["Sprint 2"] start the next planned sprint
104
+ kadence sprint close close and report velocity
105
+ kadence sprint status progress of the active sprint
106
+ kadence sprint burndown chart rebuilt from the journal
107
+ kadence sprint list every sprint
108
+
109
+ kadence template save bug --type bug --priority high
110
+ kadence template list | delete <name>
111
+ ```
112
+
113
+ Most commands accept several tasks at once — `kadence task move KAD-1,KAD-2 done`
114
+ — and apply **all or nothing**: if one id does not exist, nothing changes.
115
+
116
+ Add `--json` to any command for a stable machine-readable shape.
117
+
118
+ ## The interactive board
119
+
120
+ ```
121
+ kadence ui
122
+ ```
123
+
124
+ Columns side by side, mouse and keyboard:
125
+
126
+ ```
127
+ ←→ column ↑↓ task enter details [ ] shift a card
128
+ m status a assign c comment e edit in $EDITOR
129
+ p priority t log time n new d delete
130
+ s sprint menu (status, burndown, start, close) S add to sprint
131
+ / filter ? help q quit
132
+ ```
133
+
134
+ Enter opens a card where every field is editable in place. Dragging a card with
135
+ the mouse moves it between columns. Each action runs the same command the CLI
136
+ does, so the board can never disagree with the terminal.
137
+
138
+ The board loads its UI layer lazily — `kadence task add` never pays for it.
139
+
140
+ ## For AI agents
141
+
142
+ Tasks are files. An agent reads them directly, or through the CLI — no MCP
143
+ server, no token, no network:
144
+
145
+ ```bash
146
+ kadence board --json
147
+ kadence task list --json --status in_progress --sort priority
148
+ kadence task show KAD-1 --json
149
+ kadence sprint status --json
150
+ KADENCE_SOURCE=agent kadence task move KAD-1 in_progress
151
+ ```
152
+
153
+ Every `--json` response carries `schema: "kadence/v1"`. stdout holds JSON and
154
+ nothing else; warnings go to stderr. Exit codes: `0` success, `1` runtime error,
155
+ `2` bad arguments.
156
+
157
+ `init` writes `.kadence/README.md` and a section in `AGENTS.md` so your agent
158
+ finds this on its own.
159
+
160
+ ## How it works
161
+
162
+ ```
163
+ .kadence/
164
+ ├── state.json derived cache — gitignored, safe to delete
165
+ └── events/
166
+ ├── archive/ compacted history, one file per month
167
+ └── 2026-09/ recent events, one file each
168
+ ```
169
+
170
+ Every command appends one event. State is folded from the journal on read, so
171
+ the board can never drift from reality. Two branches writing at once produce two
172
+ different files, and git merges them without a conflict by construction.
173
+
174
+ Measured on 10,000 events:
175
+
176
+ | | |
177
+ |---|---|
178
+ | Cold start with compacted archive | 28 ms |
179
+ | Warm start (cache) | 7 ms |
180
+ | Journal on disk | 1.9 MB (39 MB without compaction) |
181
+ | Bundle | 30 KB, zero runtime deps in the fast path |
182
+
183
+ These are enforced by tests that fail on regression.
184
+
185
+ ## Honest status
186
+
187
+ What is verified:
188
+
189
+ - The merge thesis, on real git branches: three people editing one task produce
190
+ zero conflicts, and every intent is preserved with its author.
191
+ - Performance and size guardrails, by tests that fail if they regress.
192
+ - The conflict problem exists in the wild — measured, not assumed.
193
+
194
+ What is not:
195
+
196
+ - **Whether teams want this.** The velocity bet rests on reasoning, not on user
197
+ interviews. That research is designed but not yet run
198
+ ([interview script](docs/research/interview-script.md)).
199
+ - Conflicts are real but **rare** — roughly one merge in two hundred. That is
200
+ why the headline message is analytics, not conflict-freedom.
201
+
202
+ The full reasoning, including what would prove this product wrong, lives in
203
+ [docs/](docs/README.md).
204
+
205
+ ## Development
206
+
207
+ ```bash
208
+ npm install
209
+ npm test # 363 tests
210
+ npm run build # single 40 KB bundle
211
+ npm run typecheck
212
+ ```
213
+
214
+ The core has **zero runtime dependencies** — ULID and validation are
215
+ hand-rolled, because a general-purpose validator cost 15% of the startup budget
216
+ for a seven-field object ([ADR-003](docs/decisions/003-zero-runtime-deps-in-core.md)).
217
+ The CLI layer uses `cac` and nothing else.
218
+
219
+ Architecture decisions are in [docs/decisions/](docs/decisions/); each one
220
+ records what was measured and what would make us revisit it.
221
+
222
+ ## License
223
+
224
+ MIT
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import v from"blessed";var c={border:"gray",borderFocus:"cyan",headerFg:"white",headerBg:"blue",selectedFg:"black",selectedBg:"cyan",dim:"gray",hint:"gray",warn:"yellow",danger:"red"},oe={backlog:"gray",todo:"white",in_progress:"blue",doing:"blue",blocked:"red",in_review:"magenta",review:"magenta",done:"green",shipped:"green"};function W(s){return oe[s]??"white"}var le={urgent:"\u203C",high:"\u2191",normal:" ",low:"\u2193"},ae={urgent:"red",high:"yellow",normal:"white",low:"gray"},ue={bug:"\u2716",story:"\u25C6",epic:"\u2B22",task:"\xB7"};function E(s,i){return`{${i}-fg}${s}{/}`}function H(s,i){let d=E(le[s.priority],ae[s.priority]),g=E(ue[s.type]??"\xB7","gray"),a=E(s.label,"cyan"),u=[];if(s.blockedBy.length>0&&u.push(E("\u2298","red")),s.comments.length>0&&u.push(E("\u{1F4AC}","gray")),s.due!==null){let $=s.due<new Date().toISOString().slice(0,10);u.push(E($?"\u23F0":"\u{1F4C5}",$?"red":"gray"))}let f=[s.assignee!==null?E(`@${s.assignee.split("@")[0]}`,"gray"):"",s.estimate!==null?E(String(s.estimate),"yellow"):"",u.join("")].filter($=>$.length>0).join(" "),I=`${D(d)}${D(g)} ${D(a)} `,B=f.length>0?` ${D(f)}`:"",P=Math.max(4,i-I.length-B.length),R=[...s.title],x=R.length>P?`${R.slice(0,P-1).join("")}\u2026`:s.title;return`${d}${g} ${a} ${x}${f.length>0?` ${f}`:""}`}function Y(s,i){return i?`{cyan-bg}{black-fg}${D(s)}{/}`:` ${s}`}function z(s,i,d,g=12){let a=`${s.padEnd(g)} ${i}`;return d?`{cyan-bg}{black-fg}\u25B8 ${a}{/}`:` ${a}`}function D(s){return s.replace(/\{[^}]*\}/g,"")}var J=["\u2190\u2192\u2191\u2193 move","enter details","[ ] shift","m status","a assign","c comment","e edit","n new","s sprint","/ filter","? help","q quit (Ctrl-C forces)"].join(" ");function V(s){let i=[],d=!1;function g(){d=!0,setImmediate(()=>{d=!1})}return{dispatch(a){if(d)return;let u=i[i.length-1];u!==void 0?u(a):s(a)},push(a){i.push(a),g();let u=!1;return()=>{if(u)return;u=!0;let f=i.lastIndexOf(a);f!==-1&&i.splice(f,1),g()}},isDialogOpen:()=>i.length>0,depth:()=>i.length}}function X(s){if(s.ch==="")return!1;let i=s.ch.charCodeAt(0);return i<32||i===127}var de=["up","down","pageup","pagedown","home","end"],Q=["escape","q"];function _(s){return de.includes(s.name)}function Z(s){return Q.includes(s.name)||Q.includes(s.ch)}function M(s,i,d){return d===0?0:(s+i+d)%d}var ee="cancelled";function me(s){let i=v.screen({smartCSR:!0,title:"kadence",fullUnicode:!0,mouse:!0}),{state:d}=s.reload(),g="",a=[],u=0,f=V(t=>se(t));function I(t=0){try{i.destroy()}catch{}process.exit(t)}process.on("SIGINT",()=>I(0)),process.on("SIGTERM",()=>I(0)),i.program.on("keypress",(t,n)=>{let r={ch:t??"",name:n?.name??""};(r.name==="C-c"||r.ch==="")&&I(0),!(X(r)&&r.name!=="enter"&&r.name!=="escape")&&f.dispatch(r)});let B=v.box({parent:i,top:0,height:1,width:"100%",tags:!0,style:{fg:c.headerFg,bg:c.headerBg}}),P=v.box({parent:i,bottom:0,height:1,width:"100%",tags:!0,content:` ${J}`,style:{fg:c.hint}}),R=v.box({parent:i,bottom:1,height:1,width:"100%",tags:!0,style:{fg:c.warn}});function x(t,n=c.warn){R.setContent(` ${t}`),R.style.fg=n,i.render()}function $(){let t=d.statuses.filter(r=>r!==ee),n=d.orphanStatuses.filter(r=>r!==ee);return[...t,...n]}function te(t){let n=g.toLowerCase();return d.tasks.filter(r=>r.status===t&&(n===""||r.title.toLowerCase().includes(n)||(r.assignee??"").toLowerCase().includes(n)||r.labels.some(e=>e.toLowerCase().includes(n))))}function N(){for(let r of a)r.box.destroy();a=[];let t=$(),n=Math.max(Math.floor(100/Math.max(t.length,1)),12);t.forEach((r,e)=>{let o=v.box({parent:i,top:1,left:`${e*n}%`,width:`${n}%`,bottom:2,label:` ${r} `,border:{type:"line"},style:{border:{fg:c.border},label:{fg:W(r)}}}),h=v.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"}}});a.push({status:r,box:o,list:h,tasks:[],cursor:0})})}function p(t=!1){t&&(d=s.reload().state),a.length!==$().length&&N();let n=0,r=0;a.forEach((l,S)=>{l.tasks=te(l.status),n+=l.tasks.length,r+=l.tasks.reduce((C,T)=>C+(T.estimate??0),0);let K=l.box.width-4;l.cursor=Math.min(l.cursor,Math.max(0,l.tasks.length-1)),l.list.setItems(l.tasks.map((C,T)=>Y(H(C,K),S===u&&T===l.cursor)));let L=l.tasks.reduce((C,T)=>C+(T.estimate??0),0);l.box.setLabel(` ${l.status} (${l.tasks.length}${L>0?`, ${L}`:""}) `),l.box.style.border.fg=S===u?c.borderFocus:c.border});let e=d.sprints.find(l=>l.status==="active"),o=e===void 0?"no active sprint":e.name,h=g===""?"":` filter: "${g}"`;B.setContent(` kadence ${o} ${n} tasks, ${r} points${h}`),d.cycles.length>0&&x(`${d.cycles.length} dependency cycle(s) \u2014 see kadence task list`,c.danger),i.render()}function w(){let t=a[u];return t?.tasks[t.cursor]}function A(){a.forEach((t,n)=>{let r=t.box.width-4;t.list.setItems(t.tasks.map((e,o)=>Y(H(e,r),n===u&&o===t.cursor))),t.box.style.border.fg=n===u?c.borderFocus:c.border}),i.render()}function m(t){t!==null?x(t,c.warn):x(""),p(!0)}function k(t,n,r){let e=f.push(()=>{}),o=v.prompt({parent:i,top:"center",left:"center",width:"60%",height:7,border:{type:"line"},style:{border:{fg:c.borderFocus}},keys:!0,mouse:!0});o.input(t,n,(h,l)=>{o.destroy(),e(),i.render(),typeof l=="string"&&r(l.trim())})}function ne(t){let n=v.box({parent:i,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}),r=[{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 (${$().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=v.list({parent:n,top:0,left:1,right:1,height:r.length,keys:!1,mouse:!1,interactive:!1,tags:!0,style:{selected:{fg:c.selectedFg,bg:c.selectedBg}}}),o=0,h=v.box({parent:n,top:r.length+1,left:1,right:1,bottom:0,tags:!0,scrollable:!0});function l(){e.setItems(r.map((y,O)=>z(y.label,y.value(),O===o)));let b=[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(y=>` {gray-fg}${y.author}:{/} ${y.text}`),"","{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(y=>y!=="");h.setContent(b.join(`
7
+ `)),i.render()}l();let S=f.push(b=>T(b)),K=()=>{S(),n.destroy(),p(!0)};function L(){d=s.reload().state;let b=d.tasks.find(y=>y.id===t.id);if(b===void 0){K();return}Object.assign(t,b),l()}function C(){let b=G(()=>s.edit(t.id));b!==null&&x(b),L()}function T(b){let{ch:y,name:O}=b;if(O==="up"||y==="k")return o=M(o,-1,r.length),l();if(O==="down"||y==="j")return o=M(o,1,r.length),l();if(Z(b))return K();if(y==="e")return C();if(O==="enter"){let j=r[o];if(j===void 0)return;if(j.key==="description")return C();k(j.hint,j.value()==="\u2014"?"":j.value(),ie=>{let U=s.setField(t.id,j.key,ie);U!==null&&x(U),L()})}}i.render()}function re(){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","","{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{/}"],n=v.box({parent:i,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
+ `)}),r=f.push(e=>{_(e)||(r(),n.destroy(),p())});n.on("click",()=>{r(),n.destroy(),p()}),i.render()}function q(t,n,r){let e=r.length>0?`
9
+
10
+ {gray-fg}${r.map(l=>`${l.key} ${l.label}`).join(" ")} esc close{/}`:`
11
+
12
+ {gray-fg}press any key to close{/}`,o=v.box({parent:i,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:n+e}),h=f.push(l=>{if(_(l))return;let S=r.find(K=>K.key===l.ch);h(),o.destroy(),S!==void 0?S.run():p()});i.render()}function se(t){let{ch:n,name:r}=t;if(r==="left"||n==="h")return u=Math.max(0,u-1),p();if(r==="right"||n==="l")return u=Math.min(a.length-1,u+1),p();if(r==="up"||n==="k"){let e=a[u];e!==void 0&&(e.cursor=M(e.cursor,-1,e.tasks.length),A());return}if(r==="down"||n==="j"){let e=a[u];e!==void 0&&(e.cursor=M(e.cursor,1,e.tasks.length),A());return}if(r==="enter"){let e=w();e!==void 0&&ne(e);return}if(n==="["||n==="]"){let e=w();if(e===void 0)return;let o=n==="]"?1:-1,h=a[u+o];return h===void 0?void 0:(m(s.move(e.id,h.status)),u+=o,p())}if(n==="m"){let e=w();return e===void 0?void 0:k(`Move ${e.label} to (${$().join(", ")}):`,"",o=>m(s.move(e.id,o)))}if(n==="a"){let e=w();return e===void 0?void 0:k(`Assign ${e.label} to (or "none"):`,e.assignee??"",o=>m(s.assign(e.id,o)))}if(n==="c"){let e=w();return e===void 0?void 0:k(`Comment on ${e.label}:`,"",o=>m(s.comment(e.id,o)))}if(n==="t"){let e=w();return e===void 0?void 0:k(`Log time on ${e.label} (2h, 90m, -30m):`,"",o=>m(s.logTime(e.id,o)))}if(n==="p"){let e=w();return e===void 0?void 0:k(`Priority for ${e.label} (low, normal, high, urgent):`,e.priority,o=>m(s.setPriority(e.id,o)))}if(n==="n")return k("New task title:","",e=>m(s.create(e)));if(n==="d"){let e=w();return e===void 0?void 0:k(`Delete ${e.label}? type "yes":`,"",o=>{o.toLowerCase()==="yes"?m(s.remove(e.id)):x("Not deleted.")})}if(n==="e"){let e=w();return e===void 0?void 0:m(G(()=>s.edit(e.id)))}if(n==="S"){let e=w();return e===void 0?void 0:m(s.addToSprint(e.id))}if(n==="s")return q("Sprint",s.sprintStatus(),[{key:"b",label:"burndown",run:()=>q("Burndown",s.burndown(),[])},{key:"n",label:"start next sprint",run:()=>m(s.sprintStart())},{key:"x",label:"close sprint",run:()=>m(s.sprintClose())}]);if(n==="/")return k("Filter (title, assignee or label):",g,e=>{g=e==="*"?"":e,p()});if(r==="escape"&&g!=="")return g="",x("Filter cleared."),p();if(n==="r")return x("Reloaded."),p(!0);if(n==="?")return re();(n==="q"||r==="C-c")&&I(0)}function G(t){let n=i;n.leave();let r=t();return n.enter(),r}let F=null;a.forEach(()=>{}),i.on("mousedown",t=>{if(f.isDialogOpen())return;let n=a.findIndex(h=>{let l=h.box.left;return t.x>=l&&t.x<l+h.box.width});if(n===-1)return;u=n;let r=a[n],e=t.y-r.box.top-1,o=r.tasks[e];o!==void 0&&(r.cursor=e,F={task:o,from:n}),p()}),i.on("mouseup",t=>{if(f.isDialogOpen()||F===null)return;let n=a.findIndex(r=>{let e=r.box.left;return t.x>=e&&t.x<e+r.box.width});n!==-1&&n!==F.from&&(m(s.move(F.task.id,a[n].status)),u=n,p()),F=null}),N(),p()}export{me as runBoardUi};
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ var U=["backlog","todo","in_progress","blocked","in_review","done","cancelled"],Ot="done",Ie="cancelled",D=["task","bug","story","epic"],R=["low","normal","high","urgent"];function ne(e){let n=[...e].sort((l,p)=>l.id<p.id?-1:l.id>p.id?1:0),r=new Map,t=new Map,s=new Map,i=null,o=[],a=[];for(let l of n){if(l.type==="template.saved"){let p=typeof l.data?.name=="string"?l.data.name:null;p!==null&&s.set(p,{name:p,fields:l.data?.fields??{},author:l.actor});continue}if(l.type==="board.configured"){let p=l.data?.statuses;if(Array.isArray(p)){let m=p.filter(g=>typeof g=="string"&&g.length>0);m.length>0&&(i=m)}continue}if(l.type==="template.deleted"){let p=typeof l.data?.name=="string"?l.data.name:null;p!==null&&s.delete(p);continue}q(l,r,t,o,a)}let d=a.length>0,u=a;for(;u.length>0;){let l=[];for(let p of u)q(p,r,t,o,l);if(l.length===u.length){u=l;break}u=l}if(d)for(let l of r.values())l.history.sort((p,m)=>p.id<m.id?-1:1);let c=[...r.values()].sort((l,p)=>l.id<p.id?-1:1);c.forEach((l,p)=>{l.label=`KAD-${p+1}`});let f=new Set(c.map(l=>l.id));for(let l of c)l.parent!==null&&!f.has(l.parent)&&(l.parent=null),l.blockedBy=l.blockedBy.filter(p=>f.has(p));return{tasks:c,sprints:[...t.values()].sort((l,p)=>l.id<p.id?-1:1),statuses:i??[...U],orphanStatuses:[...new Set(c.map(l=>l.status).filter(l=>!(i??U).includes(l)))].sort(),templates:[...s.values()].sort((l,p)=>l.name.localeCompare(p.name)),cycles:_e(c),pending:u,rejected:o}}function q(e,n,r,t,s){let i=e.data??{};if(e.type==="task.created")return n.has(e.entity)||n.set(e.entity,{id:e.entity,label:"",title:typeof i.title=="string"?i.title:"(untitled)",description:x(i.description),type:Q(i.type),priority:ee(i.priority),status:"backlog",labels:te(i.labels),assignee:x(i.assignee),reporter:e.actor,sprint:null,parent:x(i.parent),blockedBy:[],due:x(i.due),comments:[],estimate:typeof i.estimate=="number"?i.estimate:null,loggedHours:0,createdAt:e.ts,updatedAt:e.ts,history:[]}),K(n.get(e.entity),e),!0;if(e.type==="sprint.created")return r.has(e.entity)||r.set(e.entity,{id:e.entity,name:typeof i.name=="string"?i.name:"(untitled)",description:x(i.description),startDate:x(i.startDate),endDate:x(i.endDate),status:"planned",closedBy:null,taskIds:[]}),!0;if(e.type.startsWith("sprint.")){let a=r.get(e.entity);if(a===void 0)return s.push(e),!1;if(e.type==="sprint.started")return a.status==="planned"&&(a.status="active"),!0;if(e.type==="sprint.updated")return a.status==="closed"?(t.push(e),!0):(typeof i.name=="string"&&(a.name=i.name),i.description!==void 0&&(a.description=x(i.description)),i.startDate!==void 0&&(a.startDate=x(i.startDate)),i.endDate!==void 0&&(a.endDate=x(i.endDate)),!0);if(e.type==="sprint.closed")return a.closedBy===null?(a.status="closed",a.closedBy=e.id):t.push(e),!0;if(e.type==="sprint.cancelled")return a.status==="planned"?a.status="cancelled":t.push(e),!0;if(e.type==="sprint.task_added"){if(a.status==="closed")return t.push(e),!0;let d=typeof i.task=="string"?i.task:null;if(d===null)return!0;let u=n.get(d);return u===void 0?(s.push(e),!1):(u.sprint=a.id,a.taskIds.includes(d)||a.taskIds.push(d),K(u,e),!0)}return!0}let o=n.get(e.entity);if(o===void 0)return s.push(e),!1;if(e.type==="task.deleted")return n.delete(e.entity),!0;switch(e.type){case"task.moved":{let a=i.to;typeof a=="string"&&a.length>0&&(o.status=a);break}case"task.cancelled":o.status=Ie;break;case"task.reopened":o.status="in_progress";break;case"task.assigned":o.assignee=x(i.assignee);break;case"task.updated":typeof i.title=="string"&&(o.title=i.title),i.description!==void 0&&(o.description=x(i.description)),i.type!==void 0&&(o.type=Q(i.type)),i.priority!==void 0&&(o.priority=ee(i.priority)),i.labels!==void 0&&(o.labels=te(i.labels)),i.due!==void 0&&(o.due=x(i.due)),typeof i.estimate=="number"&&(o.estimate=i.estimate);break;case"task.parent_set":o.parent=x(i.parent);break;case"task.blocked_by_added":{let a=x(i.blocker);a!==null&&!o.blockedBy.includes(a)&&o.blockedBy.push(a);break}case"task.blocked_by_removed":{let a=x(i.blocker);a!==null&&(o.blockedBy=o.blockedBy.filter(d=>d!==a));break}case"task.time_logged":{let a=i.hours;typeof a=="number"&&Number.isFinite(a)&&(o.loggedHours=Math.max(0,o.loggedHours+a));break}case"task.commented":{let a=x(i.text);a!==null&&o.comments.push({id:e.id,author:e.actor,ts:e.ts,text:a});break}default:break}return K(o,e),!0}function K(e,n){e.history.push({id:n.id,type:n.type,actor:n.actor,ts:n.ts,data:n.data??{}}),n.ts>e.updatedAt&&(e.updatedAt=n.ts)}function x(e){return typeof e=="string"&&e.length>0?e:null}function Q(e){return D.includes(e)?e:"task"}function ee(e){return R.includes(e)?e:"normal"}function te(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"&&n.length>0):[]}function _e(e){let n=new Map(e.map(i=>[i.id,i])),r=[],t=new Set,s=(i,o)=>{let a=new Map,d=(u,c)=>{let f=a.get(u);if(f==="done")return;if(f==="visiting"){let p=c.indexOf(u),m=c.slice(p),g=`${i}:${[...m].sort().join(",")}`;t.has(g)||(t.add(g),r.push({kind:i,path:[...m,u]}));return}a.set(u,"visiting");let l=n.get(u);if(l!==void 0)for(let p of o(l))d(p,[...c,u]);a.set(u,"done")};for(let u of e)d(u.id,[])};return s("parent",i=>i.parent===null?[]:[i.parent]),s("blocking",i=>i.blockedBy),r}var re={urgent:0,high:1,normal:2,low:3};function se(e,n){return e!==null&&e.toLowerCase().includes(n)}function oe(e,n,r=new Date){let t=r.toISOString().slice(0,10),s=n.search?.toLowerCase();return e.filter(i=>{if(s!==void 0&&s.length>0){let o=i.comments.some(a=>a.text.toLowerCase().includes(s));if(!se(i.title,s)&&!se(i.description,s)&&!o)return!1}if(n.status!==void 0&&i.status!==n.status||n.type!==void 0&&i.type!==n.type||n.priority!==void 0&&i.priority!==n.priority)return!1;if(n.assignee!==void 0){let o=n.assignee.toLowerCase(),a=(i.assignee??"").toLowerCase();if(o==="none"?a!=="":a!==o)return!1}if(n.label!==void 0){let o=n.label.toLowerCase();if(!i.labels.some(a=>a.toLowerCase()===o))return!1}return!(n.sprint!==void 0&&i.sprint!==n.sprint||n.overdue===!0&&(i.due===null||i.due>=t)||n.dueBefore!==void 0&&(i.due===null||i.due>=n.dueBefore))})}function ae(e,n){let r=[...e];switch(n){case"priority":return r.sort((t,s)=>re[t.priority]-re[s.priority]);case"due":return r.sort((t,s)=>ie(t.due,s.due,(i,o)=>i<o?-1:i>o?1:0));case"estimate":return r.sort((t,s)=>ie(t.estimate,s.estimate,(i,o)=>o-i));default:return r.sort((t,s)=>t.id<s.id?-1:t.id>s.id?1:0)}}function ie(e,n,r){return e===null&&n===null?0:e===null?1:n===null?-1:r(e,n)}function de(e){let n=[];return e.search!==void 0&&n.push(`search="${e.search}"`),e.status!==void 0&&n.push(`status=${e.status}`),e.type!==void 0&&n.push(`type=${e.type}`),e.priority!==void 0&&n.push(`priority=${e.priority}`),e.assignee!==void 0&&n.push(`assignee=${e.assignee}`),e.label!==void 0&&n.push(`label=${e.label}`),e.overdue===!0&&n.push("overdue"),e.dueBefore!==void 0&&n.push(`due before ${e.dueBefore}`),n.length===0?`No tasks yet.
3
+ Create the first one:
4
+ kadence task add "title"`:`No tasks match ${n.join(" and ")}.
5
+ Try fewer filters:
6
+ kadence task list`}var H=["created","priority","due","estimate"];function ue(e){return H.includes(e)}import{execFileSync as Fe}from"node:child_process";function le(e,n){try{return Fe("git",n,{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return null}}function ce(e){let n=le(e,["rev-parse","--show-toplevel"]);return n===null||n.length===0?null:n}function pe(e){let n=le(e,["config","user.email"]);return n===null||n.length===0?null:n}import{mkdirSync as He,readdirSync as Ye,readFileSync as We,renameSync as Ge,rmSync as Jt,writeFileSync as Ze}from"node:fs";import{join as N}from"node:path";var Me=["task.created","task.moved","task.assigned","task.commented","task.updated","task.cancelled","task.reopened","task.deleted","task.parent_set","task.blocked_by_added","task.blocked_by_removed","task.time_logged","template.saved","template.deleted","board.configured","sprint.created","sprint.started","sprint.updated","sprint.closed","sprint.cancelled","sprint.task_added"],Be=new Set(Me),fe=/^[0-9ABCDEFGHJKMNPQRSTVWXYZ]{26}$/,Le=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?(Z|[+-]\d{2}:\d{2})$/;function Je(e){return typeof e=="string"&&Be.has(e)}function Ue(e){if(typeof e!="object"||e===null)return["event"];let n=e,r=[];return(typeof n.id!="string"||!fe.test(n.id))&&r.push("id"),Je(n.type)||r.push("type"),(typeof n.entity!="string"||!fe.test(n.entity))&&r.push("entity"),(typeof n.actor!="string"||n.actor.length===0)&&r.push("actor"),(typeof n.ts!="string"||!Le.test(n.ts)||Number.isNaN(Date.parse(n.ts)))&&r.push("ts"),n.source!=="human"&&n.source!=="agent"&&r.push("source"),n.data!==void 0&&(typeof n.data!="object"||n.data===null)&&r.push("data"),r}function ge(e){let n=e.data?.description;if(typeof n!="string"||!n.includes(`
7
+ `))return JSON.stringify(e);let r={...e,data:{...e.data,description:n.split(`
8
+ `)}};return JSON.stringify(r,null,2)}function Y(e){let n;try{n=JSON.parse(e)}catch(t){return{event:null,error:`unreadable JSON: ${t.message}`,unknownType:!1}}n=Ke(n);let r=Ue(n);return r.length===1&&r[0]==="type"?{event:null,error:null,unknownType:!0}:r.length>0?{event:null,error:`invalid fields: ${r.join(", ")}`,unknownType:!1}:{event:n,error:null,unknownType:!1}}function Ke(e){if(typeof e!="object"||e===null)return e;let n=e,r=n.data;if(typeof r!="object"||r===null)return e;let t=r.description;return Array.isArray(t)?{...n,data:{...r,description:t.filter(s=>typeof s=="string").join(`
9
+ `)}}:e}var Ve=.2;function O(e){return N(e,".kadence")}function M(e){return N(O(e),"events")}function ze(e){return N(M(e),"archive")}function Xe(e){return e.slice(0,7)}function w(e,n){let r=N(M(e),Xe(n.ts));He(r,{recursive:!0});let t=N(r,`${n.id}.json`),s=N(r,`.${n.id}.tmp`);Ze(s,`${ge(n)}
10
+ `,"utf8"),Ge(s,t)}function I(e){let n=M(e),r=[],t=[],s=new Set,i=0,o=W(ze(e)),a=new Set(o);for(let u of W(n)){let c;try{c=We(u,"utf8")}catch{t.push(u);continue}if(a.has(u)){let l;try{l=JSON.parse(c)}catch{t.push(u);continue}if(!Array.isArray(l)){t.push(u);continue}for(let p of l){let m=Y(JSON.stringify(p));m.unknownType?i++:m.error!==null||m.event===null?t.push(u):s.has(m.event.id)||(s.add(m.event.id),r.push(m.event))}continue}let f=Y(c);if(f.unknownType){i++;continue}if(f.error!==null||f.event===null){t.push(u);continue}s.has(f.event.id)||(s.add(f.event.id),r.push(f.event))}r.sort((u,c)=>u.id<c.id?-1:u.id>c.id?1:0);let d=r.length+t.length;return{events:r,corrupted:t,unknownTypes:i,systemicCorruption:d>0&&t.length/d>Ve}}function W(e){let n;try{n=Ye(e,{withFileTypes:!0})}catch{return[]}let r=[];for(let t of n){let s=N(e,t.name);t.isDirectory()?r.push(...W(s)):t.name.endsWith(".json")&&r.push(s)}return r}import{randomFillSync as qe}from"node:crypto";var ke="0123456789ABCDEFGHJKMNPQRSTVWXYZ",Qe=10,et=16,me=2**48-1;function tt(e){let n="",r=e;for(let t=Qe-1;t>=0;t--)n=ke[r%32]+n,r=Math.floor(r/32);return n}function nt(e){let n="",r=0,t=0;for(let s of e){for(r=r<<8|s,t+=8;t>=5;)t-=5,n+=ke[r>>>t&31];r&=(1<<t)-1}return n.slice(0,et)}function rt(e){for(let n=e.length-1;n>=0;n--){let r=e[n];if(r<255){e[n]=r+1;return}e[n]=0}throw new Error("ULID: random space exhausted within a single millisecond")}function st(){let e=-1,n=new Uint8Array(10);return function(t=Date.now()){if(!Number.isInteger(t)||t<0||t>me)throw new RangeError(`ULID: time out of range 0..${me}: ${t}`);return t>e?(e=t,qe(n)):rt(n),tt(e)+nt(n)}}var $=st();import{readFileSync as it,writeFileSync as ot,renameSync as at,readdirSync as dt,mkdirSync as ut}from"node:fs";import{join as he}from"node:path";var ye="kadence-snapshot/1";function be(e){return he(O(e),"state.json")}function xe(e,n){let r=lt(M(e)),t=ct(e);if(t!==null&&t.version===ye&&t.lastEventId===r.lastEventId&&t.eventCount===r.count)return{state:t.state,fromCache:!0,incomingEvents:0};let s=I(e),i=ne(s.events),o=t===null||n===void 0?0:ft(s.events,t,n);return pt(e,{version:ye,lastEventId:r.lastEventId,eventCount:r.count,state:i}),{state:i,fromCache:!1,incomingEvents:o}}function lt(e){let n="",r=0,t=s=>{let i;try{i=dt(s,{withFileTypes:!0})}catch{return}for(let o of i)if(o.isDirectory())t(he(s,o.name));else if(o.name.endsWith(".json")){r++;let a=o.name.slice(0,-5);a>n&&(n=a)}};return t(e),{lastEventId:n,count:r}}function ct(e){try{let n=JSON.parse(it(be(e),"utf8"));if(typeof n!="object"||n===null)return null;let r=n;return typeof r.version!="string"||typeof r.lastEventId!="string"||typeof r.eventCount!="number"||typeof r.state!="object"?null:r}catch{return null}}function pt(e,n){try{ut(O(e),{recursive:!0});let r=be(e),t=`${r}.tmp`;ot(t,JSON.stringify(n),"utf8"),at(t,r)}catch{}}function ft(e,n,r){let t=0,s=0;for(let o of e)o.id<=n.lastEventId?t++:o.actor!==r&&s++;let i=Math.max(0,t-n.eventCount);return s+i}var S={dim:"\x1B[2m",bold:"\x1B[1m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",reset:"\x1B[0m"};function Z(e,n){return e.NO_COLOR!==void 0?!1:n}function E(e,n,r){return r?`${n}${e}${S.reset}`:e}var gt={done:S.green,in_progress:S.blue,blocked:S.yellow,cancelled:S.dim},mt=72;function Se(e,n=mt){let r=[...e];return r.length<=n?e:`${r.slice(0,n-1).join("")}\u2026`}function G(e){return[...e].length}function ve(e,n){let r=n-G(e);return r>0?e+" ".repeat(r):e}function $e(e,n){if(e.length===0)return`No tasks yet.
11
+ Create the first one:
12
+ kadence task add "title"`;let r=Math.max(...e.map(s=>G(s.label)),2),t=Math.max(...e.map(s=>G(s.status)),6);return e.map(s=>{let i=E(ve(s.label,r),S.bold,n),o=E(ve(s.status,t),gt[s.status]??S.dim,n),a=s.estimate===null?"":E(` (${s.estimate})`,S.dim,n);return`${i} ${o} ${Se(s.title)}${a}`}).join(`
13
+ `)}function we(e){return e<=0?null:`Merged ${e} ${e===1?"change":"changes"} from another branch, no conflicts.`}var kt={urgent:"!!",high:"!",normal:"",low:"v"},yt={bug:"BUG",story:"STORY",task:""};function Te(e,n){let r=[E(e.label,S.bold,n)],t=kt[e.priority];t!==""&&r.push(E(t,e.priority==="low"?S.dim:S.yellow,n));let s=yt[e.type]??"";s!==""&&r.push(E(s,S.dim,n)),r.push(Se(e.title));let i=[];return e.assignee!==null&&i.push(`@${e.assignee.split("@")[0]}`),e.estimate!==null&&i.push(`${e.estimate}`),i.length>0&&r.push(E(`(${i.join(", ")})`,S.dim,n)),` ${r.join(" ")}`}function qt(e,n){if(Object.values(e).reduce((s,i)=>s+i.length,0)===0)return`No tasks yet.
14
+ Create the first one:
15
+ kadence task add "title"`;let t=[];for(let[s,i]of Object.entries(e)){if(i.length===0)continue;let o=i.reduce((d,u)=>d+(u.estimate??0),0),a=o>0?` \u2014 ${o}`:"";t.push(E(`${s} (${i.length}${a})`,S.bold,n),...i.map(d=>Te(d,n)),"")}return t.join(`
16
+ `).trimEnd()}function ht(e,n=new Date){let r=Date.parse(`${e}T00:00:00.000Z`),t=Date.parse(`${n.toISOString().slice(0,10)}T00:00:00.000Z`);if(Number.isNaN(r))return"";let s=Math.round((r-t)/864e5);return s<0?` (overdue by ${-s} day${s===-1?"":"s"})`:s===0?" (today)":s===1?" (tomorrow)":s<=7?` (in ${s} days)`:""}function Ce(e,n){if(e.length===0)return`No tasks yet.
17
+ Create the first one:
18
+ kadence task add "title"`;let r=new Set(e.map(a=>a.id)),t=new Map;for(let a of e){let d=a.parent!==null&&r.has(a.parent)?a.parent:null,u=t.get(d)??[];u.push(a),t.set(d,u)}let s=[],i=new Set,o=(a,d)=>{if(!(d>10))for(let u of t.get(a)??[]){if(i.has(u.id))continue;i.add(u.id);let c=" ".repeat(d),f=u.blockedBy.length>0?E(" [blocked]",S.yellow,n):"";s.push(`${c}${Te(u,n).trimStart()}${f}`),o(u.id,d+1)}};return o(null,0),s.join(`
19
+ `)}function Ee(e){let n=[`${e.label} ${e.title}`,""];if(e.description!==null&&n.push(e.description,""),n.push(` Status: ${e.status}`),n.push(` Type: ${e.type}`),n.push(` Priority: ${e.priority}`),e.labels.length>0&&n.push(` Labels: ${e.labels.join(", ")}`),e.parent!==null&&n.push(` Parent: ${e.parent}`),e.blockedBy.length>0&&n.push(` Blocked by: ${e.blockedBy.length} task(s)`),n.push(` Assignee: ${e.assignee??"\u2014"}`),n.push(` Reporter: ${e.reporter}`),e.due!==null&&n.push(` Due: ${e.due}${ht(e.due)}`),n.push(` Estimate: ${e.estimate??"\u2014"}`),e.comments.length>0){n.push("",` Comments (${e.comments.length}):`);for(let r of e.comments){n.push(` ${r.author} \xB7 ${r.ts.slice(0,10)}`);for(let t of r.text.split(`
20
+ `))n.push(` ${t}`)}}if(e.history.length>0){n.push("",` History (${e.history.length}):`);for(let r of e.history){let t=r.type==="task.moved"?` \u2192 ${String(r.data.to)}`:"";n.push(` ${r.ts.slice(0,16).replace("T"," ")} ${r.actor} ${r.type}${t}`)}}return n.join(`
21
+ `)}import{existsSync as bt}from"node:fs";var un=U;function h(e,n){let r=ce(e);if(r===null)return{ok:!1,exitCode:1,message:`kadence lives inside a git repository, and there is none here.
22
+ Create one and try again:
23
+ git init`};if(!bt(O(r)))return{ok:!1,exitCode:1,message:`No .kadence/ found here.
24
+ Run:
25
+ npx kadence init`};let t=pe(r);if(t===null)return{ok:!1,exitCode:1,message:`Git does not know who you are, so there is no author for the event.
26
+ Run:
27
+ git config user.email you@example.com`};let s=n.KADENCE_SOURCE==="agent"?"agent":"human";return{root:r,actor:t,source:s}}function b(e){return"root"in e}function ln(e,n,r,t={}){let s=h(e,n);if(!b(s))return s;let i=r.trim();if(i.length===0)return{ok:!1,exitCode:2,message:"A task needs a title."};if(t.type!==void 0&&!D.includes(t.type))return{ok:!1,exitCode:2,message:`Unknown type "${t.type}".
28
+ Available: ${D.join(", ")}`};if(t.priority!==void 0&&!R.includes(t.priority))return{ok:!1,exitCode:2,message:`Unknown priority "${t.priority}".
29
+ Available: ${R.join(", ")}`};let o;if(t.parent!==void 0){let{state:c}=k(s.root,s.actor),f=T(c,t.parent);if(f===void 0)return{ok:!1,exitCode:1,message:`No parent task ${t.parent}.
30
+ kadence task list`};o=f.id}let a=$(),d={id:a,type:"task.created",entity:a,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{title:i,...t.description!==void 0?{description:t.description}:{},...t.type!==void 0?{type:t.type}:{},...t.priority!==void 0?{priority:t.priority}:{},...t.assignee!==void 0?{assignee:t.assignee}:{},...t.labels!==void 0&&t.labels.length>0?{labels:t.labels}:{},...t.due!==void 0?{due:t.due}:{},...o!==void 0?{parent:o}:{},...t.estimate!==void 0?{estimate:t.estimate}:{}}};w(s.root,d);let u=t.estimate===void 0?`
31
+ Without an estimate this task will not count towards velocity. Add --estimate.`:"";return{ok:!0,exitCode:0,message:`Created: ${i}${u}`,data:{schema:"kadence/v1",ok:!0,task:{id:a,title:i}}}}function k(e,n){let r=xe(e,n),t=I(e),s=[],i=we(r.incomingEvents);return i!==null&&s.push(i),t.systemicCorruption?s.push(`The journal is badly damaged: ${t.corrupted.length} of ${t.corrupted.length+t.events.length} events are unreadable. Try: git checkout .kadence/`):t.corrupted.length>0&&s.push(`Skipped ${t.corrupted.length} corrupted event(s).`),t.unknownTypes>0&&s.push(`Skipped ${t.unknownTypes} event(s) from a newer format. Update kadence.`),{state:r.state,warnings:s}}function T(e,n){let r=n.toUpperCase();return e.tasks.find(t=>t.id===r||t.label===r)}function De(e,n){return{ok:!1,exitCode:2,message:`Unknown status "${e}".
32
+ Available: ${n.join(", ")}
33
+ kadence board config --statuses "todo,doing,done"`}}function cn(e,n,r){let t=h(e,n);if(!b(t))return t;if(r.type!==void 0&&!D.includes(r.type))return{ok:!1,exitCode:2,message:`Unknown type "${r.type}".
34
+ Available: ${D.join(", ")}`};if(r.priority!==void 0&&!R.includes(r.priority))return{ok:!1,exitCode:2,message:`Unknown priority "${r.priority}".
35
+ Available: ${R.join(", ")}`};if(r.sort!==void 0&&!ue(r.sort))return{ok:!1,exitCode:2,message:`Unknown sort key "${r.sort}".
36
+ Available: ${H.join(", ")}`};let{state:s,warnings:i}=k(t.root,t.actor);if(r.status!==void 0&&!s.statuses.includes(r.status))return De(r.status,s.statuses);let{sort:o,tree:a,...d}=r,u=oe(s.tasks,d),c=o===void 0?u:ae(u,o);return c.length===0?{ok:!0,exitCode:0,warnings:i,message:de(d),data:{schema:"kadence/v1",ok:!0,tasks:[]}}:{ok:!0,exitCode:0,warnings:i,message:a===!0?Ce(c,Z(n,process.stdout.isTTY===!0)):$e(c,Z(n,process.stdout.isTTY===!0)),data:{schema:"kadence/v1",ok:!0,tasks:c.map(Re),cycles:s.cycles}}}function pn(e,n,r,t){let s=h(e,n);if(!b(s))return s;let{state:i,warnings:o}=k(s.root,s.actor);if(!i.statuses.includes(t))return De(t,i.statuses);let{tasks:a,error:d}=P(i,r);if(d!==null)return{ok:!1,exitCode:1,message:d};let u=[],c=[],f="";for(let p of a){if(p.status===t){c.push(p);continue}let m=p.status;w(s.root,{id:$(),type:"task.moved",entity:p.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{from:m,to:t}}),u.push(p),a.length===1&&i.statuses.indexOf(t)-i.statuses.indexOf(m)>1&&(f=`
37
+ Moved straight from ${m} to ${t}, skipping the stages between.`)}if(u.length===0)return{ok:!0,exitCode:0,warnings:o,message:v("already there",c,`is already ${t}.`)};let l=c.length>0?`
38
+ ${c.length} already ${t}.`:"";return{ok:!0,exitCode:0,warnings:o,message:`${v("moved",u,`${u[0].status} \u2192 ${t}`)}${f}${l}`,data:{schema:"kadence/v1",ok:!0,moved:u.map(p=>({id:p.id,label:p.label,to:t}))}}}function Re(e){return{id:e.id,label:e.label,title:e.title,description:e.description,type:e.type,priority:e.priority,status:e.status,labels:e.labels,assignee:e.assignee,reporter:e.reporter,sprint:e.sprint,loggedHours:e.loggedHours,parent:e.parent,blockedBy:e.blockedBy,due:e.due,comments:e.comments,estimate:e.estimate,history:e.history}}function fn(e,n,r,t){let s=h(e,n);if(!b(s))return s;let{state:i,warnings:o}=k(s.root,s.actor),{tasks:a,error:d}=P(i,r);if(d!==null)return{ok:!1,exitCode:1,message:d};let u=t.trim().toLowerCase()==="none"?null:t.trim(),c=a.filter(f=>f.assignee!==u);if(c.length===0)return{ok:!0,exitCode:0,warnings:o,message:u===null?v("already unassigned",a,"is already unassigned."):v("already assigned",a,`is already assigned to ${u}.`)};for(let f of c)w(s.root,{id:$(),type:"task.assigned",entity:f.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{assignee:u}});return{ok:!0,exitCode:0,warnings:o,message:u===null?v("unassigned",c,"unassigned."):v("assigned",c,`\u2192 ${u}`),data:{schema:"kadence/v1",ok:!0,assigned:c.map(f=>({id:f.id,label:f.label,assignee:u}))}}}function gn(e,n,r){let t=h(e,n);if(!b(t))return t;let{state:s,warnings:i}=k(t.root,t.actor),o=T(s,r);return o===void 0?{ok:!1,exitCode:1,message:`No task ${r}.
39
+ kadence task list`}:{ok:!0,exitCode:0,warnings:i,message:Ee(o),data:{schema:"kadence/v1",ok:!0,task:Re(o)}}}function mn(e,n,r,t){let s=h(e,n);if(!b(s))return s;if(t.type!==void 0&&!D.includes(t.type))return{ok:!1,exitCode:2,message:`Unknown type "${t.type}".
40
+ Available: ${D.join(", ")}`};if(t.priority!==void 0&&!R.includes(t.priority))return{ok:!1,exitCode:2,message:`Unknown priority "${t.priority}".
41
+ Available: ${R.join(", ")}`};if(t.due!==void 0&&t.due!==""&&!xt(t.due))return{ok:!1,exitCode:2,message:`Due date must be YYYY-MM-DD, got "${t.due}".
42
+ kadence task edit KAD-1 --due 2026-09-30`};let{state:i,warnings:o}=k(s.root,s.actor),{tasks:a,error:d}=P(i,r);if(d!==null)return{ok:!1,exitCode:1,message:d};if(t.title!==void 0&&a.length>1)return{ok:!1,exitCode:2,message:"A title can only be set on one task at a time."};let u=[],c=new Set;for(let l of a){let p={},m=[];if(t.title!==void 0&&t.title!==l.title&&(p.title=t.title,m.push("title")),t.description!==void 0&&t.description!==(l.description??"")&&(p.description=t.description,m.push("description")),t.type!==void 0&&t.type!==l.type&&(p.type=t.type,m.push("type")),t.priority!==void 0&&t.priority!==l.priority&&(p.priority=t.priority,m.push("priority")),t.due!==void 0&&t.due!==(l.due??"")&&(p.due=t.due,m.push("due")),t.estimate!==void 0&&t.estimate!==l.estimate&&(p.estimate=t.estimate,m.push("estimate")),t.labels!==void 0&&t.labels.join(",")!==l.labels.join(",")&&(p.labels=t.labels,m.push("labels")),m.length!==0){w(s.root,{id:$(),type:"task.updated",entity:l.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:p}),u.push(l);for(let g of m)c.add(g)}}if(u.length===0)return{ok:!0,exitCode:0,warnings:o,message:v("unchanged",a,"nothing changed.")};let f=[...c].join(", ");return{ok:!0,exitCode:0,warnings:o,message:v("updated",u,`updated ${f}.`),data:{schema:"kadence/v1",ok:!0,updated:u.map(l=>({id:l.id,label:l.label})),changed:[...c]}}}function xt(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;let n=new Date(`${e}T00:00:00.000Z`);return!Number.isNaN(n.getTime())&&n.toISOString().slice(0,10)===e}function kn(e,n,r){let t=h(e,n);if(!b(t))return t;let{state:s,warnings:i}=k(t.root,t.actor),{tasks:o,error:a}=P(s,r);if(a!==null)return{ok:!1,exitCode:1,message:a};let d=o.filter(u=>u.status!=="cancelled");if(d.length===0)return{ok:!0,exitCode:0,warnings:i,message:v("already cancelled",o,"is already cancelled.")};for(let u of d)w(t.root,{id:$(),type:"task.cancelled",entity:u.id,actor:t.actor,ts:new Date().toISOString(),source:t.source,data:{}});return{ok:!0,exitCode:0,warnings:i,message:`${v("cancelled",d,"cancelled.")}
43
+ Cancelled work stays in history and does not count as missed.`,data:{schema:"kadence/v1",ok:!0,cancelled:d.map(u=>({id:u.id,label:u.label}))}}}function yn(e,n,r){let t=h(e,n);if(!b(t))return t;let{state:s,warnings:i}=k(t.root,t.actor),{tasks:o,error:a}=P(s,r);if(a!==null)return{ok:!1,exitCode:1,message:a};for(let u of o)w(t.root,{id:$(),type:"task.deleted",entity:u.id,actor:t.actor,ts:new Date().toISOString(),source:t.source,data:{title:u.title}});let d=o.length===1?`${o[0].label} deleted: "${o[0].title}".`:`${o.length} tasks deleted: ${o.map(u=>u.label).join(", ")}.`;return{ok:!0,exitCode:0,warnings:i,message:`${d}
44
+ The events stay in the journal \u2014 history is never rewritten.`,data:{schema:"kadence/v1",ok:!0,deleted:o.map(u=>({id:u.id,label:u.label}))}}}function hn(e,n,r,t){let s=h(e,n);if(!b(s))return s;let i=t.trim();if(i.length===0)return{ok:!1,exitCode:2,message:"A comment needs text."};let{state:o,warnings:a}=k(s.root,s.actor),d=T(o,r);return d===void 0?{ok:!1,exitCode:1,message:`No task ${r}.
45
+ kadence task list`}:(w(s.root,{id:$(),type:"task.commented",entity:d.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{text:i}}),{ok:!0,exitCode:0,warnings:a,message:`Comment added to ${d.label}.`,data:{schema:"kadence/v1",ok:!0,task:{id:d.id,label:d.label}}})}function P(e,n){let r=n.split(",").map(o=>o.trim()).filter(o=>o.length>0);if(r.length===0)return{tasks:[],error:"No task given."};let t=[],s=[];for(let o of r){let a=T(e,o);a===void 0?s.push(o):t.push(a)}return s.length>0?{tasks:[],error:`No task ${s.join(", ")} \u2014 nothing was changed.
46
+ All ids must exist before a bulk change runs.
47
+ kadence task list`}:{tasks:[...new Map(t.map(o=>[o.id,o])).values()],error:null}}function v(e,n,r){return n.length===1?`${n[0].label}: ${r}`:`${n.length} tasks ${e}: ${n.map(t=>t.label).join(", ")}`}function bn(e,n,r,t){let s=h(e,n);if(!b(s))return s;let{state:i,warnings:o}=k(s.root,s.actor),{tasks:a,error:d}=P(i,r);if(d!==null)return{ok:!1,exitCode:1,message:d};let u=t.trim().toLowerCase()==="none",c=null;if(!u){let p=T(i,t);if(p===void 0)return{ok:!1,exitCode:1,message:`No task ${t}.
48
+ kadence task list`};if(a.some(m=>m.id===p.id))return{ok:!1,exitCode:2,message:"A task cannot be its own parent."};c=p.id}let f=a.filter(p=>p.parent!==c);if(f.length===0)return{ok:!0,exitCode:0,warnings:o,message:v("unchanged",a,"already there.")};for(let p of f)w(s.root,{id:$(),type:"task.parent_set",entity:p.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{parent:c}});let l=u?"detached":T(i,t).label;return{ok:!0,exitCode:0,warnings:[...o,...Ne(s.root,s.actor)],message:u?v("detached",f,"detached from its parent."):v("moved",f,`\u2192 child of ${l}`),data:{schema:"kadence/v1",ok:!0,parent:c}}}function xn(e,n,r,t,s){let i=h(e,n);if(!b(i))return i;let{state:o,warnings:a}=k(i.root,i.actor),{tasks:d,error:u}=P(o,r);if(u!==null)return{ok:!1,exitCode:1,message:u};let c=T(o,t);if(c===void 0)return{ok:!1,exitCode:1,message:`No task ${t}.
49
+ kadence task list`};if(d.some(l=>l.id===c.id))return{ok:!1,exitCode:2,message:"A task cannot block itself."};let f=d.filter(l=>s?l.blockedBy.includes(c.id):!l.blockedBy.includes(c.id));if(f.length===0)return{ok:!0,exitCode:0,warnings:a,message:v("unchanged",d,s?"was not blocked by it.":"is already blocked by it.")};for(let l of f)w(i.root,{id:$(),type:s?"task.blocked_by_removed":"task.blocked_by_added",entity:l.id,actor:i.actor,ts:new Date().toISOString(),source:i.source,data:{blocker:c.id}});return{ok:!0,exitCode:0,warnings:[...a,...Ne(i.root,i.actor)],message:s?v("unblocked",f,`no longer blocked by ${c.label}.`):v("blocked",f,`blocked by ${c.label}.`),data:{schema:"kadence/v1",ok:!0,blocker:c.id}}}function Ne(e,n){let{state:r}=k(e,n),t=new Map(r.tasks.map(s=>[s.id,s.label]));return r.cycles.map(s=>{let i=s.path.map(o=>t.get(o)??o).join(" \u2192 ");return`Dependency cycle (${s.kind}): ${i}. Both edges were kept \u2014 resolve it when you can.`})}function vt(e){let n=/^(-?\d+(?:\.\d+)?)\s*(h|hours?|m|min|minutes?)?$/i.exec(e.trim());if(n===null)return null;let r=Number(n[1]);return!Number.isFinite(r)||r===0?null:(n[2]??"h").toLowerCase().startsWith("m")?r/60:r}function vn(e,n,r,t){let s=h(e,n);if(!b(s))return s;let i=vt(t);if(i===null)return{ok:!1,exitCode:2,message:`Cannot read "${t}" as a duration.
50
+ Use hours or minutes:
51
+ kadence task log KAD-1 2h
52
+ kadence task log KAD-1 90m
53
+ kadence task log KAD-1 -30m to correct a mistake`};let{state:o,warnings:a}=k(s.root,s.actor),d=T(o,r);if(d===void 0)return{ok:!1,exitCode:1,message:`No task ${r}.
54
+ kadence task list`};w(s.root,{id:$(),type:"task.time_logged",entity:d.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{hours:i}});let u=Math.max(0,d.loggedHours+i),c=d.estimate===null?`
55
+ No estimate on this task, so there is nothing to compare against.`:"";return{ok:!0,exitCode:0,warnings:a,message:`${d.label}: ${u.toFixed(1)}h logged in total.${c}`,data:{schema:"kadence/v1",ok:!0,task:{id:d.id,label:d.label,loggedHours:u}}}}import{spawnSync as St}from"node:child_process";import{mkdtempSync as $t,readFileSync as wt,rmSync as Tt,writeFileSync as Ct}from"node:fs";import{tmpdir as Et}from"node:os";import{join as Pe}from"node:path";var B="#";function Dt(e){return e.GIT_EDITOR??e.VISUAL??e.EDITOR??"vi"}function En(e,n,r){let t=$t(Pe(Et(),"kadence-edit-")),s=Pe(t,"KADENCE_EDITMSG.md"),i=["",`${B} ${r}`,`${B} Lines starting with '${B}' are ignored.`,`${B} Save an empty file to abort.`].join(`
56
+ `);try{Ct(s,`${n}${i}
57
+ `,"utf8");let o=Dt(e),a=St(o,[s],{stdio:"inherit",shell:!0});if(a.error!==void 0||a.status!==null&&a.status!==0)return{text:null,error:`Editor "${o}" exited without saving.
58
+ Set one explicitly:
59
+ export EDITOR=nano`};let u=wt(s,"utf8").split(`
60
+ `).filter(c=>!c.startsWith(B)).join(`
61
+ `).trim();return{text:u.length===0?null:u,error:null}}catch(o){return{text:null,error:`Could not open an editor: ${o.message}`}}finally{Tt(t,{recursive:!0,force:!0})}}function Dn(e,n){return e.KADENCE_SOURCE==="agent"?!1:n}function V(e,n){let r=e.sprints.find(g=>g.id===n);if(r===void 0)return null;let t=e.tasks.filter(g=>g.sprint===n),s=t.filter(g=>g.status==="cancelled"),i=t.filter(g=>g.status!=="cancelled"),o=i.filter(g=>g.status==="done"),a=i.filter(g=>g.status!=="done"),d=L(i.map(g=>g.estimate??0)),u=L(o.map(g=>g.estimate??0)),c=o.filter(g=>g.estimate===null),f=o.map(Rt).filter(g=>g!==null),l=f.length>0?L(f):null,p=L(o.filter(g=>g.estimate!==null).map(g=>g.estimate)),m=l!==null&&p>0?l/p:null;return{id:r.id,name:r.name,status:r.status,committed:d,velocity:u,actualHours:l,hoursPerPoint:m,done:o,carriedOver:a,cancelled:s,unestimated:c,loggedHours:L(t.map(g=>g.loggedHours))}}function Rt(e){let n=e.history.find(s=>s.type==="task.moved"&&s.data.to==="in_progress"),r=[...e.history].reverse().find(s=>s.type==="task.moved"&&s.data.to==="done");if(n===void 0||r===void 0)return null;let t=Date.parse(r.ts)-Date.parse(n.ts);return t>0?t/36e5:null}function L(e){return e.reduce((n,r)=>n+r,0)}function J(e){return new Date(e).toISOString().slice(0,10)}function Nt(e,n){let r=[];for(let t=Date.parse(`${e}T00:00:00.000Z`);t<=Date.parse(`${n}T00:00:00.000Z`);t+=864e5)r.push(J(t));return r}function je(e,n,r,t=J(Date.now())){let s=e.tasks.filter(y=>y.sprint===r.id&&y.status!=="cancelled"),i=new Map(s.map(y=>[y.id,y.estimate??0])),o=[...i.values()].reduce((y,C)=>y+C,0),a=n.filter(y=>i.has(y.entity));if(a.length===0)return null;let d=r.startDate??J(a[0].ts),u=r.endDate??J(a.at(-1).ts),c=r.status==="closed"||u<t?u:t;if(c<d)return null;let f=new Set,l=new Map;for(let y of a){let C=J(y.ts);if(C<d)continue;let A=y.type==="task.moved"?y.data?.to:void 0,X=i.get(y.entity)??0;A==="done"&&!f.has(y.entity)?(f.add(y.entity),l.set(C,(l.get(C)??0)+X)):A!==void 0&&A!=="done"&&f.has(y.entity)&&(f.delete(y.entity),l.set(C,(l.get(C)??0)-X))}let p=Nt(d,c),m=Math.max(p.length-1,1),g=o;return{sprintName:r.name,committed:o,finalRemaining:(r.status==="closed",null),days:p.map((y,C)=>{let A=l.get(y)??0;return g-=A,{date:y,remaining:Math.max(0,g),ideal:Math.max(0,o-o/m*C),completed:A}})}}function Ae(e,n=40){if(e.committed===0)return`"${e.sprintName}": nothing to burn down \u2014 no estimated tasks.`;let r=[`"${e.sprintName}" \u2014 ${e.committed} points committed`,""];for(let s of e.days){let i=Math.round(s.remaining/e.committed*n),o=Math.round(s.ideal/e.committed*n),a=[];for(let c=0;c<n;c++)c===o&&c>=i?a.push("\u250A"):c<i?a.push(c===o?"\u2503":"\u2588"):a.push(" ");let d=s.remaining-s.ideal,u=Math.abs(d)<.5?"":d>0?` +${d.toFixed(0)}`:` ${d.toFixed(0)}`;r.push(`${s.date.slice(5)} ${a.join("")} ${String(s.remaining).padStart(3)}${u}`)}let t=e.days.at(-1);return t!==void 0&&(r.push(""),r.push(t.remaining===0?" All committed work is done.":` ${t.remaining} of ${e.committed} points remain.`+(t.remaining>t.ideal?" Behind the ideal line.":" On or ahead of the line."))),r.join(`
62
+ `)}function j(e){return e.sprints.find(n=>n.status==="active")}function Pt(e){return e.sprints.filter(n=>n.status==="planned")}function _(e,n){let r=n.trim().toLowerCase();return e.sprints.find(t=>t.name.toLowerCase()===r)}function F(e,n,r,t){w(e.root,{id:$(),type:n,entity:r,actor:e.actor,ts:new Date().toISOString(),source:e.source,data:t})}function Mn(e,n,r){let t=h(e,n);if(!b(t))return t;let s=r.trim();if(s.length===0)return{ok:!1,exitCode:2,message:"A sprint needs a name."};let{state:i,warnings:o}=k(t.root,t.actor);if(_(i,s)!==void 0)return{ok:!1,exitCode:2,message:`Sprint "${s}" already exists.`};let a=j(i)!==void 0,d=$();return F(t,"sprint.created",d,{name:s}),a||F(t,"sprint.started",d,{}),{ok:!0,exitCode:0,warnings:o,message:a?`Sprint "${s}" planned.
63
+
64
+ kadence sprint add KAD-1 --sprint "${s}"
65
+ kadence sprint start "${s}"`:`Sprint "${s}" started.
66
+
67
+ kadence sprint add KAD-1
68
+ kadence sprint status`,data:{schema:"kadence/v1",ok:!0,sprint:{id:d,name:s,status:a?"planned":"active"}}}}function Bn(e,n,r,t={}){let s=h(e,n);if(!b(s))return s;let{state:i,warnings:o}=k(s.root,s.actor),a=t.sprint===void 0?j(i):_(i,t.sprint);if(a===void 0)return t.sprint===void 0?{ok:!1,exitCode:1,message:`No active sprint.
69
+ kadence sprint create "Sprint 1"`}:{ok:!1,exitCode:1,message:`No sprint named "${t.sprint}".
70
+ kadence sprint list`};if(a.status==="closed")return{ok:!1,exitCode:1,message:`Sprint "${a.name}" is closed \u2014 its velocity is not rewritten.`};let d=T(i,r);if(d===void 0)return{ok:!1,exitCode:1,message:`No task ${r}.
71
+ kadence task list`};if(d.sprint===a.id)return{ok:!0,exitCode:0,warnings:o,message:`${d.label} is already in the sprint.`};F(s,"sprint.task_added",a.id,{task:d.id});let u=d.estimate===null?`
72
+ Without an estimate this task will not count towards velocity.`:"";return{ok:!0,exitCode:0,warnings:o,message:`${d.label} \u2192 "${a.name}"${u}`,data:{schema:"kadence/v1",ok:!0,task:{id:d.id,label:d.label},sprint:a.id}}}function Ln(e,n){let r=h(e,n);if(!b(r))return r;let{state:t,warnings:s}=k(r.root,r.actor),i=j(t);if(i===void 0)return{ok:!1,exitCode:1,message:`No active sprint.
73
+ kadence sprint create "Sprint 1"`};let o=V(t,i.id);F(r,"sprint.closed",i.id,{velocity:o.velocity});let a=[...s];return o.unestimated.length>0&&a.push(`${o.unestimated.length} completed task(s) without an estimate were left out of velocity: `+o.unestimated.map(d=>d.label).join(", ")),{ok:!0,exitCode:0,warnings:a,message:jt(o),data:{schema:"kadence/v1",ok:!0,report:Oe(o)}}}function Jn(e,n){let r=h(e,n);if(!b(r))return r;let{state:t,warnings:s}=k(r.root,r.actor),i=j(t);if(i===void 0)return{ok:!0,exitCode:0,warnings:s,message:`No active sprint.
74
+ kadence sprint create "Sprint 1"`,data:{schema:"kadence/v1",ok:!0,sprint:null}};let o=V(t,i.id),a=[`"${o.name}" \u2014 ${o.velocity} of ${o.committed} points`,"",...o.done.map(d=>` \u2713 ${d.label} ${d.title}`),...o.carriedOver.map(d=>` \xB7 ${d.label} ${d.title} (${d.status})`)];return{ok:!0,exitCode:0,warnings:s,message:a.join(`
75
+ `),data:{schema:"kadence/v1",ok:!0,report:Oe(o)}}}function jt(e){let n=[`Sprint "${e.name}" closed.`,""];if(n.push(` Velocity: ${e.velocity} of ${e.committed} points`),e.hoursPerPoint!==null&&e.actualHours!==null&&e.actualHours>=1/60&&n.push(` Actual: ${z(e.actualHours)} \u2014 ${z(e.hoursPerPoint)} per point`),e.loggedHours>0&&n.push(` Logged: ${z(e.loggedHours)} entered by hand`),e.carriedOver.length>0){n.push("",` Carried over (${e.carriedOver.length}):`);for(let r of e.carriedOver)n.push(` \xB7 ${r.label} ${r.title}`)}return e.cancelled.length>0&&n.push("",` Cancelled (${e.cancelled.length}) \u2014 not counted towards velocity`),n.join(`
76
+ `)}function z(e){return e<1?`${Math.round(e*60)}m`:e<10?`${e.toFixed(1)}h`:`${Math.round(e)}h`}function Oe(e){return{id:e.id,name:e.name,status:e.status,velocity:e.velocity,committed:e.committed,actualHours:e.actualHours,hoursPerPoint:e.hoursPerPoint,done:e.done.map(n=>n.label),carriedOver:e.carriedOver.map(n=>n.label),cancelled:e.cancelled.map(n=>n.label),unestimated:e.unestimated.map(n=>n.label),loggedHours:e.loggedHours}}function Un(e,n,r){let t=h(e,n);if(!b(t))return t;let{state:s,warnings:i}=k(t.root,t.actor),o=j(s);if(o!==void 0)return{ok:!1,exitCode:1,message:`Sprint "${o.name}" is still active.
77
+ Close it so velocity can be computed:
78
+ kadence sprint close`};let a=Pt(s),d=r===void 0?a[0]:_(s,r);return d===void 0?{ok:!1,exitCode:1,message:r===void 0?`No planned sprints.
79
+ kadence sprint create "Sprint 2"`:`No sprint named "${r}".
80
+ kadence sprint list`}:d.status!=="planned"?{ok:!1,exitCode:1,message:`Sprint "${d.name}" is already ${d.status}.`}:(F(t,"sprint.started",d.id,{}),{ok:!0,exitCode:0,warnings:i,message:`Sprint "${d.name}" started.
81
+
82
+ kadence sprint status`,data:{schema:"kadence/v1",ok:!0,sprint:{id:d.id,name:d.name}}})}function Kn(e,n){let r=h(e,n);if(!b(r))return r;let{state:t,warnings:s}=k(r.root,r.actor);if(t.sprints.length===0)return{ok:!0,exitCode:0,warnings:s,message:`No sprints yet.
83
+ kadence sprint create "Sprint 1"`,data:{schema:"kadence/v1",ok:!0,sprints:[]}};let i=t.sprints.map(o=>{let a=t.tasks.filter(u=>u.sprint===o.id),d=a.reduce((u,c)=>u+(c.estimate??0),0);return{sprint:o,tasks:a,points:d}});return{ok:!0,exitCode:0,warnings:s,message:i.map(({sprint:o,tasks:a,points:d})=>{let u=o.status==="active"?"\u2192":" ",c=a.length===0?"":` ${a.length} tasks, ${d} points`;return`${u} ${o.name.padEnd(20)} ${o.status.padEnd(8)}${c}`}).join(`
84
+ `),data:{schema:"kadence/v1",ok:!0,sprints:i.map(({sprint:o,tasks:a,points:d})=>({id:o.id,name:o.name,status:o.status,taskIds:o.taskIds,taskCount:a.length,points:d}))}}}function At(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;let n=new Date(`${e}T00:00:00.000Z`);return!Number.isNaN(n.getTime())&&n.toISOString().slice(0,10)===e}function Hn(e,n,r,t){let s=h(e,n);if(!b(s))return s;for(let[l,p]of[["--start",t.startDate],["--end",t.endDate]])if(p!==void 0&&p!==""&&!At(p))return{ok:!1,exitCode:2,message:`${l} must be YYYY-MM-DD, got "${p}".
85
+ kadence sprint edit --start 2026-09-01`};let{state:i,warnings:o}=k(s.root,s.actor),a=r===void 0?j(i):_(i,r);if(a===void 0)return{ok:!1,exitCode:1,message:r===void 0?`No active sprint.
86
+ kadence sprint list`:`No sprint named "${r}".
87
+ kadence sprint list`};if(a.status==="closed")return{ok:!1,exitCode:1,message:`Sprint "${a.name}" is closed \u2014 its record is not rewritten.`};if(t.name!==void 0&&t.name!==a.name&&_(i,t.name)!==void 0)return{ok:!1,exitCode:2,message:`Sprint "${t.name}" already exists.`};let d=t.startDate??a.startDate??"",u=t.endDate??a.endDate??"";if(d!==""&&u!==""&&u<d)return{ok:!1,exitCode:2,message:`The end date (${u}) is before the start date (${d}).`};let c={},f=[];return t.name!==void 0&&t.name!==a.name&&(c.name=t.name,f.push("name")),t.description!==void 0&&t.description!==(a.description??"")&&(c.description=t.description,f.push("description")),t.startDate!==void 0&&t.startDate!==(a.startDate??"")&&(c.startDate=t.startDate,f.push("start")),t.endDate!==void 0&&t.endDate!==(a.endDate??"")&&(c.endDate=t.endDate,f.push("end")),f.length===0?{ok:!0,exitCode:0,warnings:o,message:`"${a.name}": nothing changed.`}:(F(s,"sprint.updated",a.id,c),{ok:!0,exitCode:0,warnings:o,message:`"${a.name}": updated ${f.join(", ")}.`,data:{schema:"kadence/v1",ok:!0,sprint:{id:a.id,changed:f}}})}function Yn(e,n,r){let t=h(e,n);if(!b(t))return t;let{state:s,warnings:i}=k(t.root,t.actor),o=r===void 0?j(s):_(s,r);if(o===void 0)return{ok:!1,exitCode:1,message:r===void 0?`No active sprint.
88
+ kadence sprint list`:`No sprint named "${r}".
89
+ kadence sprint list`};let a=je(s,I(t.root).events,o);return a===null?{ok:!0,exitCode:0,warnings:i,message:`"${o.name}" has no tasks yet.
90
+ kadence sprint add KAD-1`,data:{schema:"kadence/v1",ok:!0,burndown:null}}:{ok:!0,exitCode:0,warnings:i,message:Ae(a),data:{schema:"kadence/v1",ok:!0,burndown:a}}}export{ce as a,O as b,M as c,w as d,$ as e,Ot as f,Ie as g,D as h,R as i,Z as j,qt as k,H as l,un as m,h as n,b as o,ln as p,k as q,cn as r,pn as s,Re as t,fn as u,gn as v,mn as w,kn as x,yn as y,hn as z,bn as A,xn as B,vn as C,En as D,Dn as E,Mn as F,Bn as G,Ln as H,Jn as I,Un as J,Kn as K,Hn as L,Yn as M};
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import{C as x,D as C,E as h,G as y,H as E,I as A,J as N,M as F,n as b,o as T,p as c,q as l,s as d,u as f,w as u,y as S,z as k}from"./chunk-BUHXYOZ4.js";async function $(r,e){let a=b(r,e);if(!T(a))return a;if(process.stdout.isTTY!==!0)return{ok:!1,exitCode:1,message:`The interactive board needs a terminal.
3
+ For pipes and scripts use:
4
+ kadence board --json`};let g;try{g=await import("./board-7RVHIQJQ.js")}catch(t){return{ok:!1,exitCode:1,message:`The interactive board could not start: ${t.message}
5
+ The plain board always works:
6
+ kadence board`}}return g.runBoardUi({reload:()=>l(a.root,a.actor),move:(t,o)=>s(d(r,e,t,o)),assign:(t,o)=>s(f(r,e,t,o)),create:t=>s(c(r,e,t,{})),remove:t=>s(S(r,e,t)),edit:t=>{if(!h(e,!0))return"No editor available.";let{state:o}=l(a.root,a.actor),m=o.tasks.find(i=>i.id===t);if(m===void 0)return"Task not found.";let n=C(e,m.description??"",`Editing the description of ${m.label}.`);return n.error!==null?n.error:n.text===null?"Aborted \u2014 nothing changed.":s(u(r,e,t,{description:n.text}))},comment:(t,o)=>s(k(r,e,t,o)),setField:(t,o,m)=>{let n=m.trim();if(o==="status")return s(d(r,e,t,n));if(o==="assignee")return s(f(r,e,t,n.length===0?"none":n));if(o==="estimate"){let i=Number(n);return!Number.isFinite(i)||i<0?"Estimate must be a positive number.":s(u(r,e,t,{estimate:i}))}if(o==="labels"){let i=n.split(",").map(p=>p.trim()).filter(p=>p.length>0);return s(u(r,e,t,{labels:i}))}return s(u(r,e,t,{[o]:n}))},logTime:(t,o)=>s(x(r,e,t,o)),setPriority:(t,o)=>s(u(r,e,t,{priority:o})),addToSprint:t=>s(y(r,e,t,{})),sprintStatus:()=>A(r,e).message,burndown:()=>F(r,e,void 0).message,sprintStart:()=>s(N(r,e,void 0)),sprintClose:()=>s(E(r,e))}),{ok:!0,exitCode:0,message:""}}function s(r){return r.message.split(`
7
+ `)[0]??""}export{$ as runUi};
package/dist/cli.js ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ import{A as se,B as ae,C as T,D as ie,E as re,F as oe,G as de,H as ce,I as le,J as ue,K as me,L as fe,M as pe,a as F,b as U,c as $,d as A,e as g,f as E,g as q,h as W,i as P,j as Y,k as G,l as V,m as S,n as k,o as b,p as J,q as y,r as H,s as z,t as Q,u as X,v as O,w as Z,x as ee,y as te,z as ne}from"./chunks/chunk-BUHXYOZ4.js";function K(n){return n==null?[]:Array.isArray(n)?n:[n]}function _e(n,t,s,e){var a,i=n[t],r=~e.string.indexOf(t)?s==null||s===!0?"":String(s):typeof s=="boolean"?s:~e.boolean.indexOf(t)?s==="false"?!1:s==="true"||(n._.push((a=+s,a*0===0?a:s)),!!s):(a=+s,a*0===0?a:s);n[t]=i==null?r:Array.isArray(i)?i.concat(r):[i,r]}function Be(n,t){n=n||[],t=t||{};var s,e,a,i,r,d={_:[]},o=0,l=0,u=0,m=n.length;let p=t.alias!==void 0,D=t.unknown!==void 0,M=t.default!==void 0;if(t.alias=t.alias||{},t.string=K(t.string),t.boolean=K(t.boolean),p)for(s in t.alias)for(e=t.alias[s]=K(t.alias[s]),o=0;o<e.length;o++)(t.alias[e[o]]=e.concat(s)).splice(o,1);for(o=t.boolean.length;o-- >0;)for(e=t.alias[t.boolean[o]]||[],l=e.length;l-- >0;)t.boolean.push(e[l]);for(o=t.string.length;o-- >0;)for(e=t.alias[t.string[o]]||[],l=e.length;l-- >0;)t.string.push(e[l]);if(M){for(s in t.default)if(i=typeof t.default[s],e=t.alias[s]=t.alias[s]||[],t[i]!==void 0)for(t[i].push(s),o=0;o<e.length;o++)t[i].push(e[o])}let L=D?Object.keys(t.alias):[];for(o=0;o<m;o++){if(a=n[o],a==="--"){d._=d._.concat(n.slice(++o));break}for(l=0;l<a.length&&a.charCodeAt(l)===45;l++);if(l===0)d._.push(a);else if(a.substring(l,l+3)==="no-"){if(i=a.substring(l+3),D&&!~L.indexOf(i))return t.unknown(a);d[i]=!1}else{for(u=l+1;u<a.length&&a.charCodeAt(u)!==61;u++);for(i=a.substring(l,u),r=a.substring(++u)||o+1===m||(""+n[o+1]).charCodeAt(0)===45||n[++o],e=l===2?[i]:i,u=0;u<e.length;u++){if(i=e[u],D&&!~L.indexOf(i))return t.unknown("-".repeat(l)+i);_e(d,i,u+1<e.length||r,t)}}}if(M)for(s in t.default)d[s]===void 0&&(d[s]=t.default[s]);if(p)for(s in d)for(e=t.alias[s]||[];e.length>0;)d[e.shift()]=d[s];return d}function ke(n){return n.replace(/[<[].+/,"").trim()}function Me(n){let t=/<([^>]+)>/g,s=/\[([^\]]+)\]/g,e=[],a=d=>{let o=!1,l=d[1];return l.startsWith("...")&&(l=l.slice(3),o=!0),{required:d[0].startsWith("<"),value:l,variadic:o}},i;for(;i=t.exec(n);)e.push(a(i));let r;for(;r=s.exec(n);)e.push(a(r));return e}function Le(n){let t={alias:{},boolean:[]};for(let[s,e]of n.entries())e.names.length>1&&(t.alias[e.names[0]]=e.names.slice(1)),e.isBoolean&&(e.negated&&n.some((a,i)=>i!==s&&a.names.some(r=>e.names.includes(r))&&typeof a.required=="boolean")||t.boolean.push(e.names[0]));return t}function he(n){return n.sort((t,s)=>t.length>s.length?-1:1)[0]}function ge(n,t){return n.length>=t?n:`${n}${" ".repeat(t-n.length)}`}function Fe(n){return n.replaceAll(/([a-z])-([a-z])/g,(t,s,e)=>s+e.toUpperCase())}function Ue(n,t,s){let e=n;for(let a=0;a<t.length;a++){let i=t[a];if(a===t.length-1){e[i]=s;return}if(e[i]==null){let r=+t[a+1]>-1;e[i]=r?[]:{}}e=e[i]}}function qe(n,t){for(let s of Object.keys(t)){let e=t[s];e.shouldTransform&&(n[s]=[n[s]].flat(),typeof e.transformFunction=="function"&&(n[s]=n[s].map(e.transformFunction)))}}function We(n){let t=/([^\\/]+)$/.exec(n);return t?t[1]:""}function be(n){return n.split(".").map((t,s)=>s===0?Fe(t):t).join(".")}var x=class extends Error{constructor(n){super(n),this.name="CACError",typeof Error.captureStackTrace!="function"&&(this.stack=new Error(n).stack)}},Pe=class{rawName;description;name;names;isBoolean;required;config;negated;constructor(n,t,s){this.rawName=n,this.description=t,this.config=Object.assign({},s),n=n.replaceAll(".*",""),this.negated=!1,this.names=ke(n).split(",").map(e=>{let a=e.trim().replace(/^-{1,2}/,"");return a.startsWith("no-")&&(this.negated=!0,a=a.replace(/^no-/,"")),be(a)}).sort((e,a)=>e.length>a.length?1:-1),this.name=this.names.at(-1),this.negated&&this.config.default==null&&(this.config.default=!0),n.includes("<")?this.required=!0:n.includes("[")?this.required=!1:this.isBoolean=!0}},j,w;if(typeof process<"u"){let n;typeof Deno<"u"&&typeof Deno.version?.deno=="string"?n="deno":typeof Bun<"u"&&typeof Bun.version=="string"?n="bun":n="node",w=`${process.platform}-${process.arch} ${n}-${process.version}`,j=process.argv}else typeof navigator>"u"?w="unknown":w=`${navigator.platform} ${navigator.userAgent}`;var ye=class{rawName;description;config;cli;options;aliasNames;name;args;commandAction;usageText;versionNumber;examples;helpCallback;globalCommand;constructor(n,t,s={},e){this.rawName=n,this.description=t,this.config=s,this.cli=e,this.options=[],this.aliasNames=[],this.name=ke(n),this.args=Me(n),this.examples=[]}usage(n){return this.usageText=n,this}allowUnknownOptions(){return this.config.allowUnknownOptions=!0,this}ignoreOptionDefaultValue(){return this.config.ignoreOptionDefaultValue=!0,this}version(n,t="-v, --version"){return this.versionNumber=n,this.option(t,"Display version number"),this}example(n){return this.examples.push(n),this}option(n,t,s){let e=new Pe(n,t,s);return this.options.push(e),this}alias(n){return this.aliasNames.push(n),this}action(n){return this.commandAction=n,this}isMatched(n){return this.name===n||this.aliasNames.includes(n)}get isDefaultCommand(){return this.name===""||this.aliasNames.includes("!")}get isGlobalCommand(){return this instanceof ve}hasOption(n){return n=n.split(".")[0],this.options.find(t=>t.names.includes(n))}outputHelp(){let{name:n,commands:t}=this.cli,{versionNumber:s,options:e,helpCallback:a}=this.cli.globalCommand,i=[{body:`${n}${s?`/${s}`:""}`}];if(i.push({title:"Usage",body:` $ ${n} ${this.usageText||this.rawName}`}),(this.isGlobalCommand||this.isDefaultCommand)&&t.length>0){let d=he(t.map(o=>o.rawName));i.push({title:"Commands",body:t.map(o=>` ${ge(o.rawName,d.length)} ${o.description}`).join(`
3
+ `)},{title:"For more info, run any command with the `--help` flag",body:t.map(o=>` $ ${n}${o.name===""?"":` ${o.name}`} --help`).join(`
4
+ `)})}let r=this.isGlobalCommand?e:[...this.options,...e||[]];if(!this.isGlobalCommand&&!this.isDefaultCommand&&(r=r.filter(d=>d.name!=="version")),r.length>0){let d=he(r.map(o=>o.rawName));i.push({title:"Options",body:r.map(o=>` ${ge(o.rawName,d.length)} ${o.description} ${o.config.default===void 0?"":`(default: ${o.config.default})`}`).join(`
5
+ `)})}this.examples.length>0&&i.push({title:"Examples",body:this.examples.map(d=>typeof d=="function"?d(n):d).join(`
6
+ `)}),a&&(i=a(i)||i),console.info(i.map(d=>d.title?`${d.title}:
7
+ ${d.body}`:d.body).join(`
8
+
9
+ `))}outputVersion(){let{name:n}=this.cli,{versionNumber:t}=this.cli.globalCommand;t&&console.info(`${n}/${t} ${w}`)}checkRequiredArgs(){let n=this.args.filter(t=>t.required).length;if(this.cli.args.length<n)throw new x(`missing required args for command \`${this.rawName}\``)}checkUnknownOptions(){let{options:n,globalCommand:t}=this.cli;if(!this.config.allowUnknownOptions){for(let s of Object.keys(n))if(s!=="--"&&!this.hasOption(s)&&!t.hasOption(s))throw new x(`Unknown option \`${s.length>1?`--${s}`:`-${s}`}\``)}}checkOptionValue(){let{options:n,globalCommand:t}=this.cli,s=[...t.options,...this.options];for(let e of s){let a=n[e.name.split(".")[0]];if(e.required){let i=s.some(r=>r.negated&&r.names.includes(e.name));if(a===!0||a===!1&&!i)throw new x(`option \`${e.rawName}\` value is missing`)}}}checkUnusedArgs(){let n=this.args.some(t=>t.variadic)?1/0:this.args.length;if(n<this.cli.args.length)throw new x(`Unused args: ${this.cli.args.slice(n).map(t=>`\`${t}\``).join(", ")}`)}},ve=class extends ye{constructor(n){super("@@global@@","",{},n)}},Ye=class extends EventTarget{name;commands;globalCommand;matchedCommand;matchedCommandName;rawArgs;args;options;showHelpOnExit;showVersionOnExit;constructor(n=""){super(),this.name=n,this.commands=[],this.rawArgs=[],this.args=[],this.options={},this.globalCommand=new ve(this),this.globalCommand.usage("<command> [options]")}usage(n){return this.globalCommand.usage(n),this}command(n,t,s){let e=new ye(n,t||"",s,this);return e.globalCommand=this.globalCommand,this.commands.push(e),e}option(n,t,s){return this.globalCommand.option(n,t,s),this}help(n){return this.globalCommand.option("-h, --help","Display this message"),this.globalCommand.helpCallback=n,this.showHelpOnExit=!0,this}version(n,t="-v, --version"){return this.globalCommand.version(n,t),this.showVersionOnExit=!0,this}example(n){return this.globalCommand.example(n),this}outputHelp(){this.matchedCommand?this.matchedCommand.outputHelp():this.globalCommand.outputHelp()}outputVersion(){this.globalCommand.outputVersion()}setParsedInfo({args:n,options:t},s,e){return this.args=n,this.options=t,s&&(this.matchedCommand=s),e&&(this.matchedCommandName=e),this}unsetMatchedCommand(){this.matchedCommand=void 0,this.matchedCommandName=void 0}parse(n,{run:t=!0}={}){if(!n){if(!j)throw new Error("No argv provided and runtime process argv is not available.");n=j}this.rawArgs=n,this.name||(this.name=n[1]?We(n[1]):"cli");let s=!0;for(let a of this.commands){let i=this.mri(n.slice(2),a),r=i.args[0];if(a.isMatched(r)){s=!1;let d={...i,args:i.args.slice(1)};this.setParsedInfo(d,a,r),this.dispatchEvent(new CustomEvent(`command:${r}`,{detail:a}))}}if(s){for(let a of this.commands)if(a.isDefaultCommand){s=!1;let i=this.mri(n.slice(2),a);this.setParsedInfo(i,a),this.dispatchEvent(new CustomEvent("command:!",{detail:a}))}}if(s){let a=this.mri(n.slice(2));this.setParsedInfo(a)}this.options.help&&this.showHelpOnExit&&(this.outputHelp(),t=!1,this.unsetMatchedCommand()),this.options.version&&this.showVersionOnExit&&this.matchedCommandName==null&&(this.outputVersion(),t=!1,this.unsetMatchedCommand());let e={args:this.args,options:this.options};return t&&this.runMatchedCommand(),!this.matchedCommand&&this.args[0]&&this.dispatchEvent(new CustomEvent("command:*",{detail:this.args[0]})),e}mri(n,t){let s=[...this.globalCommand.options,...t?t.options:[]],e=Le(s),a=[],i=n.indexOf("--");i!==-1&&(a=n.slice(i+1),n=n.slice(0,i));let r=Be(n,e);r=Object.keys(r).reduce((m,p)=>({...m,[be(p)]:r[p]}),{_:[]});let d=r._,o={"--":a},l=t&&t.config.ignoreOptionDefaultValue?t.config.ignoreOptionDefaultValue:this.globalCommand.config.ignoreOptionDefaultValue,u=Object.create(null);for(let m of s){if(!l&&m.config.default!==void 0)for(let p of m.names)o[p]=m.config.default;Array.isArray(m.config.type)&&u[m.name]===void 0&&(u[m.name]=Object.create(null),u[m.name].shouldTransform=!0,u[m.name].transformFunction=m.config.type[0])}for(let m of Object.keys(r))m!=="_"&&(Ue(o,m.split("."),r[m]),qe(o,u));return{args:d,options:o}}runMatchedCommand(){let{args:n,options:t,matchedCommand:s}=this;if(!s||!s.commandAction)return;s.checkUnknownOptions(),s.checkOptionValue(),s.checkRequiredArgs(),s.checkUnusedArgs();let e=[];return s.args.forEach((a,i)=>{a.variadic?e.push(n.slice(i)):e.push(n[i])}),e.push(t),s.commandAction.apply(this,e)}},Ae=(n="")=>new Ye(n);import{existsSync as C,mkdirSync as Ge,readFileSync as $e,writeFileSync as I}from"node:fs";import{join as _}from"node:path";var xe=`# kadence \u2014 for AI agents
10
+
11
+ This project's tasks live here as plain files. Read them directly, or through
12
+ the CLI. No server required.
13
+
14
+ ## Commands
15
+
16
+ kadence board --json the whole board
17
+ kadence task list --json all tasks
18
+ kadence task show KAD-42 --json one task with its history
19
+ kadence task add "title" -d "..." --type bug --estimate 3
20
+ kadence task move KAD-42 in_progress
21
+ kadence task assign KAD-42 you@example.com
22
+ kadence sprint status --json current sprint progress
23
+
24
+ ## JSON contract
25
+
26
+ Every \`--json\` response carries \`schema: "kadence/v1"\`. stdout holds JSON and
27
+ nothing else; warnings go to stderr. Exit codes: 0 success, 1 runtime error,
28
+ 2 bad arguments.
29
+
30
+ ## Working as an agent
31
+
32
+ Set \`KADENCE_SOURCE=agent\` so events record your authorship. Without it an
33
+ event is marked as human \u2014 we do not guess.
34
+
35
+ ## What not to do
36
+
37
+ Do not hand-edit files under \`.kadence/events/\`: the journal is appended to,
38
+ never modified. To correct the state, add a new event through the CLI.
39
+ `,we="<!-- kadence:begin -->",R="<!-- kadence:end -->",N=`${we}
40
+ ## Project tasks \u2014 kadence
41
+
42
+ Tasks live in \`.kadence/\` as plain files. Read them directly or via the CLI:
43
+
44
+ kadence board --json the whole board
45
+ kadence task list --json all tasks
46
+ kadence task move KAD-1 done change state
47
+
48
+ \`--json\` responses carry \`schema: "kadence/v1"\`; stdout is JSON only.
49
+ When acting as an agent, set \`KADENCE_SOURCE=agent\`.
50
+
51
+ Details: \`.kadence/README.md\`
52
+ ${R}`;function Ce(n){if(n===null||n.trim().length===0)return`${N}
53
+ `;let t=n.indexOf(we),s=n.indexOf(R);if(t!==-1&&s!==-1&&s>t){let a=n.slice(0,t),i=n.slice(s+R.length);return`${a}${N}${i}`}let e=n.endsWith(`
54
+ `)?`
55
+ `:`
56
+
57
+ `;return`${n}${e}${N}
58
+ `}var De=".kadence/state.json";function Ee(n){let t=F(n);if(t===null)return{ok:!1,alreadyInitialized:!1,root:null,message:`kadence lives inside a git repository, and there is none here.
59
+ Create one and try again:
60
+ git init`};let s=C($(t));Ge($(t),{recursive:!0}),Ve(t);let e=_(U(t),"README.md");return C(e)||I(e,xe,"utf8"),Je(t),{ok:!0,alreadyInitialized:s,root:t,message:s?"kadence is already initialised.":`kadence is ready.
61
+
62
+ kadence task add "first task"
63
+ kadence board
64
+
65
+ Files were created but not committed \u2014 that call is yours.`}}function Ve(n){let t=_(n,".gitignore"),s="";if(C(t)&&(s=$e(t,"utf8")),s.includes(De))return;let e=s.length>0&&!s.endsWith(`
66
+ `)?`
67
+ `:"";I(t,`${s}${e}${De}
68
+ `,"utf8")}function Je(n){let t=_(n,"AGENTS.md"),s=C(t)?$e(t,"utf8"):null,e=Ce(s);e!==s&&I(t,e,"utf8")}var B="cancelled";function Se(n,t,s){let e=k(n,t);if(!b(e))return e;let{state:a,warnings:i}=y(e.root,e.actor),r=a.tasks.filter(u=>u.status!==B);if(s.assignee!==void 0){let u=s.assignee.toLowerCase(),m=u==="me"?e.actor.toLowerCase():u;r=r.filter(p=>(p.assignee??"").toLowerCase()===m)}if(s.sprint==="active"){let u=a.sprints.find(m=>m.status==="active"||m.status==="planned");r=u===void 0?[]:r.filter(m=>m.sprint===u.id)}let d={};for(let u of a.statuses)u!==B&&(d[u]=r.filter(m=>m.status===u));let o=a.orphanStatuses.filter(u=>u!==B);for(let u of o)d[u]=r.filter(m=>m.status===u);let l=o.length>0?[`Statuses not in the board configuration: ${o.join(", ")}.
69
+ Tasks there are still shown. Add the column or move them:
70
+ kadence board config --statuses "..."`]:[];return{ok:!0,exitCode:0,warnings:[...i,...l],message:G(d,Y(t,process.stdout.isTTY===!0)),data:{schema:"kadence/v1",ok:!0,columns:Object.fromEntries(Object.entries(d).map(([u,m])=>[u,m.map(Q)]))}}}function Oe(n,t,s){let e=k(n,t);if(!b(e))return e;let{state:a,warnings:i}=y(e.root,e.actor);if(s===void 0)return{ok:!0,exitCode:0,warnings:i,message:`Board columns: ${a.statuses.join(", ")}
71
+
72
+ Change them with:
73
+ kadence board config --statuses "todo,doing,review,done"`,data:{schema:"kadence/v1",ok:!0,statuses:a.statuses}};let r=s.split(",").map(l=>l.trim().toLowerCase().replace(/\s+/g,"_")).filter(l=>l.length>0);if(r.length===0)return{ok:!1,exitCode:2,message:"At least one status is required."};if(new Set(r).size!==r.length)return{ok:!1,exitCode:2,message:"The same status is listed twice."};if(!r.includes(E))return{ok:!1,exitCode:2,message:`The list must include "${E}" \u2014 velocity and burndown are computed from it.`};let d=a.tasks.filter(l=>!r.includes(l.status)&&l.status!==q);A(e.root,{id:g(),type:"board.configured",entity:g(),actor:e.actor,ts:new Date().toISOString(),source:e.source,data:{statuses:r}});let o=d.length>0?`
74
+ ${d.length} task(s) remain in removed columns: ${[...new Set(d.map(l=>l.status))].join(", ")}. They are still listed.`:"";return{ok:!0,exitCode:0,warnings:i,message:`Board columns: ${r.join(", ")}${o}`,data:{schema:"kadence/v1",ok:!0,statuses:r}}}var He=["description","type","priority","estimate","labels","assignee"];function Te(n,t,s,e){let a=k(n,t);if(!b(a))return a;let i=s.trim();if(i.length===0)return{ok:!1,exitCode:2,message:"A template needs a name."};let r={};for(let d of He)e[d]!==void 0&&(r[d]=e[d]);return Object.keys(r).length===0?{ok:!1,exitCode:2,message:`A template needs at least one field.
75
+ kadence template save bug --type bug --priority high --label triage`}:(A(a.root,{id:g(),type:"template.saved",entity:g(),actor:a.actor,ts:new Date().toISOString(),source:a.source,data:{name:i,fields:r}}),{ok:!0,exitCode:0,message:`Template "${i}" saved: ${Object.keys(r).join(", ")}.
76
+ kadence task add "title" --template ${i}`,data:{schema:"kadence/v1",ok:!0,template:{name:i,fields:r}}})}function Ke(n,t){let s=k(n,t);if(!b(s))return s;let{state:e,warnings:a}=y(s.root,s.actor);return e.templates.length===0?{ok:!0,exitCode:0,warnings:a,message:`No templates yet.
77
+ kadence template save bug --type bug --priority high`,data:{schema:"kadence/v1",ok:!0,templates:[]}}:{ok:!0,exitCode:0,warnings:a,message:e.templates.map(i=>{let r=Object.entries(i.fields).map(([d,o])=>`${d}=${Array.isArray(o)?o.join("/"):String(o)}`).join(" ");return` ${i.name.padEnd(14)} ${r}`}).join(`
78
+ `),data:{schema:"kadence/v1",ok:!0,templates:e.templates}}}function je(n,t,s){let e=k(n,t);if(!b(e))return e;let{state:a,warnings:i}=y(e.root,e.actor);return a.templates.some(r=>r.name===s)?(A(e.root,{id:g(),type:"template.deleted",entity:g(),actor:e.actor,ts:new Date().toISOString(),source:e.source,data:{name:s}}),{ok:!0,exitCode:0,warnings:i,message:`Template "${s}" deleted.`}):{ok:!1,exitCode:1,message:`No template "${s}".
79
+ kadence template list`}}function Ne(n,t,s){let e=k(n,t);if(!b(e))return{error:e};let{state:a}=y(e.root,e.actor),i=a.templates.find(r=>r.name===s);if(i===void 0){let r=a.templates.map(d=>d.name).join(", ");return{error:{ok:!1,exitCode:1,message:`No template "${s}".`+(r.length>0?`
80
+ Available: ${r}`:`
81
+ kadence template save ...`)}}}return{fields:i.fields}}var h=Ae("kadence");function c(n,t){for(let s of n.warnings??[])process.stderr.write(`${s}
82
+ `);if(t){let s=n.data??{schema:"kadence/v1",ok:n.ok,...n.ok?{}:{error:{message:n.message}}};process.stdout.write(`${JSON.stringify(s)}
83
+ `)}else(n.ok?process.stdout:process.stderr).write(`${n.message}
84
+ `);process.exit(n.exitCode)}function Re(n,t,s,e){if(n!==void 0)return n;re(process.env,process.stdout.isTTY===!0)||c(f(`No terminal available for an editor.
85
+ Pass the text directly:
86
+ --description "..."`),e);let a=ie(process.env,t,s);return a.error!==null&&c({ok:!1,exitCode:1,message:a.error},e),a.text===null&&c({ok:!0,exitCode:0,message:"Aborted \u2014 nothing changed."},e),a.text}function f(n){return{ok:!1,exitCode:2,message:n}}h.command("init","Set up kadence in this repository").example(" kadence init").action(()=>{let n=Ee(process.cwd());c({ok:n.ok,message:n.message,exitCode:n.ok?0:1},!1)});h.command("task [action] [arg] [value]","Tasks: add | list | show | move | assign").option("--title <text>","New title (for edit)").option("-d, --description <text>","Full description; use quotes for multiple lines").option("--type <type>",`Type: ${W.join(" | ")}`).option("--priority <level>",`Priority: ${P.join(" | ")}`).option("-a, --assignee <who>","Assignee, e.g. dev@example.com").option("--label <name>","Label; repeat the flag for several").option("--estimate <points>","Estimate in points, a positive number").option("--due <date>","Due date, YYYY-MM-DD; empty string clears it").option("--status <status>",`Filter by status: ${S.join(" | ")}`).option("--search <text>","Search title, description and comments").option("--overdue","Only tasks past their due date").option("--due-before <date>","Only tasks due before YYYY-MM-DD").option("--sort <key>",`Sort by: ${V.join(" | ")}`).option("--tree","Show parent/child structure").option("--parent <task>",'Parent task, e.g. KAD-1 (use "none" to detach)').option("--template <name>","Pre-fill fields from a saved template").option("--json","Machine-readable output for agents").example(' kadence task add "Fix login" -d "Broken since 2.3" --type bug --priority high --estimate 3').example(" kadence task list --status in_progress --sort priority").example(" kadence task list --search cookie --overdue").example(" kadence task list --assignee me --label auth").example(" kadence task list --tree").example(" kadence task move KAD-1,KAD-2,KAD-3 done bulk: all or nothing").example(' kadence task add "Login form" --parent KAD-1 KAD-1 can be an epic').example(" kadence task parent KAD-2 KAD-1").example(" kadence task block KAD-2 KAD-1 KAD-2 waits for KAD-1").example(" kadence task unblock KAD-2 KAD-1").example(" kadence task log KAD-1 2h also 90m, or -30m to correct").example(' kadence task add "Crash on save" --template bug').example(" kadence task show KAD-1").example(" kadence task move KAD-1 done").example(" kadence task edit KAD-1 --priority urgent --due 2026-09-30").example(" kadence task edit KAD-1 opens $EDITOR for the description").example(' kadence task comment KAD-1 "Needs review"').example(' kadence task assign KAD-1 dev@example.com (use "none" to unassign)').example(" kadence task cancel KAD-1 keeps it in history").example(" kadence task delete KAD-1 drops it from the board").action((n,t,s,e)=>{let a=e.json===!0,i=process.cwd();switch(n===void 0&&c(f(`Which action?
87
+ kadence task add "Fix login"
88
+ kadence task list
89
+ kadence task show KAD-1
90
+ kadence task edit KAD-1
91
+ kadence task move KAD-1 done
92
+ kadence task assign KAD-1 dev@example.com
93
+ kadence task comment KAD-1 "text"
94
+ kadence task cancel KAD-1
95
+ kadence task delete KAD-1`),a),n){case"add":{t===void 0&&c(f(`A title is required:
96
+ kadence task add "Fix login"`),a);let r=e.estimate===void 0?void 0:Number(e.estimate);r!==void 0&&(!Number.isFinite(r)||r<0)&&c(f(`Estimate must be a positive number, got "${e.estimate}".
97
+ kadence task add "Fix login" --estimate 3`),a);let d={};if(e.template!==void 0){let l=Ne(i,process.env,e.template);"error"in l?c(l.error,a):d=l.fields}let o=e.label===void 0?void 0:Array.isArray(e.label)?e.label:[e.label];c(J(i,process.env,t,{...d,...e.description!==void 0?{description:e.description}:{},...e.type!==void 0?{type:e.type}:{},...e.priority!==void 0?{priority:e.priority}:{},...e.assignee!==void 0?{assignee:e.assignee}:{},...o!==void 0?{labels:o}:{},...e.due!==void 0?{due:e.due}:{},...e.parent!==void 0?{parent:e.parent}:{},...r!==void 0?{estimate:r}:{}}),a);break}case"log":(t===void 0||s===void 0)&&c(f(`A task and a duration are required:
98
+ kadence task log KAD-1 2h
99
+ kadence task log KAD-1 90m`),a),c(T(i,process.env,t,s),a);break;case"parent":(t===void 0||s===void 0)&&c(f(`A task and a parent are required:
100
+ kadence task parent KAD-2 KAD-1
101
+ kadence task parent KAD-2 none to detach`),a),c(se(i,process.env,t,s),a);break;case"block":case"unblock":(t===void 0||s===void 0)&&c(f(`A task and a blocker are required:
102
+ kadence task block KAD-2 KAD-1 KAD-2 waits for KAD-1
103
+ kadence task unblock KAD-2 KAD-1`),a),c(ae(i,process.env,t,s,n==="unblock"),a);break;case"edit":{t===void 0&&c(f(`Which task?
104
+ kadence task edit KAD-1 --priority high`),a);let r=e.estimate===void 0?void 0:Number(e.estimate);r!==void 0&&(!Number.isFinite(r)||r<0)&&c(f(`Estimate must be a positive number, got "${e.estimate}".`),a);let d=e.label===void 0?void 0:Array.isArray(e.label)?e.label:[e.label],o=e.title!==void 0||e.description!==void 0||e.type!==void 0||e.priority!==void 0||e.due!==void 0||r!==void 0||d!==void 0||s!==void 0,l=e.description;if(!o){let u=O(i,process.env,t);u.ok||c(u,a);let m=u.data.task??{description:null};l=Re(void 0,m.description??"",`Editing the description of ${t}.`,a)}c(Z(i,process.env,t,{...e.title!==void 0?{title:e.title}:s!==void 0?{title:s}:{},...l!==void 0?{description:l}:{},...e.type!==void 0?{type:e.type}:{},...e.priority!==void 0?{priority:e.priority}:{},...e.due!==void 0?{due:e.due}:{},...r!==void 0?{estimate:r}:{},...d!==void 0?{labels:d}:{}}),a);break}case"comment":{t===void 0&&c(f(`Which task?
105
+ kadence task comment KAD-1 "text"`),a);let r=Re(s,"",`Comment on ${t}.`,a);c(ne(i,process.env,t,r??""),a);break}case"cancel":t===void 0&&c(f(`Which task?
106
+ kadence task cancel KAD-1`),a),c(ee(i,process.env,t),a);break;case"delete":t===void 0&&c(f(`Which task?
107
+ kadence task delete KAD-1`),a),c(te(i,process.env,t),a);break;case"list":c(H(i,process.env,{...e.status!==void 0?{status:e.status}:{},...e.search!==void 0?{search:e.search}:{},...e.type!==void 0?{type:e.type}:{},...e.priority!==void 0?{priority:e.priority}:{},...e.assignee!==void 0?{assignee:e.assignee}:{},...e.label!==void 0?{label:Array.isArray(e.label)?e.label.at(-1):e.label}:{},...e.overdue===!0?{overdue:!0}:{},...e.dueBefore!==void 0?{dueBefore:e.dueBefore}:{},...e.sort!==void 0?{sort:e.sort}:{},...e.tree===!0?{tree:!0}:{}}),a);break;case"show":t===void 0&&c(f(`Which task?
108
+ kadence task show KAD-1`),a),c(O(i,process.env,t),a);break;case"move":(t===void 0||s===void 0)&&c(f(`A task and a target status are required:
109
+ kadence task move KAD-1 done
110
+ Statuses: ${S.join(", ")}`),a),c(z(i,process.env,t,s),a);break;case"assign":(t===void 0||s===void 0)&&c(f(`A task and an assignee are required:
111
+ kadence task assign KAD-1 dev@example.com
112
+ kadence task assign KAD-1 none to unassign`),a),c(X(i,process.env,t,s),a);break;default:c(f(`Unknown action "${n}".
113
+ Available: add, list, show, edit, move, assign, comment, log,
114
+ parent, block, unblock, cancel, delete
115
+ kadence task --help`),a)}});h.command("board [action]",'Kanban board in the terminal; "config" edits the columns').option("--statuses <list>",'Comma-separated columns, e.g. "todo,doing,done"').option("-a, --assignee <who>",`Only this person's tasks; "me" means you`).option("--sprint","Only tasks in the active sprint").option("--json","Machine-readable output for agents").example(" kadence board").example(" kadence board --assignee me --sprint").example(" kadence board config").example(' kadence board config --statuses "todo,doing,review,done"').action((n,t)=>{n==="config"&&c(Oe(process.cwd(),process.env,t.statuses),t.json===!0),n!==void 0&&c(f(`Unknown action "${n}".
116
+ Available: config
117
+ kadence board --help`),t.json===!0),c(Se(process.cwd(),process.env,{...t.assignee!==void 0?{assignee:t.assignee}:{},...t.sprint===!0?{sprint:"active"}:{}}),t.json===!0)});h.command("sprint [action] [name]","Sprints: create | add | edit | start | close | status | list | burndown").option("--sprint <name>","Which sprint to add to; defaults to the active one").option("--name <name>","New name (for edit)").option("-d, --description <text>","Sprint description (for edit)").option("--start <date>","Start date, YYYY-MM-DD").option("--end <date>","End date, YYYY-MM-DD").option("--json","Machine-readable output for agents").example(' kadence sprint create "Sprint 1" first one starts right away').example(' kadence sprint create "Sprint 2" later ones are planned').example(' kadence sprint add KAD-1 --sprint "Sprint 2"').example(" kadence sprint start starts the next planned sprint").example(" kadence sprint edit --start 2026-09-01 --end 2026-09-14").example(' kadence sprint edit "Sprint 2" --name "Sprint 2: auth"').example(" kadence sprint burndown chart from the journal, any day").example(" kadence sprint close closes the active one, reports velocity").action((n,t,s)=>{let e=s.json===!0,a=process.cwd();switch(n===void 0&&c(f(`Which action?
118
+ kadence sprint create "Sprint 1"
119
+ kadence sprint add KAD-1
120
+ kadence sprint edit --start 2026-09-01
121
+ kadence sprint start
122
+ kadence sprint close
123
+ kadence sprint status
124
+ kadence sprint list`),e),n){case"create":t===void 0&&c(f(`A sprint name is required:
125
+ kadence sprint create "Sprint 1"`),e),c(oe(a,process.env,t),e);break;case"add":t===void 0&&c(f(`Which task?
126
+ kadence sprint add KAD-1
127
+ kadence sprint add KAD-1 --sprint "Sprint 2"`),e),c(de(a,process.env,t,s.sprint===void 0?{}:{sprint:s.sprint}),e);break;case"edit":c(fe(a,process.env,t,{...s.name!==void 0?{name:s.name}:{},...s.description!==void 0?{description:s.description}:{},...s.start!==void 0?{startDate:s.start}:{},...s.end!==void 0?{endDate:s.end}:{}}),e);break;case"start":c(ue(a,process.env,t),e);break;case"close":c(ce(a,process.env),e);break;case"status":c(le(a,process.env),e);break;case"list":c(me(a,process.env),e);break;case"burndown":c(pe(a,process.env,t),e);break;default:c(f(`Unknown action "${n}".
128
+ Available: create, add, edit, start, close, status, list, burndown
129
+ kadence sprint --help`),e)}});h.command("template [action] [name]","Task templates: save | list | delete").option("-d, --description <text>","Default description").option("--type <type>","Default type").option("--priority <level>","Default priority").option("-a, --assignee <who>","Default assignee").option("--label <name>","Default label; repeat for several").option("--estimate <points>","Default estimate").option("--json","Machine-readable output for agents").example(" kadence template save bug --type bug --priority high --label triage").example(" kadence template list").action((n,t,s)=>{let e=s.json===!0,a=process.cwd();switch(n){case"save":{t===void 0&&c(f(`A template name is required:
130
+ kadence template save bug --type bug`),e);let i=s.label===void 0?void 0:Array.isArray(s.label)?s.label:[s.label];c(Te(a,process.env,t,{...s.description!==void 0?{description:s.description}:{},...s.type!==void 0?{type:s.type}:{},...s.priority!==void 0?{priority:s.priority}:{},...s.assignee!==void 0?{assignee:s.assignee}:{},...i!==void 0?{labels:i}:{},...s.estimate!==void 0?{estimate:Number(s.estimate)}:{}}),e);break}case"list":case void 0:c(Ke(a,process.env),e);break;case"delete":t===void 0&&c(f(`Which template?
131
+ kadence template delete bug`),e),c(je(a,process.env,t),e);break;default:c(f(`Unknown action "${n}".
132
+ Available: save, list, delete`),e)}});h.command("ui","Interactive kanban board").alias("board:ui").example(" kadence ui").action(async()=>{let{runUi:n}=await import("./chunks/ui-WFLRVGUH.js"),t=await n(process.cwd(),process.env);t.ok||c(t,!1)});h.help();h.version("0.1.0-dev");var v=process.argv;if(v[2]==="task"&&v[3]==="log"&&v[4]!==void 0&&v[5]!==void 0){let n=T(process.cwd(),process.env,v[4],v[5]),t=v.includes("--json");c(n,t)}var Ie=process.argv.findIndex((n,t)=>n.startsWith("-")&&/^-\d+(\.\d+)?$/.test(n)&&process.argv[t-1]==="--estimate");Ie!==-1&&(process.stderr.write(`Estimate must be a positive number, got "${process.argv[Ie]}".
133
+ kadence task add "Fix login" --estimate 3
134
+ `),process.exit(2));try{h.parse()}catch(n){process.stderr.write(`${n.message}
135
+ `),process.exit(2)}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "kadence",
3
+ "version": "0.1.0",
4
+ "description": "Tasks, sprints and velocity as plain files inside your git repository",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "kadence": "dist/cli.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE",
17
+ "CHANGELOG.md"
18
+ ],
19
+ "scripts": {
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "build": "node scripts/build.mjs",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepublishOnly": "npm run typecheck && npm test && npm run build"
25
+ },
26
+ "dependencies": {
27
+ "@types/blessed": "^0.1.27",
28
+ "blessed": "^0.1.81",
29
+ "cac": "^7.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.0.0",
33
+ "esbuild": "^0.28.0",
34
+ "typescript": "^5.6.0",
35
+ "vitest": "^4.0.0"
36
+ },
37
+ "keywords": [
38
+ "cli",
39
+ "git",
40
+ "task",
41
+ "sprint",
42
+ "velocity",
43
+ "kanban",
44
+ "tui",
45
+ "project-management",
46
+ "ai-agents",
47
+ "event-sourcing",
48
+ "offline"
49
+ ],
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/bogutskiandriy/FlowIt.git"
53
+ },
54
+ "homepage": "https://github.com/bogutskiandriy/FlowIt#readme",
55
+ "bugs": {
56
+ "url": "https://github.com/bogutskiandriy/FlowIt/issues"
57
+ }
58
+ }