kadence 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +19 -5
- package/dist/chunks/{board-6UNW5ISX.js → board-5SQP5RX6.js} +1 -1
- package/dist/chunks/chunk-CR5YON2J.js +10 -0
- package/dist/chunks/chunk-J7QEHKDW.js +248 -0
- package/dist/chunks/{ui-Q53SLKMA.js → ui-OTWFK76P.js} +2 -2
- package/dist/cli.js +142 -127
- package/package.json +1 -1
- package/dist/chunks/chunk-CDGGOWGY.js +0 -10
- package/dist/chunks/chunk-FCPGSN7D.js +0 -240
package/dist/cli.js
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{$ as
|
|
2
|
+
import{$ as zt,A as wt,B as vt,C as xt,D as St,E as Ct,F as Pe,G as At,H as jt,I as Dt,J as Tt,K as Rt,L as Et,M as Nt,N as Ot,O as Mt,P as _t,Q as Pt,R as It,S as Lt,T as Ie,U as ee,V as Wt,W as Bt,X as Ft,Y as Kt,Z as Ut,_ as Ht,a as st,aa as Yt,ba as Jt,ca as qt,da as Vt,e as ot,ea as Gt,f as Me,fa as Zt,g as O,ga as Qt,h as rt,i as it,j as at,k as dt,l as lt,m as ct,n as R,o as ke,p as pt,q as ht,r as _e,s as y,t as W,u as A,v as ye,w as j,x as $t,y as C,z as B}from"./chunks/chunk-J7QEHKDW.js";import{b as I,c as L,d as ut,e as mt,g as ft,h as ie,j as gt,k as kt,o as ae,p as X,q as be,r as bt,s as yt}from"./chunks/chunk-CR5YON2J.js";function Le(e){return e==null?[]:Array.isArray(e)?e:[e]}function xs(e,n,t,o){var s,r=e[n],i=~o.string.indexOf(n)?t==null||t===!0?"":String(t):typeof t=="boolean"?t:~o.boolean.indexOf(n)?t==="false"?!1:t==="true"||(e._.push((s=+t,s*0===0?s:t)),!!t):(s=+t,s*0===0?s:t);e[n]=r==null?i:Array.isArray(r)?r.concat(i):[r,i]}function Ss(e,n){e=e||[],n=n||{};var t,o,s,r,i,a={_:[]},d=0,l=0,c=0,u=e.length;let m=n.alias!==void 0,g=n.unknown!==void 0,h=n.default!==void 0;if(n.alias=n.alias||{},n.string=Le(n.string),n.boolean=Le(n.boolean),m)for(t in n.alias)for(o=n.alias[t]=Le(n.alias[t]),d=0;d<o.length;d++)(n.alias[o[d]]=o.concat(t)).splice(d,1);for(d=n.boolean.length;d-- >0;)for(o=n.alias[n.boolean[d]]||[],l=o.length;l-- >0;)n.boolean.push(o[l]);for(d=n.string.length;d-- >0;)for(o=n.alias[n.string[d]]||[],l=o.length;l-- >0;)n.string.push(o[l]);if(h){for(t in n.default)if(r=typeof n.default[t],o=n.alias[t]=n.alias[t]||[],n[r]!==void 0)for(n[r].push(t),d=0;d<o.length;d++)n[r].push(o[d])}let k=g?Object.keys(n.alias):[];for(d=0;d<u;d++){if(s=e[d],s==="--"){a._=a._.concat(e.slice(++d));break}for(l=0;l<s.length&&s.charCodeAt(l)===45;l++);if(l===0)a._.push(s);else if(s.substring(l,l+3)==="no-"){if(r=s.substring(l+3),g&&!~k.indexOf(r))return n.unknown(s);a[r]=!1}else{for(c=l+1;c<s.length&&s.charCodeAt(c)!==61;c++);for(r=s.substring(l,c),i=s.substring(++c)||d+1===u||(""+e[d+1]).charCodeAt(0)===45||e[++d],o=l===2?[r]:r,c=0;c<o.length;c++){if(r=o[c],g&&!~k.indexOf(r))return n.unknown("-".repeat(l)+r);xs(a,r,c+1<o.length||i,n)}}}if(h)for(t in n.default)a[t]===void 0&&(a[t]=n.default[t]);if(m)for(t in a)for(o=n.alias[t]||[];o.length>0;)a[o.shift()]=a[t];return a}function tn(e){return e.replace(/[<[].+/,"").trim()}function Cs(e){let n=/<([^>]+)>/g,t=/\[([^\]]+)\]/g,o=[],s=a=>{let d=!1,l=a[1];return l.startsWith("...")&&(l=l.slice(3),d=!0),{required:a[0].startsWith("<"),value:l,variadic:d}},r;for(;r=n.exec(e);)o.push(s(r));let i;for(;i=t.exec(e);)o.push(s(i));return o}function As(e){let n={alias:{},boolean:[]};for(let[t,o]of e.entries())o.names.length>1&&(n.alias[o.names[0]]=o.names.slice(1)),o.isBoolean&&(o.negated&&e.some((s,r)=>r!==t&&s.names.some(i=>o.names.includes(i))&&typeof s.required=="boolean")||n.boolean.push(o.names[0]));return n}function Xt(e){return e.sort((n,t)=>n.length>t.length?-1:1)[0]}function en(e,n){return e.length>=n?e:`${e}${" ".repeat(n-e.length)}`}function js(e){return e.replaceAll(/([a-z])-([a-z])/g,(n,t,o)=>t+o.toUpperCase())}function Ds(e,n,t){let o=e;for(let s=0;s<n.length;s++){let r=n[s];if(s===n.length-1){o[r]=t;return}if(o[r]==null){let i=+n[s+1]>-1;o[r]=i?[]:{}}o=o[r]}}function Ts(e,n){for(let t of Object.keys(n)){let o=n[t];o.shouldTransform&&(e[t]=[e[t]].flat(),typeof o.transformFunction=="function"&&(e[t]=e[t].map(o.transformFunction)))}}function Rs(e){let n=/([^\\/]+)$/.exec(e);return n?n[1]:""}function nn(e){return e.split(".").map((n,t)=>t===0?js(n):n).join(".")}var $e=class extends Error{constructor(e){super(e),this.name="CACError",typeof Error.captureStackTrace!="function"&&(this.stack=new Error(e).stack)}},Es=class{rawName;description;name;names;isBoolean;required;config;negated;constructor(e,n,t){this.rawName=e,this.description=n,this.config=Object.assign({},t),e=e.replaceAll(".*",""),this.negated=!1,this.names=tn(e).split(",").map(o=>{let s=o.trim().replace(/^-{1,2}/,"");return s.startsWith("no-")&&(this.negated=!0,s=s.replace(/^no-/,"")),nn(s)}).sort((o,s)=>o.length>s.length?1:-1),this.name=this.names.at(-1),this.negated&&this.config.default==null&&(this.config.default=!0),e.includes("<")?this.required=!0:e.includes("[")?this.required=!1:this.isBoolean=!0}},We,we;if(typeof process<"u"){let e;typeof Deno<"u"&&typeof Deno.version?.deno=="string"?e="deno":typeof Bun<"u"&&typeof Bun.version=="string"?e="bun":e="node",we=`${process.platform}-${process.arch} ${e}-${process.version}`,We=process.argv}else typeof navigator>"u"?we="unknown":we=`${navigator.platform} ${navigator.userAgent}`;var sn=class{rawName;description;config;cli;options;aliasNames;name;args;commandAction;usageText;versionNumber;examples;helpCallback;globalCommand;constructor(e,n,t={},o){this.rawName=e,this.description=n,this.config=t,this.cli=o,this.options=[],this.aliasNames=[],this.name=tn(e),this.args=Cs(e),this.examples=[]}usage(e){return this.usageText=e,this}allowUnknownOptions(){return this.config.allowUnknownOptions=!0,this}ignoreOptionDefaultValue(){return this.config.ignoreOptionDefaultValue=!0,this}version(e,n="-v, --version"){return this.versionNumber=e,this.option(n,"Display version number"),this}example(e){return this.examples.push(e),this}option(e,n,t){let o=new Es(e,n,t);return this.options.push(o),this}alias(e){return this.aliasNames.push(e),this}action(e){return this.commandAction=e,this}isMatched(e){return this.name===e||this.aliasNames.includes(e)}get isDefaultCommand(){return this.name===""||this.aliasNames.includes("!")}get isGlobalCommand(){return this instanceof on}hasOption(e){return e=e.split(".")[0],this.options.find(n=>n.names.includes(e))}outputHelp(){let{name:e,commands:n}=this.cli,{versionNumber:t,options:o,helpCallback:s}=this.cli.globalCommand,r=[{body:`${e}${t?`/${t}`:""}`}];if(r.push({title:"Usage",body:` $ ${e} ${this.usageText||this.rawName}`}),(this.isGlobalCommand||this.isDefaultCommand)&&n.length>0){let a=Xt(n.map(d=>d.rawName));r.push({title:"Commands",body:n.map(d=>` ${en(d.rawName,a.length)} ${d.description}`).join(`
|
|
3
3
|
`)},{title:"For more info, run any command with the `--help` flag",body:n.map(d=>` $ ${e}${d.name===""?"":` ${d.name}`} --help`).join(`
|
|
4
|
-
`)})}let i=this.isGlobalCommand?
|
|
5
|
-
`)})}this.examples.length>0&&
|
|
6
|
-
`)}),s&&(
|
|
4
|
+
`)})}let i=this.isGlobalCommand?o:[...this.options,...o||[]];if(!this.isGlobalCommand&&!this.isDefaultCommand&&(i=i.filter(a=>a.name!=="version")),i.length>0){let a=Xt(i.map(d=>d.rawName));r.push({title:"Options",body:i.map(d=>` ${en(d.rawName,a.length)} ${d.description} ${d.config.default===void 0?"":`(default: ${d.config.default})`}`).join(`
|
|
5
|
+
`)})}this.examples.length>0&&r.push({title:"Examples",body:this.examples.map(a=>typeof a=="function"?a(e):a).join(`
|
|
6
|
+
`)}),s&&(r=s(r)||r),console.info(r.map(a=>a.title?`${a.title}:
|
|
7
7
|
${a.body}`:a.body).join(`
|
|
8
8
|
|
|
9
|
-
`))}outputVersion(){let{name:e}=this.cli,{versionNumber:n}=this.cli.globalCommand;n&&console.info(`${e}/${n} ${
|
|
9
|
+
`))}outputVersion(){let{name:e}=this.cli,{versionNumber:n}=this.cli.globalCommand;n&&console.info(`${e}/${n} ${we}`)}checkRequiredArgs(){let e=this.args.filter(n=>n.required).length;if(this.cli.args.length<e)throw new $e(`missing required args for command \`${this.rawName}\``)}checkUnknownOptions(){let{options:e,globalCommand:n}=this.cli;if(!this.config.allowUnknownOptions){for(let t of Object.keys(e))if(t!=="--"&&!this.hasOption(t)&&!n.hasOption(t))throw new $e(`Unknown option \`${t.length>1?`--${t}`:`-${t}`}\``)}}checkOptionValue(){let{options:e,globalCommand:n}=this.cli,t=[...n.options,...this.options];for(let o of t){let s=e[o.name.split(".")[0]];if(o.required){let r=t.some(i=>i.negated&&i.names.includes(o.name));if(s===!0||s===!1&&!r)throw new $e(`option \`${o.rawName}\` value is missing`)}}}checkUnusedArgs(){let e=this.args.some(n=>n.variadic)?1/0:this.args.length;if(e<this.cli.args.length)throw new $e(`Unused args: ${this.cli.args.slice(e).map(n=>`\`${n}\``).join(", ")}`)}},on=class extends sn{constructor(e){super("@@global@@","",{},e)}},Ns=class extends EventTarget{name;commands;globalCommand;matchedCommand;matchedCommandName;rawArgs;args;options;showHelpOnExit;showVersionOnExit;constructor(e=""){super(),this.name=e,this.commands=[],this.rawArgs=[],this.args=[],this.options={},this.globalCommand=new on(this),this.globalCommand.usage("<command> [options]")}usage(e){return this.globalCommand.usage(e),this}command(e,n,t){let o=new sn(e,n||"",t,this);return o.globalCommand=this.globalCommand,this.commands.push(o),o}option(e,n,t){return this.globalCommand.option(e,n,t),this}help(e){return this.globalCommand.option("-h, --help","Display this message"),this.globalCommand.helpCallback=e,this.showHelpOnExit=!0,this}version(e,n="-v, --version"){return this.globalCommand.version(e,n),this.showVersionOnExit=!0,this}example(e){return this.globalCommand.example(e),this}outputHelp(){this.matchedCommand?this.matchedCommand.outputHelp():this.globalCommand.outputHelp()}outputVersion(){this.globalCommand.outputVersion()}setParsedInfo({args:e,options:n},t,o){return this.args=e,this.options=n,t&&(this.matchedCommand=t),o&&(this.matchedCommandName=o),this}unsetMatchedCommand(){this.matchedCommand=void 0,this.matchedCommandName=void 0}parse(e,{run:n=!0}={}){if(!e){if(!We)throw new Error("No argv provided and runtime process argv is not available.");e=We}this.rawArgs=e,this.name||(this.name=e[1]?Rs(e[1]):"cli");let t=!0;for(let s of this.commands){let r=this.mri(e.slice(2),s),i=r.args[0];if(s.isMatched(i)){t=!1;let a={...r,args:r.args.slice(1)};this.setParsedInfo(a,s,i),this.dispatchEvent(new CustomEvent(`command:${i}`,{detail:s}))}}if(t){for(let s of this.commands)if(s.isDefaultCommand){t=!1;let r=this.mri(e.slice(2),s);this.setParsedInfo(r,s),this.dispatchEvent(new CustomEvent("command:!",{detail:s}))}}if(t){let s=this.mri(e.slice(2));this.setParsedInfo(s)}this.options.help&&this.showHelpOnExit&&(this.outputHelp(),n=!1,this.unsetMatchedCommand()),this.options.version&&this.showVersionOnExit&&this.matchedCommandName==null&&(this.outputVersion(),n=!1,this.unsetMatchedCommand());let o={args:this.args,options:this.options};return n&&this.runMatchedCommand(),!this.matchedCommand&&this.args[0]&&this.dispatchEvent(new CustomEvent("command:*",{detail:this.args[0]})),o}mri(e,n){let t=[...this.globalCommand.options,...n?n.options:[]],o=As(t),s=[],r=e.indexOf("--");r!==-1&&(s=e.slice(r+1),e=e.slice(0,r));let i=Ss(e,o);i=Object.keys(i).reduce((u,m)=>({...u,[nn(m)]:i[m]}),{_:[]});let a=i._,d={"--":s},l=n&&n.config.ignoreOptionDefaultValue?n.config.ignoreOptionDefaultValue:this.globalCommand.config.ignoreOptionDefaultValue,c=Object.create(null);for(let u of t){if(!l&&u.config.default!==void 0)for(let m of u.names)d[m]=u.config.default;Array.isArray(u.config.type)&&c[u.name]===void 0&&(c[u.name]=Object.create(null),c[u.name].shouldTransform=!0,c[u.name].transformFunction=u.config.type[0])}for(let u of Object.keys(i))u!=="_"&&(Ds(d,u.split("."),i[u]),Ts(d,c));return{args:a,options:d}}runMatchedCommand(){let{args:e,options:n,matchedCommand:t}=this;if(!t||!t.commandAction)return;t.checkUnknownOptions(),t.checkOptionValue(),t.checkRequiredArgs(),t.checkUnusedArgs();let o=[];return t.args.forEach((s,r)=>{s.variadic?o.push(e.slice(r)):o.push(e[r])}),o.push(n),t.commandAction.apply(this,o)}},rn=(e="")=>new Ns(e);import{existsSync as V,mkdirSync as cn,readFileSync as xe,writeFileSync as de}from"node:fs";import{join as G}from"node:path";var an=".kadence/state.json",Os=["AGENTS.md","CLAUDE.md"];function un(e,n="dev",t={}){let o=st(e);if(o===null)return{ok:!1,alreadyInitialized:!1,root:null,message:`kadence lives inside a git repository, and there is none here.
|
|
10
10
|
Create one and try again:
|
|
11
|
-
git init`};let s=
|
|
11
|
+
git init`};let s=V(Me(o));cn(Me(o),{recursive:!0}),_s(o);let r=G(ot(o),"README.md");V(r)||de(r,dt(n),"utf8");for(let l of Os)Ps(o,l,n);let i=t.hooks===!0?`
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${Ms(o)}`:"",a=t.hooks!==!0&&V(G(o,".claude"))&&!ln(o)?`
|
|
14
14
|
|
|
15
|
-
kadence init --hooks adds prime at session start.`:"",d=[".kadence/","AGENTS.md","CLAUDE.md"];return t.hooks===!0&&
|
|
15
|
+
kadence init --hooks adds prime at session start.`:"",d=[".kadence/","AGENTS.md","CLAUDE.md"];return t.hooks===!0&&ln(o)&&d.push(".claude/settings.json"),{ok:!0,alreadyInitialized:s,root:o,message:s?`kadence is already initialised.${i}${a}`:`kadence is ready.
|
|
16
16
|
|
|
17
17
|
kadence task add "first task"
|
|
18
18
|
kadence decision add "What we chose" --why "Why we chose it"
|
|
19
19
|
kadence board
|
|
20
20
|
|
|
21
21
|
Commit ${d.join(", ")} so a teammate's agent finds them.
|
|
22
|
-
Files were created but not committed \u2014 that call is yours.`+i+a}}var
|
|
23
|
-
kadence init --hooks`}}let s=
|
|
24
|
-
`,"utf8"),`Updated the SessionStart hook in ${t}: it now prints an install hint where kadence is missing.`}let a=
|
|
25
|
-
`,"utf8"),`Added a SessionStart hook to ${t}: every session now starts with \`kadence prime\`.`}function
|
|
22
|
+
Files were created but not committed \u2014 that call is yours.`+i+a}}var ve="if command -v kadence >/dev/null 2>&1; then kadence prime; else echo 'kadence is not installed on this machine: ask the human to run npm install -g kadence. The team journal is in .kadence/.'; fi",mn=["kadence prime",ve],dn="startup";function Ms(e){let n=G(e,".claude"),t=G(n,"settings.json"),o={};if(V(t)){let d=xe(t,"utf8");try{let l=JSON.parse(d);if(typeof l!="object"||l===null||Array.isArray(l))throw new Error("not an object");o=l}catch{return`${t} is not valid JSON, so the hook was not added. Fix it and run:
|
|
23
|
+
kadence init --hooks`}}let s=o.hooks??{},r=Array.isArray(s.SessionStart)?s.SessionStart:[],i=r.flatMap(d=>(Array.isArray(d.hooks)?d.hooks:[]).filter(l=>typeof l.command=="string"&&mn.includes(l.command)));if(i.some(d=>d.command===ve))return`The SessionStart hook is already in ${t}.`;if(i.length>0){for(let d of i)d.command=ve;return de(t,`${JSON.stringify(o,null,2)}
|
|
24
|
+
`,"utf8"),`Updated the SessionStart hook in ${t}: it now prints an install hint where kadence is missing.`}let a=r.find(d=>d.matcher===dn);return a===void 0&&(a={matcher:dn,hooks:[]},r.push(a)),Array.isArray(a.hooks)||(a.hooks=[]),a.hooks.push({type:"command",command:ve,timeout:60}),s.SessionStart=r,o.hooks=s,cn(n,{recursive:!0}),de(t,`${JSON.stringify(o,null,2)}
|
|
25
|
+
`,"utf8"),`Added a SessionStart hook to ${t}: every session now starts with \`kadence prime\`.`}function ln(e){let n=G(e,".claude","settings.json");if(!V(n))return!1;try{let o=JSON.parse(xe(n,"utf8"))?.hooks?.SessionStart;return Array.isArray(o)?o.some(s=>Array.isArray(s?.hooks)&&s.hooks.some(r=>typeof r?.command=="string"&&mn.includes(r.command))):!1}catch{return!1}}function _s(e){let n=G(e,".gitignore"),t="";if(V(n)&&(t=xe(n,"utf8")),t.includes(an))return;let o=t.length>0&&!t.endsWith(`
|
|
26
26
|
`)?`
|
|
27
|
-
`:"";
|
|
28
|
-
`,"utf8")}function
|
|
27
|
+
`:"";de(n,`${t}${o}${an}
|
|
28
|
+
`,"utf8")}function Ps(e,n,t){let o=G(e,n),s=V(o)?xe(o,"utf8"):null,r=lt(s,t);r!==s&&de(o,r,"utf8")}function Is(e){return{label:e.label,title:e.title,priority:e.priority,estimate:e.estimate,labels:e.labels,claimedBy:e.claimedBy,contestedBy:e.contestedBy}}function pn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i={statuses:s.statuses,started:s.started},a=be(s.tasks,{viewer:ye(o,n),...i,...t.assignee===void 0?{}:{assignee:t.assignee}}),d=t.limit!==void 0&&t.limit>0?a.slice(0,t.limit):a;if(d.length===0)return{ok:!0,exitCode:0,warnings:r,message:bt(s.tasks,o.actor,t.assignee,i),data:{schema:"kadence/v1",ok:!0,tasks:[]}};let l=ke(n,process.stdout.isTTY===!0),c=d.map(u=>{let m=u.contestedBy.length>0?` [contested: ${u.contestedBy.join(", ")}]`:"";return`${pt(u,l)}${m}`});return{ok:!0,exitCode:0,warnings:r,message:[...c,"",`Take the first one:
|
|
29
29
|
kadence task claim ${d[0].label}`].join(`
|
|
30
|
-
`),data:{schema:"kadence/v1",ok:!0,tasks:d.map(
|
|
31
|
-
`),data:{schema:"kadence/v1",ok:!0,sprint:a===void 0?null:{name:a.name,endDate:a.endDate,daysLeft:d},mine:
|
|
30
|
+
`),data:{schema:"kadence/v1",ok:!0,tasks:d.map(Is)}}}var Ls=864e5;function Be(e){return e.history[e.history.length-1]?.ts??e.createdAt}function le(e,n){let t=Math.floor((n.getTime()-Date.parse(e))/Ls);return t>0?t:0}function Ws(e){for(let n=e.history.length-1;n>=0;n--){let t=e.history[n];if(t.id===e.claimedEventId)return!1;if(t.type==="task.moved")return!0}return!1}function Bs(e,n,t,o,s,r){let i=[],a=e.blockedBy.filter(l=>o.has(l));if(a.length>0&&i.push({kind:"dead_blocker",blockers:a.map(l=>t.get(l)??l)}),!ie(n,e))return i;let d=le(Be(e),s);if(d>=r&&i.push({kind:"stalled",days:d}),e.assignee===null&&e.claimedBy===null){let l=ft(e,n.started,n.statuses,n.startedChanges),c=l===null?d:le(l,s);c>=r&&i.push({kind:"unowned",days:c})}if(e.claimedBy!==null&&e.claimedAt!==null&&!Ws(e)){let l=le(e.claimedAt,s);l>=r&&i.push({kind:"stale_claim",days:l,who:e.claimedBy})}return i}function te(e){switch(e.kind){case"stalled":return`stalled ${String(e.days)}d`;case"unowned":return`unowned ${String(e.days)}d`;case"stale_claim":return`claimed ${String(e.days)}d ago by ${e.who??"someone"}, never moved`;case"dead_blocker":return`blocked by ${(e.blockers??[]).join(", ")}, already done`}}function Se(e,n=new Date,t=7){let o=e.tasks.filter(d=>!X(d)),s=new Set(e.tasks.filter(X).map(d=>d.id)),r=new Map(e.tasks.map(d=>[d.id,d.label])),i=[];for(let d of o){let l=Bs(d,e,r,s,n,t);l.length!==0&&i.push({label:d.label,title:d.title,status:d.status,priority:d.priority,assignee:d.assignee,idleDays:le(Be(d),n),signals:l})}let a=new Map(e.tasks.map((d,l)=>[d.label,l]));return i.sort((d,l)=>l.idleDays!==d.idleDays?l.idleDays-d.idleDays:(a.get(d.label)??0)-(a.get(l.label)??0)),{threshold:t,started:e.started,asOf:n.toISOString().slice(0,10),rows:i,notes:i.length>0?[]:Fs(e,o,n,t)}}function Fs(e,n,t,o){let s=n.filter(i=>ie(e,i));if(s.length===0)return[`Nothing to report: there is no work in progress past \`${e.started}\`.`];let r=Math.min(...s.map(i=>le(Be(i),t)));return[`Nothing to report: ${String(s.length)} task${s.length===1?"":"s"} in progress, none silent or ownerless for ${String(o)} days (the quietest was touched ${String(r)} day(s) ago).`]}function hn(e,n){return n===null?null:e.tasks.find(t=>t.id===n)?.label??null}var Ks=5,Us=5,Hs=5,zs=3,Ys=3,Js=7,fn=60,qs='record why: kadence decision add "\u2026" --why "\u2026"',gn=["kadence ready what can be started now","kadence task show KAD-1 one task in full, with its decisions","kadence decision list the reasons behind the work","kadence board the whole board"];function Ce(e){let n=[...e];return n.length>fn?`${n.slice(0,fn-1).join("")}\u2026`:e}function Vs(e,n){if(e===null)return null;let t=Date.parse(`${e}T00:00:00.000Z`);if(Number.isNaN(t))return null;let o=Date.parse(`${n.toISOString().slice(0,10)}T00:00:00.000Z`);return Math.round((t-o)/864e5)}function Gs(e,n,t){return e.tasks.filter(o=>ae(o.claimedBy,n)||o.contestedBy.some(s=>ae(s,n))||o.assignee===t&&o.status===e.started)}function Zs(e,n){if(e.contestedBy.length===0)return"";let t=[e.claimedBy,...e.contestedBy];if(!n.includes("#")&&t.every(o=>ae(o,n))){let o=t.every(s=>s!==n);return` [contested: ${t.length} of your ${o?"agents":"claims"} collided \u2014 keep one, release the rest]`}return ae(e.claimedBy,n)?` [contested: also claimed by ${e.contestedBy.join(", ")}]`:` [contested: ${e.claimedBy??"nobody"} holds it \u2014 talk before starting]`}function kn(e,n,t,o=new Date){let s=A(e,n);if(!j(s))return s;let{state:r,warnings:i}=C(s.root,s.actor),a=r.sprints.find($=>$.status==="active"),d=a===void 0?null:Vs(a.endDate,o),l=ye(s,n),c=Gs(r,l,s.actor),u=[...c].reverse().sort(($,N)=>+(N.contestedBy.length>0)-+($.contestedBy.length>0)).slice(0,Ks),m=be(r.tasks,{viewer:l,statuses:r.statuses,started:r.started}),g=Se(r,o,Js).rows,h=g.slice(0,Ys),k=r.decisions.filter($=>$.supersededBy===null).slice(-Us).reverse().map($=>({label:$.label,title:$.title})),b=r.notes.slice(-Hs).reverse().map($=>({text:$.text,by:$.by,task:hn(r,$.task)})),x=new Set(c.map($=>$.id)),S=r.documents.flatMap($=>{let N=$.tasks.find(_=>x.has(_));return N===void 0?[]:[{label:$.label,title:$.title,task:hn(r,N),bytes:Buffer.byteLength($.body,"utf8")}]}),M=S.slice(0,zs),T=[];a!==void 0&&T.push(`Sprint: ${a.name}${d===null?"":`, ${d} day(s) left`}`,"");let Y=c.length>u.length?`${u.length} of ${c.length}`:`${u.length}`;T.push(c.length===0?"Nothing claimed by you.":`Yours (${Y}):`);for(let $ of u)T.push(` ${$.label} ${$.status} ${Ce($.title)}${Zs($,l)}`);if(M.length>0){let $=S.length>M.length?`${M.length} of ${S.length}`:`${M.length}`;T.push("",`Documentation for your work (${$}): (kadence doc show DOC-N)`);for(let N of M)T.push(` ${N.label} ${Ce(N.title)} (${N.task})`)}if(T.push("",`Ready to start: ${m.length} (kadence ready)`),h.length>0){let $=g.length>h.length?`${h.length} of ${g.length}`:`${h.length}`;T.push("",`Nobody is moving (${$}): (kadence report attention)`);for(let N of h)T.push(` ${N.label} ${N.signals.map(te).join(" \xB7 ")}`)}if(k.length>0){T.push("","Decisions in force:");for(let $ of k)T.push(` ${$.label} ${Ce($.title)}`)}else T.push("",qs);if(b.length>0){T.push("","Recent notes:");for(let $ of b)T.push(` ${$.task===null?"":`${$.task} `}${Ce($.text)}`)}T.push("","Go deeper:");for(let $ of gn)T.push(` ${$}`);return{ok:!0,exitCode:0,warnings:i,message:T.join(`
|
|
31
|
+
`),data:{schema:"kadence/v1",ok:!0,sprint:a===void 0?null:{name:a.name,endDate:a.endDate,daysLeft:d},mine:u.map($=>({label:$.label,title:$.title,status:$.status,claimedBy:$.claimedBy,contestedBy:$.contestedBy})),mineTotal:c.length,documentation:M,documentationTotal:S.length,ready:m.length,attention:h,attentionTotal:g.length,decisions:k,notes:b,commands:gn}}}var Qs=3;function bn(e,n){let t=new Map;for(let o of e)t.set(n(o),(t.get(n(o))??0)+1);return[...t.entries()].sort((o,s)=>s[1]-o[1]||(o[0]<s[0]?-1:1))}function Xs(e){return e.sprints.filter(n=>n.status==="closed").sort((n,t)=>(n.closedBy??"")<(t.closedBy??"")?1:-1).slice(0,Qs).map(n=>{let t=ee(e,n.id);return{name:n.name,velocity:t?.velocity??0}})}function yn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=s.tasks.filter(h=>h.status!==I&&h.status!==L),a=new Set(s.tasks.filter(h=>h.status===I||h.status===L).map(h=>h.id)),d=bn(s.tasks,h=>h.status),l=bn(i,h=>h.assignee??"unassigned"),c=i.filter(h=>h.blockedBy.some(k=>!a.has(k))),u=s.tasks.filter(h=>h.contestedBy.length>0),m=Xs(s);if(s.tasks.length===0)return{ok:!0,exitCode:0,warnings:r,message:`No tasks yet.
|
|
32
32
|
Create the first one:
|
|
33
|
-
kadence task add "title"`,data:{schema:"kadence/v1",ok:!0,tasks:0,open:0,byStatus:[],byAssignee:[],blocked:[],contested:[],velocity:[]}};let
|
|
34
|
-
`),data:{schema:"kadence/v1",ok:!0,tasks:s.tasks.length,open:i.length,byStatus:d.map(([
|
|
35
|
-
Nothing was written. Drop --dry-run to do it.`,data:{schema:"kadence/v1",ok:!0,keepFrom:i,archivedMonths:a.months.map(c=>c.month),archivedEvents:a.events,dryRun:!0}};let l=
|
|
36
|
-
`:""
|
|
33
|
+
kadence task add "title"`,data:{schema:"kadence/v1",ok:!0,tasks:0,open:0,byStatus:[],byAssignee:[],blocked:[],contested:[],velocity:[]}};let g=[];g.push(`${s.tasks.length} tasks, ${i.length} open`),g.push("","By status:");for(let[h,k]of d)g.push(` ${k} ${h}`);if(l.length>0){g.push("","Open work by assignee:");for(let[h,k]of l)g.push(` ${k} ${h}`)}if(c.length>0&&g.push("",`Blocked (${c.length}): ${c.map(h=>h.label).join(", ")}`),u.length>0&&g.push("",`Contested (${u.length}): ${u.map(h=>h.label).join(", ")}`),m.length>0){g.push("","Velocity of the last closed sprints:");for(let h of m)g.push(` ${h.velocity} points ${h.name}`)}return{ok:!0,exitCode:0,warnings:r,message:g.join(`
|
|
34
|
+
`),data:{schema:"kadence/v1",ok:!0,tasks:s.tasks.length,open:i.length,byStatus:d.map(([h,k])=>({status:h,count:k})),byAssignee:l.map(([h,k])=>({assignee:h,count:k})),blocked:c.map(h=>h.label),contested:u.map(h=>h.label),velocity:m}}}var eo=2;function to(e,n){let t=e.getUTCFullYear(),o=e.getUTCMonth();return new Date(Date.UTC(t,o-(n-1),1)).toISOString().slice(0,7)}function $n(e,n,t,o=new Date){let s=A(e,n);if(!j(s))return s;let r=t.keepMonths??eo;if(!Number.isInteger(r)||r<1){let c=t.keepMonthsRaw??String(r);return y(2,"invalid_argument",`--keep-months must be a whole number of at least 1, got "${c}".`,{received:c,hint:"kadence compact --keep-months 3"})}let i=to(o,r),a=it(s.root,i);if(a.months.length===0)return{ok:!0,exitCode:0,message:`Nothing to archive: every event is from ${i} or later, which --keep-months ${r} keeps as separate files.`,data:{schema:"kadence/v1",ok:!0,keepFrom:i,archivedMonths:[],archivedEvents:0,dryRun:t.dryRun===!0}};let d=a.months.map(c=>`${c.month} (${c.events} event${c.events===1?"":"s"})`).join(", ");if(t.dryRun===!0)return{ok:!0,exitCode:0,message:`Would archive ${a.events} event${a.events===1?"":"s"} from ${d}, keeping ${i} onward as separate files.
|
|
35
|
+
Nothing was written. Drop --dry-run to do it.`,data:{schema:"kadence/v1",ok:!0,keepFrom:i,archivedMonths:a.months.map(c=>c.month),archivedEvents:a.events,dryRun:!0}};let l=at(s.root,i);if(l.skipped.length>0){let c=l.skipped.map(h=>h.replace(`${s.root}/`,"")).join(", "),u=l.archivedMonths.length>0?`Archived ${l.archivedMonths.join(", ")} first; those are done.
|
|
36
|
+
`:"",m=l.skipped.every(h=>!h.endsWith(".json")),g=m?"It holds events this version cannot read \u2014 most often written by a newer kadence. Update kadence and run this again.":"The archive holds every event compacted before it \u2014 restore the file from git, or move it aside if you accept losing what it held, then run this again.";return y(1,"conflicting_state",`${u}Could not read ${c}, so ${l.skipped.length===1?"that month was":"those months were"} left alone. Nothing was deleted. ${g}`,{received:c,hint:m?"npm install -g kadence":"git checkout -- .kadence/events/archive/"})}return{ok:!0,exitCode:0,message:`Archived ${l.archivedEvents} event${l.archivedEvents===1?"":"s"} from ${d} into .kadence/events/archive/, keeping ${i} onward as separate files.
|
|
37
37
|
An archived month is one file. Compact on one branch and merge it before compacting on another; the events themselves are unchanged, only where they live.
|
|
38
|
-
Nothing was committed \u2014 that call is yours.`,data:{schema:"kadence/v1",ok:!0,keepFrom:i,archivedMonths:l.archivedMonths,archivedEvents:l.archivedEvents,dryRun:!1}}}function
|
|
38
|
+
Nothing was committed \u2014 that call is yours.`,data:{schema:"kadence/v1",ok:!0,keepFrom:i,archivedMonths:l.archivedMonths,archivedEvents:l.archivedEvents,dryRun:!1}}}function wn(e,n=new Date){let t=e.tasks.filter(d=>!X(d)),o=new Set(e.tasks.filter(d=>!X(d)).map(d=>d.id)),s=new Map;for(let d of t){let l=d.assignee,c=s.get(l);c===void 0?s.set(l,[d]):c.push(d)}let r=[...s.entries()].map(([d,l])=>({assignee:d,open:l.length,openPoints:l.reduce((c,u)=>c+(u.estimate??0),0),inProgress:l.filter(c=>ie(e,c)).length,blocked:l.filter(c=>c.blockedBy.some(u=>o.has(u))).length,unestimated:l.filter(c=>c.estimate===null).length})).sort((d,l)=>l.openPoints-d.openPoints||l.open-d.open),i=[];r.length===0&&i.push("Nothing open.");let a=r.reduce((d,l)=>d+l.unestimated,0);return a>0&&i.push(`${a} open task${a===1?"":"s"} carry no estimate, so the points understate the work by an unknown amount.`),{asOf:n.toISOString().slice(0,10),started:e.started,rows:r,notes:i}}function v(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var K=`
|
|
39
39
|
:root {
|
|
40
40
|
color-scheme: light dark;
|
|
41
41
|
--bg: #ffffff; --fg: #1a1a1a; --muted: #6b6b6b; --line: #e2e2e2;
|
|
@@ -78,7 +78,7 @@ th { color: var(--muted); font-weight: 600; font-size: .78rem; text-transform: u
|
|
|
78
78
|
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
79
79
|
.empty { color: var(--muted); }
|
|
80
80
|
footer { margin-top: 2.5rem; color: var(--muted); font-size: .8rem; border-top: 1px solid var(--line); padding-top: .75rem; }
|
|
81
|
-
`,
|
|
81
|
+
`,U=`
|
|
82
82
|
.tiles { display: flex; flex-wrap: wrap; gap: .75rem; margin: 0 0 1.5rem; }
|
|
83
83
|
.tile { flex: 1 1 140px; max-width: 16rem; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .6rem .75rem; }
|
|
84
84
|
.tile .label { color: var(--muted); font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; }
|
|
@@ -108,22 +108,22 @@ details { margin: .5rem 0 1.5rem; }
|
|
|
108
108
|
summary { color: var(--muted); font-size: .82rem; cursor: pointer; }
|
|
109
109
|
summary::marker { color: var(--line); }
|
|
110
110
|
tr.critical td:first-child { border-left: 3px solid var(--critical); }
|
|
111
|
-
`;function
|
|
112
|
-
`)}function j(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function p(e){return Number.isFinite(e)?String(Math.round(e*100)/100):"0"}function de(e){if(!Number.isFinite(e)||e<=0)return 1;let n=Math.floor(Math.log10(e)),t=Math.pow(10,n),r=e/t;return(r<=1?1:r<=2?2:r<=5?5:10)*t}function Is(e,n,t,r){let s=Math.min(4,t/2,r);return r<=0?"":`M${p(e)},${p(n+r)}L${p(e)},${p(n+s)}Q${p(e)},${p(n)} ${p(e+s)},${p(n)}L${p(e+t-s)},${p(n)}Q${p(e+t)},${p(n)} ${p(e+t)},${p(n+s)}L${p(e+t)},${p(n+r)}Z`}function Ls(e,n,t,r){let s=Math.min(4,r/2,t);return t<=0?"":`M${p(e)},${p(n)}L${p(e+t-s)},${p(n)}Q${p(e+t)},${p(n)} ${p(e+t)},${p(n+s)}L${p(e+t)},${p(n+r-s)}Q${p(e+t)},${p(n+r)} ${p(e+t-s)},${p(n+r)}L${p(e)},${p(n+r)}Z`}function le(e,n,t,r){return`<svg class="viz" viewBox="0 0 ${e} ${n}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${j(t)}"><title>${j(t)}</title>${r}</svg>`}function Me(e){let t=e.height??220,r={top:12,right:14,bottom:30,left:38},s=760-r.left-r.right,o=t-r.top-r.bottom,i=Math.max(1,e.labels.length),a=s/i,d=de(Math.max(0,...e.series.flatMap(v=>v.values))),l=v=>r.top+o-v/d*o,c=[];for(let v of[0,d/2,d])c.push(`<line class="grid" x1="${r.left}" y1="${p(l(v))}" x2="${p(760-r.right)}" y2="${p(l(v))}"/>`,`<text class="tick" x="${r.left-6}" y="${p(l(v)+3.5)}" text-anchor="end">${p(v)}</text>`);let u=2,m=(a-8-u*(e.series.length-1))/e.series.length,k=Math.min(24,Math.max(2,m)),f=k*e.series.length+u*(e.series.length-1);e.series.forEach((v,g)=>{e.labels.forEach((W,z)=>{let Z=v.values[z]??0,re=o-(l(Z)-r.top);if(re<=0)return;let Y=r.left+z*a+(a-f)/2+g*(k+u);c.push(`<path d="${Is(Y,l(Z),k,re)}" fill="var(${v.color})"><title>${j(W)} \xB7 ${j(v.name)}: ${Z} ${j(e.unit)}</title></path>`)})});let y=e.labels.length>8;e.labels.forEach((v,g)=>{let W=g===0||g===e.labels.length-1;if(!(y&&!W)){if(y){let z=g===0?r.left:760-r.right;c.push(`<text class="tick" x="${p(z)}" y="${p(t-10)}" text-anchor="${g===0?"start":"end"}">${j(v)}</text>`);return}c.push(`<text class="tick" x="${p(r.left+g*a+a/2)}" y="${p(t-10)}" text-anchor="middle">${j(v)}</text>`)}});let b=`${e.series.map(v=>v.name).join(" and ")} per period, in ${e.unit}.`;return le(760,t,b,c.join(""))}function mn(e){let t=e.height??240,r={top:12,right:104,bottom:30,left:38},s=760-r.left-r.right,o=t-r.top-r.bottom,i=Math.max(1,e.dates.length),a=b=>i===1?r.left+s/2:r.left+b/(i-1)*s,d=e.dates.map((b,v)=>e.bands.reduce((g,W)=>g+(W.values[v]??0),0)),l=de(Math.max(0,...d)),c=b=>r.top+o-b/l*o,u=[];for(let b of[0,l/2,l])u.push(`<line class="grid" x1="${r.left}" y1="${p(c(b))}" x2="${p(760-r.right)}" y2="${p(c(b))}"/>`,`<text class="tick" x="${r.left-6}" y="${p(c(b)+3.5)}" text-anchor="end">${p(b)}</text>`);let m=e.dates.map(()=>0),k=[...e.bands].reverse(),f=[];for(let b of k){let v=[...m];e.dates.forEach((Y,N)=>{m[N]=(m[N]??0)+(b.values[N]??0)});let g=e.dates.map((Y,N)=>`${p(a(N))},${p(c(m[N]??0))}`),W=e.dates.map((Y,N)=>`${p(a(N))},${p(c(v[N]??0))}`).reverse();if(i===1){let Y=Math.min(24,s),N=c(v[0]??0)-c(m[0]??0);N>0&&u.push(`<rect x="${p(a(0)-Y/2)}" y="${p(c(m[0]??0))}" width="${p(Y)}" height="${p(N)}" fill="var(${b.color})"><title>${j(b.name)}: ${b.values[0]??0}</title></rect>`);continue}u.push(`<path d="M${g.join("L")}L${W.join("L")}Z" fill="var(${b.color})" fill-opacity="0.9"><title>${j(b.name)}</title></path>`,`<polyline class="seam" points="${g.join(" ")}"/>`);let z=e.dates.length-1,Z=c(m[z]??0),re=c(v[z]??0);f.push({name:b.name,y:(Z+re)/2,height:re-Z})}let y=Number.NEGATIVE_INFINITY;for(let b of[...f].sort((v,g)=>v.y-g.y))b.height<10||b.y-y<13||(y=b.y,u.push(`<text class="tick" x="${p(760-r.right+10)}" y="${p(b.y+3.5)}">${j(b.name)}</text>`));return e.dates.forEach((b,v)=>{(v===0||v===e.dates.length-1)&&u.push(`<text class="tick" x="${p(a(v))}" y="${p(t-10)}" text-anchor="${v===0?"start":"end"}">${j(b)}</text>`)}),le(760,t,`Tasks per column per day, ${e.bands.map(b=>b.name).join(", ")}.`,u.join(""))}function ye(e){let r={top:8,right:52,bottom:26,left:92},s=r.top+r.bottom+Math.max(1,e.rows.length)*26,o=760-r.left-r.right,i=de(Math.max(e.reference?.value??0,...e.rows.map(l=>l.value))),a=l=>r.left+l/i*o,d=[];return d.push(`<line class="grid" x1="${r.left}" y1="${r.top}" x2="${r.left}" y2="${p(s-r.bottom)}"/>`),e.rows.forEach((l,c)=>{let u=r.top+c*26,m=Math.min(14,16),k=a(l.value)-r.left,f=l.critical===!0?"var(--critical)":"var(--s1)";d.push(`<text class="tick mono" x="${r.left-8}" y="${p(u+m/2+8)}" text-anchor="end">${j(l.name)}</text>`,`<path d="${Ls(r.left,u+5,Math.max(k,1),m)}" fill="${f}"><title>${j(l.name)}: ${l.value} ${j(e.unit)}${l.note===void 0?"":` \xB7 ${j(l.note)}`}</title></path>`,`<text class="tick" x="${p(a(l.value)+6)}" y="${p(u+m/2+8)}">${l.value}</text>`)}),e.reference!==void 0&&e.reference.value>0&&d.push(`<line class="reference" x1="${p(a(e.reference.value))}" y1="${r.top}" x2="${p(a(e.reference.value))}" y2="${p(s-r.bottom+4)}"/>`,`<text class="tick" x="${p(a(e.reference.value))}" y="${p(s-10)}" text-anchor="middle">${j(e.reference.label)}</text>`),le(760,s,`${e.rows.length} rows, in ${e.unit}.`,d.join(""))}function pn(e,n){let s={top:10,right:20,bottom:26,left:92},o=s.top+s.bottom+Math.max(1,e.length)*44,i=760-s.left-s.right,a=de(Math.max(1,...e.map(c=>c.p95))),d=c=>s.left+c/a*i,l=[];for(let c of[0,a/2,a])l.push(`<line class="grid" x1="${p(d(c))}" y1="${s.top}" x2="${p(d(c))}" y2="${p(o-s.bottom+2)}"/>`,`<text class="tick" x="${p(d(c))}" y="${p(o-10)}" text-anchor="middle">${p(c)}</text>`);return e.forEach((c,u)=>{let m=s.top+u*44+22-4;l.push(`<text class="tick" x="${s.left-8}" y="${p(m+4)}" text-anchor="end">${j(c.name)}</text>`,`<line class="range" x1="${p(d(c.p50))}" y1="${p(m)}" x2="${p(d(c.p95))}" y2="${p(m)}"/>`);for(let[k,f,y]of[["p50",c.p50,4.5],["p85",c.p85,6],["p95",c.p95,4.5]])l.push(`<circle class="dot" cx="${p(d(f))}" cy="${p(m)}" r="${y}"><title>${j(c.name)} ${k}: ${f} ${j(n)} (n=${c.n})</title></circle>`);l.push(`<text class="tick" x="${p(d(c.p85))}" y="${p(m-12)}" text-anchor="middle">p85 = ${c.p85}</text>`)}),le(760,o,`p50, p85 and p95 per measure, in ${n}.`,l.join(""))}function hn(e){let t=e.height??230,r={top:12,right:60,bottom:30,left:38},s=760-r.left-r.right,o=t-r.top-r.bottom,i=Math.max(1,e.labels.length),a=u=>i===1?r.left+s/2:r.left+u/(i-1)*s,d=de(Math.max(0,...e.series.flatMap(u=>u.values))),l=u=>r.top+o-u/d*o,c=[];for(let u of[0,d/2,d])c.push(`<line class="grid" x1="${r.left}" y1="${p(l(u))}" x2="${p(760-r.right)}" y2="${p(l(u))}"/>`,`<text class="tick" x="${r.left-6}" y="${p(l(u)+3.5)}" text-anchor="end">${p(u)}</text>`);for(let u of e.series){let m=u.values.map((b,v)=>`${p(a(v))},${p(l(b))}`).join("L"),k=u.reference===!0;c.push(`<path class="line${k?" reference-line":""}" d="M${m}" ${k?"":`stroke="var(${u.color})"`}><title>${j(u.name)}, ${j(e.unit)}</title></path>`);let f=u.values.length-1,y=u.values[f];!k&&y!==void 0&&c.push(`<circle class="dot" cx="${p(a(f))}" cy="${p(l(y))}" r="4.5" fill="var(${u.color})"/>`,`<text class="tick" x="${p(a(f)+9)}" y="${p(l(y)+3.5)}">${y}</text>`)}return e.labels.forEach((u,m)=>{m!==0&&m!==e.labels.length-1||c.push(`<text class="tick" x="${p(a(m))}" y="${p(t-10)}" text-anchor="${m===0?"start":"end"}">${j(u)}</text>`)}),le(760,t,`${e.series.map(u=>u.name).join(" against ")}, in ${e.unit}.`,c.join(""))}var ce=["--s1","--s2","--s3","--s4","--s5","--s6","--s7","--s8"];function te(e,n){return`<p class="stamp">${e.map($).join(" ")} A file, not a page: nothing here is live, and regenerating it is <code>${$(n)}</code>.</p>`}function E(e,n,t,r=!1){return`<div class="tile${r?" critical":""}"><div class="label">${$(e)}</div><div class="value">${$(n)}</div><div class="sub">${$(t)}</div></div>`}function $e(e){return'<div class="legend">'+e.map(n=>`<span><i style="background:var(${n.color})"></i>${$(n.name)}</span>`).join("")+"</div>"}function U(e,n){return`<figure class="figure">${e}<figcaption>${$(n)}</figcaption></figure>`}function H(e,n){return`<div class="rows"><table><tr>${e.map(r=>`<th${r.num===!0?' class="num"':""}>${$(r.head)}</th>`).join("")}</tr>${n.join("")}</table></div>`}function ue(e){return e.length===0?"":e.map(n=>`<p class="empty">${$(n)}</p>`).join("")}function B(e){return`<footer>${$(e)} Folded from the event journal by kadence. No server, no network.</footer>`}function ne(e){return`${e.toISOString().slice(0,16).replace("T"," ")} UTC`}function fn(e,n=new Date){let t=[];t.push("<h1>Flow</h1>"),t.push(te([`${e.window.from} to ${e.window.to} UTC, ${e.window.days} calendar days.`,`Work counts as started at "${e.started}".`,`Generated ${ne(n)}.`],"kadence report flow --html"));let r=e.cycleTime===null?"\u2014":String(e.cycleTime.p85);t.push('<div class="tiles">',E("In progress now",String(e.wip),"tasks past the started boundary"),E("Finished",String(e.finished),`in ${e.window.days} calendar days`),E("Cycle time p85",r,e.cycleTime===null?"nothing finished yet":`calendar days, n=${e.cycleTime.n}`),E("Blocked",String(e.blocked.days),e.blocked.tasks===0?"no blocked time in the window":`days across ${e.blocked.tasks} task(s)`,e.blocked.tasks>0),"</div>"),e.sle!==null&&t.push(`<p class="callout">${$(e.sle)}</p>`);let o=[{name:"Cycle time",p:e.cycleTime},{name:"Lead time",p:e.leadTime},{name:"Response time",p:e.responseTime}].filter(i=>i.p!==null);if(t.push("<h2>How long work takes</h2>"),o.length===0?t.push('<p class="empty">Nothing has finished in this window, so there is nothing to measure.</p>'):(t.push(U(pn(o.map(i=>({name:i.name,p50:i.p.p50,p85:i.p.p85,p95:i.p.p95,n:i.p.n})),"calendar days"),"p50, p85 and p95 in calendar days. Percentiles, never a mean \u2014 the tail is the part worth managing.")),t.push(H([{head:"Measure"},{head:"p50",num:!0},{head:"p85",num:!0},{head:"p95",num:!0},{head:"n",num:!0}],o.map(i=>`<tr><td>${$(i.name)}</td><td class="num">${i.p.p50}</td><td class="num">${i.p.p85}</td><td class="num">${i.p.p95}</td><td class="num">${i.p.n}</td></tr>`)))),t.push("<h2>Created and finished, per week</h2>"),e.perWeek.length===0)t.push('<p class="empty">No weeks in this window carry either.</p>');else{let i=[{name:"Created",color:"--s2",values:e.perWeek.map(a=>a.created)},{name:"Finished",color:"--s1",values:e.perWeek.map(a=>a.finished)}];t.push($e(i.map(a=>({name:a.name,color:a.color})))),t.push(U(Me({labels:e.perWeek.map(a=>a.week),series:i,unit:"tasks"}),"One band per week, labelled by its Monday. More created than finished, week after week, is a queue growing.")),t.push("<details><summary>Every week as rows</summary>",H([{head:"Week of"},{head:"Created",num:!0},{head:"Finished",num:!0}],e.perWeek.map(a=>`<tr><td>${$(a.week)}</td><td class="num">${a.created}</td><td class="num">${a.finished}</td></tr>`)),"</details>")}if(t.push("<h2>Aging work in progress</h2>"),e.aging.length===0)t.push('<p class="empty">Nothing is in progress.</p>');else{let i=e.aging.slice(0,15);t.push(U(ye({rows:i.map(a=>({name:a.label,value:a.ageDays,critical:a.overP85,note:`${a.status} \xB7 ${a.title}`})),unit:"calendar days",...e.cycleTime===null?{}:{reference:{value:e.cycleTime.p85,label:`p85 = ${e.cycleTime.p85} d`}}}),e.cycleTime===null?"Age in calendar days, oldest first.":"Age in calendar days, oldest first. The line is the p85 cycle time: work to its right has already taken longer than 85% of what finished.")),t.push(H([{head:"Task"},{head:"Age",num:!0},{head:"Status"},{head:"Title"}],i.map(a=>`<tr class="${a.overP85?"critical":""}"><td>${$(a.label)}</td><td class="num">${a.ageDays}</td><td>${$(a.status)}</td><td>${$(a.title)}${a.overP85?' <span class="pill danger">older than p85</span>':""}</td></tr>`))),e.aging.length>i.length&&t.push(`<p class="empty">\u2026 and ${e.aging.length-i.length} more. The --json response carries every row.</p>`)}return t.push(ue(e.notes)),t.push(B(`${e.finished} finished, ${e.wip} in progress.`)),L("kadence flow",P+I,t)}function gn(e,n=new Date){let t=[];if(t.push("<h1>Cumulative flow</h1>"),t.push(te([`${e.window.from} to ${e.window.to} UTC, ${e.window.days} calendar days.`,"Tasks per column at the end of each day.",`Generated ${ne(n)}.`],"kadence report cfd --html")),e.statuses.length===0||e.days.length===0)return t.push('<p class="empty">No columns to draw yet.</p>'),t.push(B("Nothing in the window.")),L("kadence cumulative flow",P+I,t);let r=e.statuses.slice(0,ce.length),s=e.statuses.slice(ce.length),o=r.map((a,d)=>({name:a,color:ce[d],values:e.days.map(l=>l.counts[a]??0)}));s.length>0&&o.push({name:`Other (${s.length} columns)`,color:ce[ce.length-1],values:e.days.map(a=>s.reduce((d,l)=>d+(a.counts[l]??0),0))}),t.push($e(o.map(a=>({name:a.name,color:a.color})))),t.push(U(mn({dates:e.days.map(a=>a.date),bands:o}),"Bands stack in board order, finished work at the baseline. A band that widens is a queue; the height between two lines is the work sitting in that column."));let i=[{head:"Date"},...o.map(a=>({head:a.name,num:!0}))];return t.push("<details><summary>Every day as rows</summary>",H(i,e.days.map(a=>{let d=r.map(c=>`<td class="num">${a.counts[c]??0}</td>`).join(""),l=s.length===0?"":`<td class="num">${s.reduce((c,u)=>c+(a.counts[u]??0),0)}</td>`;return`<tr><td>${$(a.date)}</td>${d}${l}</tr>`})),"</details>"),t.push(B(`${e.days.length} days, ${e.statuses.length} columns.`)),L("kadence cumulative flow",P+I,t)}function kn(e,n=new Date){let t=[];if(t.push("<h1>Attention</h1>"),t.push(te([`As of ${e.asOf} UTC.`,`Work past "${e.started}" that nobody is moving \u2014 silent or ownerless for ${e.threshold} days or more, or blocked by work that is already done.`,`Generated ${ne(n)}.`],"kadence report attention --html")),t.push('<div class="tiles">',E("Needs attention",String(e.rows.length),e.rows.length===0?"nothing is stuck":"of the work in flight",e.rows.length>0),E("Threshold",`${e.threshold} d`,"silence before a task counts as stalled"),"</div>"),e.rows.length===0)t.push('<p class="empty">Nothing is stalled, unowned, claimed and forgotten, or waiting on work that is already done.</p>');else{let r=e.rows.slice(0,20);t.push(U(ye({rows:r.map(s=>({name:s.label,value:s.idleDays,critical:s.idleDays>=e.threshold*2,note:`${s.status} \xB7 ${s.title}`})),unit:"days of silence",reference:{value:e.threshold,label:`${e.threshold} d`}}),`Days since the task last moved. The line is the ${e.threshold}-day threshold; everything here is already past it, and a bar turns critical past twice it.`)),t.push(H([{head:"Task"},{head:"Idle",num:!0},{head:"Status"},{head:"Why it is here"}],r.map(s=>`<tr class="${s.idleDays>=e.threshold*2?"critical":""}"><td>${$(s.label)}</td><td class="num">${s.idleDays}</td><td>${$(s.status)}</td><td>${$(s.title)}<div class="sub">${$(s.signals.map(ee).join(" \xB7 "))}</div></td></tr>`))),e.rows.length>r.length&&t.push(`<p class="empty">\u2026 and ${e.rows.length-r.length} more. The --json response carries every row.</p>`)}return t.push(ue(e.notes)),t.push(B(`${e.rows.length} needing attention.`)),L("kadence attention",P+I,t)}function bn(e,n=new Date){let t=[];if(t.push("<h1>Burndown</h1>"),t.push(te([`${$(e.sprintName)}: ${e.committed} points committed.`,e.finalRemaining===null?"The sprint is still open, so the last day is today rather than the end.":`Closed with ${e.finalRemaining} point(s) unfinished.`,`Generated ${ne(n)}.`],"kadence report burndown --html")),e.committed===0||e.days.length===0)return t.push('<p class="empty">Nothing to burn down: no task in this sprint carries an estimate.</p>'),t.push(B(`${e.sprintName}, ${e.days.length} days.`)),L("kadence burndown",P+I,t);let r=e.days[e.days.length-1],s=r.remaining<=r.ideal;return t.push('<div class="tiles">',E("Committed",String(e.committed),"points taken into the sprint"),E("Remaining",String(r.remaining),`of ${e.committed}, on ${r.date}`,!s),E("Against the ideal",`${s?"\u2212":"+"}${Math.abs(Math.round(r.remaining-r.ideal))}`,s?"points ahead of an even burn":"points behind an even burn",!s),"</div>"),t.push($e([{name:"Remaining",color:"--s1"},{name:"An even burn",color:"--muted"}])),t.push(U(hn({labels:e.days.map(o=>o.date),series:[{name:"An even burn",color:"--muted",values:e.days.map(o=>Math.round(o.ideal*10)/10),reference:!0},{name:"Remaining",color:"--s1",values:e.days.map(o=>o.remaining)}],unit:"points"}),"Points still open at the end of each day. The muted line is where a perfectly even burn would have been \u2014 an expectation, not a measurement.")),t.push("<details><summary>Every day as rows</summary>",H([{head:"Date"},{head:"Remaining",num:!0},{head:"Even burn",num:!0},{head:"Finished that day",num:!0}],e.days.map(o=>`<tr><td>${$(o.date)}</td><td class="num">${o.remaining}</td><td class="num">${Math.round(o.ideal*10)/10}</td><td class="num">${o.completed}</td></tr>`)),"</details>"),t.push(B(`${e.sprintName}, ${e.days.length} days, ${e.committed} points.`)),L("kadence burndown",P+I,t)}function yn(e,n=new Date){let t=[];if(t.push("<h1>Velocity</h1>"),t.push(te(["Points taken into a sprint against points finished, oldest first.",`Generated ${ne(n)}.`],"kadence report velocity --html")),e.rows.length===0)return t.push('<p class="empty">No closed sprint yet. Velocity is what a finished sprint leaves behind.</p>'),t.push(ue(e.notes)),t.push(B("No sprints closed.")),L("kadence velocity",P+I,t);t.push('<div class="tiles">',E("Finished",`${e.low}\u2013${e.high}`,`points per sprint, median ${e.median}`),E("Sprints",String(e.rows.length),"closed and counted"),"</div>");let r=[{name:"Committed",color:"--s2",values:e.rows.map(s=>s.committed)},{name:"Finished",color:"--s1",values:e.rows.map(s=>s.velocity)}];return t.push($e(r.map(s=>({name:s.name,color:s.color})))),t.push(U(Me({labels:e.rows.map(s=>s.name),series:r,unit:"points"}),"A committed column taller than its finished one, sprint after sprint, is a team taking in more than it can deliver \u2014 not a team that is slow.")),t.push(H([{head:"Sprint"},{head:"Committed",num:!0},{head:"Finished",num:!0},{head:"Carried over",num:!0}],e.rows.map(s=>`<tr><td>${$(s.name)}</td><td class="num">${s.committed}</td><td class="num">${s.velocity}</td><td class="num">${s.carriedOver}</td></tr>`))),t.push(ue(e.notes)),t.push(B(`${e.rows.length} closed sprint(s).`)),L("kadence velocity",P+I,t)}function $n(e,n=new Date){let t=[];if(t.push("<h1>Workload</h1>"),t.push(te([`Open work by owner, as of ${e.asOf} UTC.`,`Work counts as in progress at "${e.started}".`,`Generated ${ne(n)}.`],"kadence report workload --html")),e.rows.length===0)return t.push('<p class="empty">Nothing open.</p>'),t.push(B("Nothing open.")),L("kadence workload",P+I,t);let r=i=>i===null?"unassigned":i.split("@")[0]??i,s=e.rows.reduce((i,a)=>i+a.openPoints,0),o=e.rows.find(i=>i.assignee===null);return t.push('<div class="tiles">',E("Open points",String(s),`across ${e.rows.length} owner(s)`),E("Unassigned",String(o?.openPoints??0),o===void 0?"everything has an owner":`points over ${o.open} task(s)`,o!==void 0&&o.openPoints>s/2),"</div>"),t.push(U(ye({rows:e.rows.map(i=>({name:r(i.assignee),value:i.openPoints,critical:i.assignee===null,note:`${i.open} open, ${i.inProgress} in progress${i.blocked>0?`, ${i.blocked} blocked`:""}`})),unit:"open points"}),"Open points per owner. The unassigned row is drawn in the critical colour and named in the table: work nobody owns is what this report exists to surface.")),t.push(H([{head:"Owner"},{head:"Open",num:!0},{head:"Points",num:!0},{head:"In progress",num:!0},{head:"Blocked",num:!0}],e.rows.map(i=>`<tr class="${i.assignee===null?"critical":""}"><td>${$(i.assignee??"(unassigned)")}</td><td class="num">${i.open}</td><td class="num">${i.openPoints}</td><td class="num">${i.inProgress}</td><td class="num">${i.blocked}</td></tr>`))),t.push(ue(e.notes)),t.push(B(`${s} open points.`)),L("kadence workload",P+I,t)}import{mkdirSync as Ws,writeFileSync as Bs}from"node:fs";import{dirname as Fs}from"node:path";function we(e,n,t,r,s){let o=$t(e,n??t,s);if("exitCode"in o)return o;Ws(Fs(o.full),{recursive:!0});try{Bs(o.full,r,"utf8")}catch(i){return w(1,"conflicting_state",`Could not write ${o.full}: ${i.code??"unknown error"}.`,{received:o.rel,hint:s})}return{path:o.full,bytes:Buffer.byteLength(r)}}var ve=["flow","cfd","attention","burndown","velocity","workload"],Ie=[{name:"flow",answers:"How long work takes, how much is in flight, and what is aging."},{name:"cfd",answers:"Where work piles up: tasks per column at the end of each day."},{name:"attention",answers:"Work in flight that nobody is moving, and why."},{name:"burndown",answers:"Whether a sprint is on track against an even burn."},{name:"velocity",answers:"Committed against completed, sprint by sprint, as a range."},{name:"workload",answers:"Who is carrying what right now, unassigned work included."}],wn={team:["attention","flow","cfd"],sprint:["burndown","velocity","workload"]};function vn(e){let n=Ie.find(t=>t.name===e);return` ${n.name.padEnd(10)} ${n.answers}`}var _e=["flow","cfd","attention"],Sn=30,Ks=7,xn=730;function Us(e,n=Sn){if(e===void 0)return n;let t=/^(\d+)\s*d?$/i.exec(e.trim()),r=t===null?NaN:Number(t[1]);return!Number.isInteger(r)||r<1||r>xn?w(2,"invalid_argument",`--since takes a number of days from 1 to ${xn}, like 30d, got "${e}".`,{received:e,hint:"kadence report flow --since 30d"}):r}function Pe(e,n){return e===null?"no data":`p50 ${e.p50} \xB7 p85 ${e.p85} \xB7 p95 ${e.p95} ${n} (n=${e.n})`}function Hs(e){let n=[];if(n.push(`Flow, ${e.window.from} to ${e.window.to} UTC (${e.window.days} calendar days). Work starts at "${e.started}".`),n.push(""),n.push(` In progress now: ${e.wip}`),n.push(` Finished: ${e.finished}`),n.push(` Cycle time: ${Pe(e.cycleTime,"days")}`),n.push(` Lead time: ${Pe(e.leadTime,"days")}`),n.push(` Response time: ${Pe(e.responseTime,"days")}`),e.blocked.tasks>0&&n.push(` Blocked: ${e.blocked.tasks} task(s), ${e.blocked.days} days in total`),e.sle!==null&&n.push("",` ${e.sle}`),e.perWeek.some(t=>t.finished>0||t.created>0)){n.push(""," Week Created Finished");for(let t of e.perWeek)n.push(` ${t.week} ${String(t.created).padStart(7)} ${String(t.finished).padStart(8)}`)}if(e.aging.length>0){n.push(""," Aging work in progress (oldest first):");for(let t of e.aging.slice(0,10)){let r=t.overP85?" \u2190 older than p85":"";n.push(` ${t.label} ${String(t.ageDays).padStart(5)} d ${t.status} ${t.title}${r}`)}e.aging.length>10&&n.push(` \u2026 and ${e.aging.length-10} more`)}if(e.notes.length>0){n.push("");for(let t of e.notes)n.push(` ${t}`)}return n.join(`
|
|
113
|
-
`)}function
|
|
114
|
-
`)}function
|
|
115
|
-
`)}function
|
|
116
|
-
`)}n.push("");let t=Math.max(8,...e.rows.map(
|
|
117
|
-
`)}function
|
|
118
|
-
`);n.push("");let t=s=>s??"(unassigned)",
|
|
119
|
-
`)}function
|
|
120
|
-
`),data:{schema:"kadence/v1",ok:!0,reports:
|
|
121
|
-
`),{...t===void 0?{}:{received:t},allowed:
|
|
122
|
-
It applies to ${
|
|
123
|
-
kadence sprint add KAD-1`,data:{schema:"kadence/v1",ok:!0,report:t,burndown:null}};l={data:{burndown:m},message:
|
|
124
|
-
Open it from disk \u2014 there is no server, and the page makes no requests.`,data:{schema:"kadence/v1",ok:!0,report:t,format:"html",path:c.path,bytes:c.bytes}}}return{ok:!0,exitCode:0,warnings:d,message:l.message,data:{schema:"kadence/v1",ok:!0,report:t,...l.data}}}import{existsSync as
|
|
111
|
+
`;function H(e,n,t){return["<!doctype html>",'<html lang="en">',"<head>",'<meta charset="utf-8">','<meta name="viewport" content="width=device-width, initial-scale=1">',`<title>${v(e)}</title>`,`<style>${n}</style>`,"</head>","<body>","<main>",...t,"</main>","</body>","</html>",""].join(`
|
|
112
|
+
`)}function E(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function f(e){return Number.isFinite(e)?String(Math.round(e*100)/100):"0"}function ce(e){if(!Number.isFinite(e)||e<=0)return 1;let n=Math.floor(Math.log10(e)),t=Math.pow(10,n),o=e/t;return(o<=1?1:o<=2?2:o<=5?5:10)*t}function no(e,n,t,o){let s=Math.min(4,t/2,o);return o<=0?"":`M${f(e)},${f(n+o)}L${f(e)},${f(n+s)}Q${f(e)},${f(n)} ${f(e+s)},${f(n)}L${f(e+t-s)},${f(n)}Q${f(e+t)},${f(n)} ${f(e+t)},${f(n+s)}L${f(e+t)},${f(n+o)}Z`}function so(e,n,t,o){let s=Math.min(4,o/2,t);return t<=0?"":`M${f(e)},${f(n)}L${f(e+t-s)},${f(n)}Q${f(e+t)},${f(n)} ${f(e+t)},${f(n+s)}L${f(e+t)},${f(n+o-s)}Q${f(e+t)},${f(n+o)} ${f(e+t-s)},${f(n+o)}L${f(e)},${f(n+o)}Z`}function ue(e,n,t,o){return`<svg class="viz" viewBox="0 0 ${e} ${n}" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${E(t)}"><title>${E(t)}</title>${o}</svg>`}function Fe(e){let t=e.height??220,o={top:12,right:14,bottom:30,left:38},s=760-o.left-o.right,r=t-o.top-o.bottom,i=Math.max(1,e.labels.length),a=s/i,d=ce(Math.max(0,...e.series.flatMap(x=>x.values))),l=x=>o.top+r-x/d*r,c=[];for(let x of[0,d/2,d])c.push(`<line class="grid" x1="${o.left}" y1="${f(l(x))}" x2="${f(760-o.right)}" y2="${f(l(x))}"/>`,`<text class="tick" x="${o.left-6}" y="${f(l(x)+3.5)}" text-anchor="end">${f(x)}</text>`);let u=2,m=(a-8-u*(e.series.length-1))/e.series.length,g=Math.min(24,Math.max(2,m)),h=g*e.series.length+u*(e.series.length-1);e.series.forEach((x,S)=>{e.labels.forEach((M,T)=>{let Y=x.values[T]??0,$=r-(l(Y)-o.top);if($<=0)return;let N=o.left+T*a+(a-h)/2+S*(g+u);c.push(`<path d="${no(N,l(Y),g,$)}" fill="var(${x.color})"><title>${E(M)} \xB7 ${E(x.name)}: ${Y} ${E(e.unit)}</title></path>`)})});let k=e.labels.length>8;e.labels.forEach((x,S)=>{let M=S===0||S===e.labels.length-1;if(!(k&&!M)){if(k){let T=S===0?o.left:760-o.right;c.push(`<text class="tick" x="${f(T)}" y="${f(t-10)}" text-anchor="${S===0?"start":"end"}">${E(x)}</text>`);return}c.push(`<text class="tick" x="${f(o.left+S*a+a/2)}" y="${f(t-10)}" text-anchor="middle">${E(x)}</text>`)}});let b=`${e.series.map(x=>x.name).join(" and ")} per period, in ${e.unit}.`;return ue(760,t,b,c.join(""))}function vn(e){let t=e.height??240,o={top:12,right:104,bottom:30,left:38},s=760-o.left-o.right,r=t-o.top-o.bottom,i=Math.max(1,e.dates.length),a=b=>i===1?o.left+s/2:o.left+b/(i-1)*s,d=e.dates.map((b,x)=>e.bands.reduce((S,M)=>S+(M.values[x]??0),0)),l=ce(Math.max(0,...d)),c=b=>o.top+r-b/l*r,u=[];for(let b of[0,l/2,l])u.push(`<line class="grid" x1="${o.left}" y1="${f(c(b))}" x2="${f(760-o.right)}" y2="${f(c(b))}"/>`,`<text class="tick" x="${o.left-6}" y="${f(c(b)+3.5)}" text-anchor="end">${f(b)}</text>`);let m=e.dates.map(()=>0),g=[...e.bands].reverse(),h=[];for(let b of g){let x=[...m];e.dates.forEach((N,_)=>{m[_]=(m[_]??0)+(b.values[_]??0)});let S=e.dates.map((N,_)=>`${f(a(_))},${f(c(m[_]??0))}`),M=e.dates.map((N,_)=>`${f(a(_))},${f(c(x[_]??0))}`).reverse();if(i===1){let N=Math.min(24,s),_=c(x[0]??0)-c(m[0]??0);_>0&&u.push(`<rect x="${f(a(0)-N/2)}" y="${f(c(m[0]??0))}" width="${f(N)}" height="${f(_)}" fill="var(${b.color})"><title>${E(b.name)}: ${b.values[0]??0}</title></rect>`);continue}u.push(`<path d="M${S.join("L")}L${M.join("L")}Z" fill="var(${b.color})" fill-opacity="0.9"><title>${E(b.name)}</title></path>`,`<polyline class="seam" points="${S.join(" ")}"/>`);let T=e.dates.length-1,Y=c(m[T]??0),$=c(x[T]??0);h.push({name:b.name,y:(Y+$)/2,height:$-Y})}let k=Number.NEGATIVE_INFINITY;for(let b of[...h].sort((x,S)=>x.y-S.y))b.height<10||b.y-k<13||(k=b.y,u.push(`<text class="tick" x="${f(760-o.right+10)}" y="${f(b.y+3.5)}">${E(b.name)}</text>`));return e.dates.forEach((b,x)=>{(x===0||x===e.dates.length-1)&&u.push(`<text class="tick" x="${f(a(x))}" y="${f(t-10)}" text-anchor="${x===0?"start":"end"}">${E(b)}</text>`)}),ue(760,t,`Tasks per column per day, ${e.bands.map(b=>b.name).join(", ")}.`,u.join(""))}function Ae(e){let o={top:8,right:52,bottom:26,left:92},s=o.top+o.bottom+Math.max(1,e.rows.length)*26,r=760-o.left-o.right,i=ce(Math.max(e.reference?.value??0,...e.rows.map(l=>l.value))),a=l=>o.left+l/i*r,d=[];return d.push(`<line class="grid" x1="${o.left}" y1="${o.top}" x2="${o.left}" y2="${f(s-o.bottom)}"/>`),e.rows.forEach((l,c)=>{let u=o.top+c*26,m=Math.min(14,16),g=a(l.value)-o.left,h=l.critical===!0?"var(--critical)":"var(--s1)";d.push(`<text class="tick mono" x="${o.left-8}" y="${f(u+m/2+8)}" text-anchor="end">${E(l.name)}</text>`,`<path d="${so(o.left,u+5,Math.max(g,1),m)}" fill="${h}"><title>${E(l.name)}: ${l.value} ${E(e.unit)}${l.note===void 0?"":` \xB7 ${E(l.note)}`}</title></path>`,`<text class="tick" x="${f(a(l.value)+6)}" y="${f(u+m/2+8)}">${l.value}</text>`)}),e.reference!==void 0&&e.reference.value>0&&d.push(`<line class="reference" x1="${f(a(e.reference.value))}" y1="${o.top}" x2="${f(a(e.reference.value))}" y2="${f(s-o.bottom+4)}"/>`,`<text class="tick" x="${f(a(e.reference.value))}" y="${f(s-10)}" text-anchor="middle">${E(e.reference.label)}</text>`),ue(760,s,`${e.rows.length} rows, in ${e.unit}.`,d.join(""))}function xn(e,n){let s={top:10,right:20,bottom:26,left:92},r=s.top+s.bottom+Math.max(1,e.length)*44,i=760-s.left-s.right,a=ce(Math.max(1,...e.map(c=>c.p95))),d=c=>s.left+c/a*i,l=[];for(let c of[0,a/2,a])l.push(`<line class="grid" x1="${f(d(c))}" y1="${s.top}" x2="${f(d(c))}" y2="${f(r-s.bottom+2)}"/>`,`<text class="tick" x="${f(d(c))}" y="${f(r-10)}" text-anchor="middle">${f(c)}</text>`);return e.forEach((c,u)=>{let m=s.top+u*44+22-4;l.push(`<text class="tick" x="${s.left-8}" y="${f(m+4)}" text-anchor="end">${E(c.name)}</text>`,`<line class="range" x1="${f(d(c.p50))}" y1="${f(m)}" x2="${f(d(c.p95))}" y2="${f(m)}"/>`);for(let[g,h,k]of[["p50",c.p50,4.5],["p85",c.p85,6],["p95",c.p95,4.5]])l.push(`<circle class="dot" cx="${f(d(h))}" cy="${f(m)}" r="${k}"><title>${E(c.name)} ${g}: ${h} ${E(n)} (n=${c.n})</title></circle>`);l.push(`<text class="tick" x="${f(d(c.p85))}" y="${f(m-12)}" text-anchor="middle">p85 = ${c.p85}</text>`)}),ue(760,r,`p50, p85 and p95 per measure, in ${n}.`,l.join(""))}function Sn(e){let t=e.height??230,o={top:12,right:60,bottom:30,left:38},s=760-o.left-o.right,r=t-o.top-o.bottom,i=Math.max(1,e.labels.length),a=u=>i===1?o.left+s/2:o.left+u/(i-1)*s,d=ce(Math.max(0,...e.series.flatMap(u=>u.values))),l=u=>o.top+r-u/d*r,c=[];for(let u of[0,d/2,d])c.push(`<line class="grid" x1="${o.left}" y1="${f(l(u))}" x2="${f(760-o.right)}" y2="${f(l(u))}"/>`,`<text class="tick" x="${o.left-6}" y="${f(l(u)+3.5)}" text-anchor="end">${f(u)}</text>`);for(let u of e.series){let m=u.values.map((b,x)=>`${f(a(x))},${f(l(b))}`).join("L"),g=u.reference===!0;c.push(`<path class="line${g?" reference-line":""}" d="M${m}" ${g?"":`stroke="var(${u.color})"`}><title>${E(u.name)}, ${E(e.unit)}</title></path>`);let h=u.values.length-1,k=u.values[h];!g&&k!==void 0&&c.push(`<circle class="dot" cx="${f(a(h))}" cy="${f(l(k))}" r="4.5" fill="var(${u.color})"/>`,`<text class="tick" x="${f(a(h)+9)}" y="${f(l(k)+3.5)}">${k}</text>`)}return e.labels.forEach((u,m)=>{m!==0&&m!==e.labels.length-1||c.push(`<text class="tick" x="${f(a(m))}" y="${f(t-10)}" text-anchor="${m===0?"start":"end"}">${E(u)}</text>`)}),ue(760,t,`${e.series.map(u=>u.name).join(" against ")}, in ${e.unit}.`,c.join(""))}var me=["--s1","--s2","--s3","--s4","--s5","--s6","--s7","--s8"];function ne(e,n){return`<p class="stamp">${e.map(v).join(" ")} A file, not a page: nothing here is live, and regenerating it is <code>${v(n)}</code>.</p>`}function P(e,n,t,o=!1){return`<div class="tile${o?" critical":""}"><div class="label">${v(e)}</div><div class="value">${v(n)}</div><div class="sub">${v(t)}</div></div>`}function je(e){return'<div class="legend">'+e.map(n=>`<span><i style="background:var(${n.color})"></i>${v(n.name)}</span>`).join("")+"</div>"}function J(e,n){return`<figure class="figure">${e}<figcaption>${v(n)}</figcaption></figure>`}function q(e,n){return`<div class="rows"><table><tr>${e.map(o=>`<th${o.num===!0?' class="num"':""}>${v(o.head)}</th>`).join("")}</tr>${n.join("")}</table></div>`}function pe(e){return e.length===0?"":e.map(n=>`<p class="empty">${v(n)}</p>`).join("")}function z(e){return`<footer>${v(e)} Folded from the event journal by kadence. No server, no network.</footer>`}function se(e){return`${e.toISOString().slice(0,16).replace("T"," ")} UTC`}function Cn(e,n=new Date){let t=[];t.push("<h1>Flow</h1>"),t.push(ne([`${e.window.from} to ${e.window.to} UTC, ${e.window.days} calendar days.`,`Work counts as started at "${e.started}".`,`Generated ${se(n)}.`],"kadence report flow --html"));let o=e.cycleTime===null?"\u2014":String(e.cycleTime.p85);t.push('<div class="tiles">',P("In progress now",String(e.wip),"tasks past the started boundary"),P("Finished",String(e.finished),`in ${e.window.days} calendar days`),P("Cycle time p85",o,e.cycleTime===null?"nothing finished yet":`calendar days, n=${e.cycleTime.n}`),P("Blocked",String(e.blocked.days),e.blocked.tasks===0?"no blocked time in the window":`days across ${e.blocked.tasks} task(s)`,e.blocked.tasks>0),"</div>"),e.sle!==null&&t.push(`<p class="callout">${v(e.sle)}</p>`);let r=[{name:"Cycle time",p:e.cycleTime},{name:"Lead time",p:e.leadTime},{name:"Response time",p:e.responseTime}].filter(i=>i.p!==null);if(t.push("<h2>How long work takes</h2>"),r.length===0?t.push('<p class="empty">Nothing has finished in this window, so there is nothing to measure.</p>'):(t.push(J(xn(r.map(i=>({name:i.name,p50:i.p.p50,p85:i.p.p85,p95:i.p.p95,n:i.p.n})),"calendar days"),"p50, p85 and p95 in calendar days. Percentiles, never a mean \u2014 the tail is the part worth managing.")),t.push(q([{head:"Measure"},{head:"p50",num:!0},{head:"p85",num:!0},{head:"p95",num:!0},{head:"n",num:!0}],r.map(i=>`<tr><td>${v(i.name)}</td><td class="num">${i.p.p50}</td><td class="num">${i.p.p85}</td><td class="num">${i.p.p95}</td><td class="num">${i.p.n}</td></tr>`)))),t.push("<h2>Created and finished, per week</h2>"),e.perWeek.length===0)t.push('<p class="empty">No weeks in this window carry either.</p>');else{let i=[{name:"Created",color:"--s2",values:e.perWeek.map(a=>a.created)},{name:"Finished",color:"--s1",values:e.perWeek.map(a=>a.finished)}];t.push(je(i.map(a=>({name:a.name,color:a.color})))),t.push(J(Fe({labels:e.perWeek.map(a=>a.week),series:i,unit:"tasks"}),"One band per week, labelled by its Monday. More created than finished, week after week, is a queue growing.")),t.push("<details><summary>Every week as rows</summary>",q([{head:"Week of"},{head:"Created",num:!0},{head:"Finished",num:!0}],e.perWeek.map(a=>`<tr><td>${v(a.week)}</td><td class="num">${a.created}</td><td class="num">${a.finished}</td></tr>`)),"</details>")}if(t.push("<h2>Aging work in progress</h2>"),e.aging.length===0)t.push('<p class="empty">Nothing is in progress.</p>');else{let i=e.aging.slice(0,15);t.push(J(Ae({rows:i.map(a=>({name:a.label,value:a.ageDays,critical:a.overP85,note:`${a.status} \xB7 ${a.title}`})),unit:"calendar days",...e.cycleTime===null?{}:{reference:{value:e.cycleTime.p85,label:`p85 = ${e.cycleTime.p85} d`}}}),e.cycleTime===null?"Age in calendar days, oldest first.":"Age in calendar days, oldest first. The line is the p85 cycle time: work to its right has already taken longer than 85% of what finished.")),t.push(q([{head:"Task"},{head:"Age",num:!0},{head:"Status"},{head:"Title"}],i.map(a=>`<tr class="${a.overP85?"critical":""}"><td>${v(a.label)}</td><td class="num">${a.ageDays}</td><td>${v(a.status)}</td><td>${v(a.title)}${a.overP85?' <span class="pill danger">older than p85</span>':""}</td></tr>`))),e.aging.length>i.length&&t.push(`<p class="empty">\u2026 and ${e.aging.length-i.length} more. The --json response carries every row.</p>`)}return t.push(pe(e.notes)),t.push(z(`${e.finished} finished, ${e.wip} in progress.`)),H("kadence flow",K+U,t)}function An(e,n=new Date){let t=[];if(t.push("<h1>Cumulative flow</h1>"),t.push(ne([`${e.window.from} to ${e.window.to} UTC, ${e.window.days} calendar days.`,"Tasks per column at the end of each day.",`Generated ${se(n)}.`],"kadence report cfd --html")),e.statuses.length===0||e.days.length===0)return t.push('<p class="empty">No columns to draw yet.</p>'),t.push(z("Nothing in the window.")),H("kadence cumulative flow",K+U,t);let o=e.statuses.slice(0,me.length),s=e.statuses.slice(me.length),r=o.map((a,d)=>({name:a,color:me[d],values:e.days.map(l=>l.counts[a]??0)}));s.length>0&&r.push({name:`Other (${s.length} columns)`,color:me[me.length-1],values:e.days.map(a=>s.reduce((d,l)=>d+(a.counts[l]??0),0))}),t.push(je(r.map(a=>({name:a.name,color:a.color})))),t.push(J(vn({dates:e.days.map(a=>a.date),bands:r}),"Bands stack in board order, finished work at the baseline. A band that widens is a queue; the height between two lines is the work sitting in that column."));let i=[{head:"Date"},...r.map(a=>({head:a.name,num:!0}))];return t.push("<details><summary>Every day as rows</summary>",q(i,e.days.map(a=>{let d=o.map(c=>`<td class="num">${a.counts[c]??0}</td>`).join(""),l=s.length===0?"":`<td class="num">${s.reduce((c,u)=>c+(a.counts[u]??0),0)}</td>`;return`<tr><td>${v(a.date)}</td>${d}${l}</tr>`})),"</details>"),t.push(z(`${e.days.length} days, ${e.statuses.length} columns.`)),H("kadence cumulative flow",K+U,t)}function jn(e,n=new Date){let t=[];if(t.push("<h1>Attention</h1>"),t.push(ne([`As of ${e.asOf} UTC.`,`Work past "${e.started}" that nobody is moving \u2014 silent or ownerless for ${e.threshold} days or more, or blocked by work that is already done.`,`Generated ${se(n)}.`],"kadence report attention --html")),t.push('<div class="tiles">',P("Needs attention",String(e.rows.length),e.rows.length===0?"nothing is stuck":"of the work in flight",e.rows.length>0),P("Threshold",`${e.threshold} d`,"silence before a task counts as stalled"),"</div>"),e.rows.length===0)t.push('<p class="empty">Nothing is stalled, unowned, claimed and forgotten, or waiting on work that is already done.</p>');else{let o=e.rows.slice(0,20);t.push(J(Ae({rows:o.map(s=>({name:s.label,value:s.idleDays,critical:s.idleDays>=e.threshold*2,note:`${s.status} \xB7 ${s.title}`})),unit:"days of silence",reference:{value:e.threshold,label:`${e.threshold} d`}}),`Days since the task last moved. The line is the ${e.threshold}-day threshold; everything here is already past it, and a bar turns critical past twice it.`)),t.push(q([{head:"Task"},{head:"Idle",num:!0},{head:"Status"},{head:"Why it is here"}],o.map(s=>`<tr class="${s.idleDays>=e.threshold*2?"critical":""}"><td>${v(s.label)}</td><td class="num">${s.idleDays}</td><td>${v(s.status)}</td><td>${v(s.title)}<div class="sub">${v(s.signals.map(te).join(" \xB7 "))}</div></td></tr>`))),e.rows.length>o.length&&t.push(`<p class="empty">\u2026 and ${e.rows.length-o.length} more. The --json response carries every row.</p>`)}return t.push(pe(e.notes)),t.push(z(`${e.rows.length} needing attention.`)),H("kadence attention",K+U,t)}function Dn(e,n=new Date){let t=[];if(t.push("<h1>Burndown</h1>"),t.push(ne([`${v(e.sprintName)}: ${e.committed} points committed.`,e.finalRemaining===null?"The sprint is still open, so the last day is today rather than the end.":`Closed with ${e.finalRemaining} point(s) unfinished.`,`Generated ${se(n)}.`],"kadence report burndown --html")),e.committed===0||e.days.length===0)return t.push('<p class="empty">Nothing to burn down: no task in this sprint carries an estimate.</p>'),t.push(z(`${e.sprintName}, ${e.days.length} days.`)),H("kadence burndown",K+U,t);let o=e.days[e.days.length-1],s=o.remaining<=o.ideal;return t.push('<div class="tiles">',P("Committed",String(e.committed),"points taken into the sprint"),P("Remaining",String(o.remaining),`of ${e.committed}, on ${o.date}`,!s),P("Against the ideal",`${s?"\u2212":"+"}${Math.abs(Math.round(o.remaining-o.ideal))}`,s?"points ahead of an even burn":"points behind an even burn",!s),"</div>"),t.push(je([{name:"Remaining",color:"--s1"},{name:"An even burn",color:"--muted"}])),t.push(J(Sn({labels:e.days.map(r=>r.date),series:[{name:"An even burn",color:"--muted",values:e.days.map(r=>Math.round(r.ideal*10)/10),reference:!0},{name:"Remaining",color:"--s1",values:e.days.map(r=>r.remaining)}],unit:"points"}),"Points still open at the end of each day. The muted line is where a perfectly even burn would have been \u2014 an expectation, not a measurement.")),t.push("<details><summary>Every day as rows</summary>",q([{head:"Date"},{head:"Remaining",num:!0},{head:"Even burn",num:!0},{head:"Finished that day",num:!0}],e.days.map(r=>`<tr><td>${v(r.date)}</td><td class="num">${r.remaining}</td><td class="num">${Math.round(r.ideal*10)/10}</td><td class="num">${r.completed}</td></tr>`)),"</details>"),t.push(z(`${e.sprintName}, ${e.days.length} days, ${e.committed} points.`)),H("kadence burndown",K+U,t)}function Tn(e,n=new Date){let t=[];if(t.push("<h1>Velocity</h1>"),t.push(ne(["Points taken into a sprint against points finished, oldest first.",`Generated ${se(n)}.`],"kadence report velocity --html")),e.rows.length===0)return t.push('<p class="empty">No closed sprint yet. Velocity is what a finished sprint leaves behind.</p>'),t.push(pe(e.notes)),t.push(z("No sprints closed.")),H("kadence velocity",K+U,t);t.push('<div class="tiles">',P("Finished",`${e.low}\u2013${e.high}`,`points per sprint, median ${e.median}`),P("Sprints",String(e.rows.length),"closed and counted"),"</div>");let o=[{name:"Committed",color:"--s2",values:e.rows.map(s=>s.committed)},{name:"Finished",color:"--s1",values:e.rows.map(s=>s.velocity)}];return t.push(je(o.map(s=>({name:s.name,color:s.color})))),t.push(J(Fe({labels:e.rows.map(s=>s.name),series:o,unit:"points"}),"A committed column taller than its finished one, sprint after sprint, is a team taking in more than it can deliver \u2014 not a team that is slow.")),t.push(q([{head:"Sprint"},{head:"Committed",num:!0},{head:"Finished",num:!0},{head:"Carried over",num:!0}],e.rows.map(s=>`<tr><td>${v(s.name)}</td><td class="num">${s.committed}</td><td class="num">${s.velocity}</td><td class="num">${s.carriedOver}</td></tr>`))),t.push(pe(e.notes)),t.push(z(`${e.rows.length} closed sprint(s).`)),H("kadence velocity",K+U,t)}function Rn(e,n=new Date){let t=[];if(t.push("<h1>Workload</h1>"),t.push(ne([`Open work by owner, as of ${e.asOf} UTC.`,`Work counts as in progress at "${e.started}".`,`Generated ${se(n)}.`],"kadence report workload --html")),e.rows.length===0)return t.push('<p class="empty">Nothing open.</p>'),t.push(z("Nothing open.")),H("kadence workload",K+U,t);let o=i=>i===null?"unassigned":i.split("@")[0]??i,s=e.rows.reduce((i,a)=>i+a.openPoints,0),r=e.rows.find(i=>i.assignee===null);return t.push('<div class="tiles">',P("Open points",String(s),`across ${e.rows.length} owner(s)`),P("Unassigned",String(r?.openPoints??0),r===void 0?"everything has an owner":`points over ${r.open} task(s)`,r!==void 0&&r.openPoints>s/2),"</div>"),t.push(J(Ae({rows:e.rows.map(i=>({name:o(i.assignee),value:i.openPoints,critical:i.assignee===null,note:`${i.open} open, ${i.inProgress} in progress${i.blocked>0?`, ${i.blocked} blocked`:""}`})),unit:"open points"}),"Open points per owner. The unassigned row is drawn in the critical colour and named in the table: work nobody owns is what this report exists to surface.")),t.push(q([{head:"Owner"},{head:"Open",num:!0},{head:"Points",num:!0},{head:"In progress",num:!0},{head:"Blocked",num:!0}],e.rows.map(i=>`<tr class="${i.assignee===null?"critical":""}"><td>${v(i.assignee??"(unassigned)")}</td><td class="num">${i.open}</td><td class="num">${i.openPoints}</td><td class="num">${i.inProgress}</td><td class="num">${i.blocked}</td></tr>`))),t.push(pe(e.notes)),t.push(z(`${s} open points.`)),H("kadence workload",K+U,t)}import{mkdirSync as oo,writeFileSync as ro}from"node:fs";import{dirname as io}from"node:path";function De(e,n,t,o,s){let r=Tt(e,n??t,s);if("exitCode"in r)return r;oo(io(r.full),{recursive:!0});try{ro(r.full,o,"utf8")}catch(i){return y(1,"conflicting_state",`Could not write ${r.full}: ${i.code??"unknown error"}.`,{received:r.rel,hint:s})}return{path:r.full,bytes:Buffer.byteLength(o)}}var Te=["flow","cfd","attention","burndown","velocity","workload"],He=[{name:"flow",answers:"How long work takes, how much is in flight, and what is aging."},{name:"cfd",answers:"Where work piles up: tasks per column at the end of each day."},{name:"attention",answers:"Work in flight that nobody is moving, and why."},{name:"burndown",answers:"Whether a sprint is on track against an even burn."},{name:"velocity",answers:"Committed against completed, sprint by sprint, as a range."},{name:"workload",answers:"Who is carrying what right now, unassigned work included."}],En={team:["attention","flow","cfd"],sprint:["burndown","velocity","workload"]};function Nn(e){let n=He.find(t=>t.name===e);return` ${n.name.padEnd(10)} ${n.answers}`}var Ke=["flow","cfd","attention"],Mn=30,ao=7,On=730;function lo(e,n=Mn){if(e===void 0)return n;let t=/^(\d+)\s*d?$/i.exec(e.trim()),o=t===null?NaN:Number(t[1]);return!Number.isInteger(o)||o<1||o>On?y(2,"invalid_argument",`--since takes a number of days from 1 to ${On}, like 30d, got "${e}".`,{received:e,hint:"kadence report flow --since 30d"}):o}function Ue(e,n){return e===null?"no data":`p50 ${e.p50} \xB7 p85 ${e.p85} \xB7 p95 ${e.p95} ${n} (n=${e.n})`}function co(e){let n=[];if(n.push(`Flow, ${e.window.from} to ${e.window.to} UTC (${e.window.days} calendar days). Work starts at "${e.started}".`),n.push(""),n.push(` In progress now: ${e.wip}`),n.push(` Finished: ${e.finished}`),n.push(` Cycle time: ${Ue(e.cycleTime,"days")}`),n.push(` Lead time: ${Ue(e.leadTime,"days")}`),n.push(` Response time: ${Ue(e.responseTime,"days")}`),e.blocked.tasks>0&&n.push(` Blocked: ${e.blocked.tasks} task(s), ${e.blocked.days} days in total`),e.sle!==null&&n.push("",` ${e.sle}`),e.perWeek.some(t=>t.finished>0||t.created>0)){n.push(""," Week Created Finished");for(let t of e.perWeek)n.push(` ${t.week} ${String(t.created).padStart(7)} ${String(t.finished).padStart(8)}`)}if(e.aging.length>0){n.push(""," Aging work in progress (oldest first):");for(let t of e.aging.slice(0,10)){let o=t.overP85?" \u2190 older than p85":"";n.push(` ${t.label} ${String(t.ageDays).padStart(5)} d ${t.status} ${t.title}${o}`)}e.aging.length>10&&n.push(` \u2026 and ${e.aging.length-10} more`)}if(e.notes.length>0){n.push("");for(let t of e.notes)n.push(` ${t}`)}return n.join(`
|
|
113
|
+
`)}function uo(e){let n=[];n.push(`Cumulative flow, ${e.window.from} to ${e.window.to} UTC. Tasks per column at the end of each day.`),n.push("");let t=e.statuses,o=Math.max(6,...t.map(r=>r.length));n.push(` ${"date".padEnd(10)} ${t.map(r=>r.padStart(o)).join(" ")}`);let s=e.days.filter((r,i)=>i%7===0||i===e.days.length-1);for(let r of s)n.push(` ${r.date} ${t.map(i=>String(r.counts[i]??0).padStart(o)).join(" ")}`);return s.length<e.days.length&&n.push("",` ${e.days.length} days in the window; one row per week shown. --json carries every day.`),n.join(`
|
|
114
|
+
`)}function mo(e){let n=[];if(n.push(`Attention, as of ${e.asOf} UTC. Work past "${e.started}" that nobody is moving \u2014 silent or ownerless for ${e.threshold} days or more, or blocked by work that is already done.`),e.rows.length>0){n.push("");for(let t of e.rows.slice(0,15))n.push(` ${t.label} ${String(t.idleDays).padStart(4)} d ${t.title}`),n.push(` ${t.signals.map(te).join(" \xB7 ")}`);e.rows.length>15&&n.push(` \u2026 and ${e.rows.length-15} more`)}if(e.notes.length>0){n.push("");for(let t of e.notes)n.push(` ${t}`)}return n.join(`
|
|
115
|
+
`)}function po(e){let n=[];if(n.push("Velocity, oldest first. Points taken into a sprint against points finished."),e.rows.length===0){n.push(""," No closed sprint yet.");for(let o of e.notes)n.push(` ${o}`);return n.join(`
|
|
116
|
+
`)}n.push("");let t=Math.max(8,...e.rows.map(o=>o.name.length));n.push(` ${"Sprint".padEnd(t)} Committed Finished Carried`);for(let o of e.rows)n.push(` ${o.name.padEnd(t)} ${String(o.committed).padStart(9)} ${String(o.velocity).padStart(8)} ${String(o.carriedOver).padStart(7)}`);n.push("",` Finished: ${e.low} to ${e.high} points, median ${e.median}, over ${e.rows.length} sprint(s).`);for(let o of e.notes)n.push(` ${o}`);return n.join(`
|
|
117
|
+
`)}function ho(e){let n=[];if(n.push(`Open work by owner, as of ${e.asOf} UTC. Work counts as in progress at "${e.started}".`),e.rows.length===0)return n.push(""," Nothing open."),n.join(`
|
|
118
|
+
`);n.push("");let t=s=>s??"(unassigned)",o=Math.max(10,...e.rows.map(s=>t(s.assignee).length));n.push(` ${"Owner".padEnd(o)} Open Points Doing Blocked`);for(let s of e.rows)n.push(` ${t(s.assignee).padEnd(o)} ${String(s.open).padStart(4)} ${String(s.openPoints).padStart(6)} ${String(s.inProgress).padStart(5)} ${String(s.blocked).padStart(7)}`);e.notes.length>0&&n.push("");for(let s of e.notes)n.push(` ${s}`);return n.join(`
|
|
119
|
+
`)}function _n(e,n,t,o,s=new Date){if(o.list===!0)return{ok:!0,exitCode:0,warnings:[],message:["Reports, each a fold over the journal:","",...En.team.map(Nn),"","Sprint and team:",...En.sprint.map(Nn),"","Each takes --json, and --html to write it as a page with charts."," kadence report flow --html"].join(`
|
|
120
|
+
`),data:{schema:"kadence/v1",ok:!0,reports:He}};if(t===void 0||!Te.includes(t))return y(2,"invalid_argument",["Which report?",...He.map(c=>` kadence report ${c.name.padEnd(10)} ${c.answers}`)].join(`
|
|
121
|
+
`),{...t===void 0?{}:{received:t},allowed:Te,hint:"kadence report flow"});if(o.since!==void 0&&!Ke.includes(t))return y(2,"invalid_argument",`--since is a window, and ${t} does not have one.
|
|
122
|
+
It applies to ${Ke.join(", ")}.`,{received:o.since,allowed:Ke,hint:`kadence report ${t}`});if(o.sprint!==void 0&&t!=="burndown")return y(2,"invalid_argument",`--sprint applies to burndown, not to ${t}.`,{received:o.sprint,hint:'kadence report burndown --sprint "Sprint 3"'});let r=lo(o.since,t==="attention"?ao:Mn);if(typeof r!="number")return r;let i=A(e,n);if(!j(i))return i;let{state:a,warnings:d}=C(i.root,i.actor),l;if(t==="attention"){let c=Se(a,s,r);l={data:c,message:mo(c),html:()=>jn(c,s)}}else if(t==="cfd"){let c=kt(a,s,r);l={data:c,message:uo(c),html:()=>An(c,s)}}else if(t==="burndown"){let c=Vt(i.root,a,o.sprint);if("exitCode"in c)return c;let{sprint:u,chart:m}=c;if(m===null)return{ok:!0,exitCode:0,warnings:d,message:`"${u.name}" has no tasks yet.
|
|
123
|
+
kadence sprint add KAD-1`,data:{schema:"kadence/v1",ok:!0,report:t,burndown:null}};l={data:{burndown:m},message:Ft(m),html:()=>Dn(m,s)}}else if(t==="velocity"){let c=Wt(a);l={data:c,message:po(c),html:()=>Tn(c,s)}}else if(t==="workload"){let c=wn(a,s);l={data:c,message:ho(c),html:()=>Rn(c,s)}}else{let c=gt(a,s,r);l={data:c,message:co(c),html:()=>Cn(c,s)}}if(o.html===!0){let c=De(i.root,o.file,`kadence-${t}.html`,l.html(),`kadence report ${t} --html --file docs/${t}.html`);return"exitCode"in c?c:{ok:!0,exitCode:0,warnings:d,message:`Wrote ${c.path}.
|
|
124
|
+
Open it from disk \u2014 there is no server, and the page makes no requests.`,data:{schema:"kadence/v1",ok:!0,report:t,format:"html",path:c.path,bytes:c.bytes}}}return{ok:!0,exitCode:0,warnings:d,message:l.message,data:{schema:"kadence/v1",ok:!0,report:t,...l.data}}}import{existsSync as fo,mkdirSync as go,readFileSync as ko,writeFileSync as bo}from"node:fs";import{homedir as yo}from"node:os";import{dirname as Pn,join as ze}from"node:path";var Re="# kadence completion",oe=["zsh","bash","fish"];function $o(e){return oe.includes(e)}var Ye=[["init","Set up kadence in this repository"],["prime","Everything a session needs before it starts"],["ready","What can be started right now"],["task","Tasks: add, list, show, move, claim, ac"],["board","Kanban board in the terminal"],["sprint","Sprints: create, start, close, status"],["milestone","Milestones: create, add, list, close"],["decision","Decisions: add, list, show"],["note","Record something learned"],["stats","Where the project stands"],["template","Task templates: save, list, delete"],["schema","The machine-readable --json contract"],["completion","Shell completion"],["ui","The interactive board"]],Je=["add","list","show","edit","move","assign","comment","log","parent","block","unblock","claim","release","ac","doc","cancel","delete"];function wo(e){let n=Ye.map(([t])=>t).join(" ");return e==="fish"?`${[`${Re} for fish`,"complete -c kadence -f",...Ye.map(([o,s])=>`complete -c kadence -n "not __fish_seen_subcommand_from ${n}" -a ${o} -d '${s.replace(/'/g,"")}'`),`complete -c kadence -n "__fish_seen_subcommand_from task" -a "${Je.join(" ")}"`,"complete -c kadence -l json -d 'Machine-readable output for agents'"].join(`
|
|
125
125
|
`)}
|
|
126
|
-
`:e==="bash"?`${
|
|
126
|
+
`:e==="bash"?`${Re} for bash
|
|
127
127
|
_kadence() {
|
|
128
128
|
local cur prev
|
|
129
129
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
@@ -134,7 +134,7 @@ _kadence() {
|
|
|
134
134
|
return
|
|
135
135
|
fi
|
|
136
136
|
case "$prev" in
|
|
137
|
-
task) COMPREPLY=( $(compgen -W "${
|
|
137
|
+
task) COMPREPLY=( $(compgen -W "${Je.join(" ")}" -- "$cur") ) ;;
|
|
138
138
|
sprint) COMPREPLY=( $(compgen -W "create add edit start close status list burndown" -- "$cur") ) ;;
|
|
139
139
|
milestone) COMPREPLY=( $(compgen -W "create add list close" -- "$cur") ) ;;
|
|
140
140
|
decision) COMPREPLY=( $(compgen -W "add list show" -- "$cur") ) ;;
|
|
@@ -144,12 +144,12 @@ _kadence() {
|
|
|
144
144
|
}
|
|
145
145
|
complete -F _kadence kadence
|
|
146
146
|
`:`#compdef kadence
|
|
147
|
-
${
|
|
147
|
+
${Re} for zsh
|
|
148
148
|
|
|
149
149
|
_kadence() {
|
|
150
150
|
local -a commands
|
|
151
151
|
commands=(
|
|
152
|
-
${
|
|
152
|
+
${Ye.map(([t,o])=>` '${t}:${o.replace(/'/g,"")}'`).join(`
|
|
153
153
|
`)}
|
|
154
154
|
)
|
|
155
155
|
|
|
@@ -159,7 +159,7 @@ ${We.map(([t,r])=>` '${t}:${r.replace(/'/g,"")}'`).join(`
|
|
|
159
159
|
fi
|
|
160
160
|
|
|
161
161
|
case "\${words[2]}" in
|
|
162
|
-
task) _values 'action' ${
|
|
162
|
+
task) _values 'action' ${Je.join(" ")} ;;
|
|
163
163
|
sprint) _values 'action' create add edit start close status list burndown ;;
|
|
164
164
|
milestone) _values 'action' create add list close ;;
|
|
165
165
|
decision) _values 'action' add list show ;;
|
|
@@ -169,42 +169,49 @@ ${We.map(([t,r])=>` '${t}:${r.replace(/'/g,"")}'`).join(`
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
_kadence "$@"
|
|
172
|
-
`}function
|
|
172
|
+
`}function vo(e,n){return e==="fish"?ze(n,".config","fish","completions","kadence.fish"):e==="bash"?ze(n,".local","share","bash-completion","completions","kadence"):ze(n,".zsh","completions","_kadence")}function xo(e){let n=e.SHELL??"";for(let t of oe)if(n.endsWith(`/${t}`)||n===t)return t;return null}function In(e,n){let t;if(n.shell!==void 0){if(!$o(n.shell))return y(2,"invalid_argument",`kadence has no completion for "${n.shell}".`,{received:n.shell,allowed:oe,hint:"kadence completion install --shell zsh"});t=n.shell}else{let i=xo(e);if(i===null)return y(2,"invalid_argument",`Could not tell which shell you use from $SHELL.
|
|
173
173
|
Name it:
|
|
174
|
-
kadence completion install --shell zsh`,{allowed:
|
|
174
|
+
kadence completion install --shell zsh`,{allowed:oe,hint:"kadence completion install --shell zsh"});t=i}let o=wo(t);if(n.install!==!0||n.isTty===!1)return{ok:!0,exitCode:0,message:o,data:{schema:"kadence/v1",ok:!0,shell:t,script:o}};let s=vo(t,n.home??yo());if(fo(s)){let i=ko(s,"utf8");if(i===o)return{ok:!0,exitCode:0,message:`Completion for ${t} is already installed at ${s}.`,data:{schema:"kadence/v1",ok:!0,shell:t,path:s,written:!1}};if(!i.includes(Re)&&n.force!==!0)return y(1,"conflicting_state",`${s} exists and was not written by kadence.
|
|
175
175
|
Nothing was changed. Look at it, then either move it or run:
|
|
176
|
-
kadence completion install --shell ${t} --force`,{received:s,hint:`kadence completion install --shell ${t} --force`})}
|
|
176
|
+
kadence completion install --shell ${t} --force`,{received:s,hint:`kadence completion install --shell ${t} --force`})}go(Pn(s),{recursive:!0}),bo(s,o,"utf8");let r=t==="zsh"?`
|
|
177
177
|
zsh loads completions from fpath, which is yours to set. Add to ~/.zshrc:
|
|
178
|
-
fpath=(${
|
|
178
|
+
fpath=(${Pn(s)} $fpath)
|
|
179
179
|
autoload -Uz compinit && compinit`:`
|
|
180
|
-
Open a new shell, or reload it, and it will be picked up.`;return{ok:!0,exitCode:0,message:`Wrote ${t} completion to ${s}.${
|
|
180
|
+
Open a new shell, or reload it, and it will be picked up.`;return{ok:!0,exitCode:0,message:`Wrote ${t} completion to ${s}.${r}`,data:{schema:"kadence/v1",ok:!0,shell:t,path:s,written:!0}}}var Ln=`A note records something learned. When there was a choice and something was
|
|
181
181
|
turned down, record it as a decision instead:
|
|
182
|
-
kadence decision add "title" --why "reason"`;function
|
|
182
|
+
kadence decision add "title" --why "reason"`;function So(e,n){return{id:e.id,text:e.text,task:n(e.task),at:e.at,by:e.by,source:e.source}}function Wn(e,n,t,o){let s=A(e,n);if(!j(s))return s;let r=t.trim();if(r.length===0)return y(2,"invalid_argument",`A note needs text.
|
|
183
183
|
|
|
184
|
-
${
|
|
184
|
+
${Ln}`,{hint:'kadence note "Tests need a git identity"'});let{state:i,warnings:a}=C(s.root,s.actor),d=null,l=null;if(o.task!==void 0&&o.task.trim().length>0){let m=B(i,o.task);if(m===void 0)return W(o.task);d=m.id,l=m.label}let c=R();O(s.root,{id:c,type:"note.recorded",entity:c,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:d===null?{text:r}:{text:r,task:d}});let u=l===null?"":` on ${l}`;return{ok:!0,exitCode:0,warnings:a,message:`Note recorded${u}.`,data:{schema:"kadence/v1",ok:!0,note:{id:c,text:r,task:l}}}}function Bn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=s.notes;if(t.task!==void 0&&t.task.trim().length>0){let c=B(s,t.task);if(c===void 0)return W(t.task);i=i.filter(u=>u.task===c.id)}let a=[...i].reverse(),d=t.limit!==void 0&&t.limit>0?a.slice(0,t.limit):a;if(d.length===0)return{ok:!0,exitCode:0,warnings:r,message:`No notes yet.
|
|
185
185
|
Record the first one:
|
|
186
186
|
kadence note "text"
|
|
187
187
|
|
|
188
|
-
${
|
|
189
|
-
`),data:{schema:"kadence/v1",ok:!0,notes:d.map(c=>
|
|
190
|
-
${e.text}`}
|
|
188
|
+
${Ln}`,data:{schema:"kadence/v1",ok:!0,notes:[]}};let l=Co(s);return{ok:!0,exitCode:0,warnings:r,message:d.map(c=>Ao(c,l)).join(`
|
|
189
|
+
`),data:{schema:"kadence/v1",ok:!0,notes:d.map(c=>So(c,l))}}}function Co(e){return n=>n===null?null:e.tasks.find(t=>t.id===n)?.label??null}function Ao(e,n){let t=n(e.task),o=t===null?"":` ${t}`,s=e.source==="agent"?` ${e.by} [agent]`:` ${e.by}`;return`${e.at.slice(0,10)}${o}${s}
|
|
190
|
+
${e.text}`}import{existsSync as jo,readFileSync as Do,statSync as To}from"node:fs";import{resolve as Ro}from"node:path";var Eo=16*1024;function re(e,n){let t=n.trim().toUpperCase();return e.documents.find(o=>o.id===t||o.label===t)}function qe(e){return y(1,"doc_not_found",`No document ${e}.
|
|
191
|
+
kadence doc list`,{received:e,hint:"kadence doc list --json"})}var Ee=e=>Buffer.byteLength(e,"utf8");function Fn(e,n,t){if([n.body,n.file,n.stdin].filter(s=>s!==void 0).length>1)return y(2,"invalid_argument","Give the text one way: --body, --file or --stdin.",{hint:t});if(n.stdin!==void 0)return n.stdin;if(n.file!==void 0){let s=Ro(e,n.file);return!jo(s)||!To(s).isFile()?y(2,"invalid_argument",`No file at ${n.file} to read the text from.`,{received:n.file,hint:t}):Do(s,"utf8")}return n.body}function Kn(e){return Ee(e)>Eo?[`This document is ${Math.round(Ee(e)/1024)} KiB, past 16 KiB. Agents read long documents worse; one document per topic keeps what they read short.`]:[]}function he(e,n){return{id:e.id,label:e.label,title:e.title,bytes:Ee(e.body),revisions:e.revisions,tasks:e.tasks.map(n).filter(t=>t!==null),updatedAt:e.updatedAt,updatedBy:e.updatedBy,source:e.source,conflicted:e.conflicts.length>0}}function No(e,n){return{...he(e,n),body:e.body,revision:e.revision,createdAt:e.createdAt,createdBy:e.createdBy,conflicts:e.conflicts}}function fe(e){let n=new Map(e.tasks.map(t=>[t.id,t.label]));return t=>n.get(t)??null}function Un(e,n,t,o){let s=A(e,n);if(!j(s))return s;let r='kadence doc add "Auth" --body "How login works."',i=t.trim();if(i.length===0)return y(2,"invalid_argument","A document needs a title.",{hint:r});let a=Fn(e,o,r);if(typeof a=="object")return a;if(a===void 0||a.trim().length===0)return y(2,"invalid_argument",'A document needs text: --body "\u2026", --file <path>, or --stdin.',{hint:r});let{state:d,warnings:l}=C(s.root,s.actor),c=null;if(o.task!==void 0&&o.task.trim().length>0){let b=B(d,o.task);if(b===void 0)return W(o.task);c=b.id}let u=R(),m=new Date().toISOString();O(s.root,{id:u,type:"doc.written",entity:u,actor:s.actor,ts:m,source:s.source,data:{title:i,body:a,parents:[]}}),c!==null&&O(s.root,{id:R(),type:"doc.linked",entity:u,actor:s.actor,ts:m,source:s.source,data:{task:c}});let g=C(s.root,s.actor).state,h=re(g,u),k=fe(g);return{ok:!0,exitCode:0,warnings:[...l,...Kn(a)],message:`${h.label} written: ${h.title}
|
|
192
|
+
kadence doc show ${h.label}`,data:{schema:"kadence/v1",ok:!0,document:he(h,k)}}}function Hn(e,n,t,o){let s=A(e,n);if(!j(s))return s;let{state:r,warnings:i}=C(s.root,s.actor),a=re(r,t);if(a===void 0)return qe(t);let d=`kadence doc edit ${a.label} --body "\u2026"`,l=Fn(e,o,d);if(typeof l=="object")return l;if(l!==void 0&&l.trim().length===0)return y(2,"invalid_argument","A document cannot be emptied; its history would still hold every word.",{hint:d});if(a.conflicts.length>0&&l===void 0)return y(1,"conflicting_state",`${a.label} has ${a.conflicts.length+1} versions written on top of the same one. Read them (kadence doc show ${a.label} --json, under conflicts), then write the merged text:
|
|
193
|
+
kadence doc edit ${a.label} --file merged.txt`,{received:t,hint:`kadence doc show ${a.label} --json`});let c=o.title?.trim()||a.title,u=l??a.body;if(c===a.title&&u===a.body&&a.conflicts.length===0)return y(2,"invalid_argument",`Nothing to change: ${a.label} already reads that way.`,{received:t,hint:d});let m=[...a.conflicts.map(b=>b.revision),a.revision];O(s.root,{id:R(),type:"doc.written",entity:a.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{title:c,body:u,parents:m}});let g=C(s.root,s.actor).state,h=re(g,a.id),k=a.conflicts.length>0?` The ${a.conflicts.length+1} competing versions are now one.`:"";return{ok:!0,exitCode:0,warnings:[...i,...Kn(u)],message:`${h.label} revised (${h.revisions} revisions; earlier ones stay in the journal).${k}`,data:{schema:"kadence/v1",ok:!0,document:he(h,fe(g))}}}function zn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=re(s,t);if(i===void 0)return qe(t);let a=fe(s),d=i.tasks.map(a).filter(u=>u!==null),l=[`${i.label} ${i.title}`,` ${i.revisions} revision${i.revisions===1?"":"s"}, last ${i.updatedAt.slice(0,10)} by ${i.updatedBy}${i.source==="agent"?" [agent]":""}`,...d.length>0?[` Explains: ${d.join(", ")}`]:[],"",i.body],c=i.conflicts.length===0?[]:[`${i.label} has ${i.conflicts.length+1} versions written on top of the same one. Shown: the latest. Also written: ${i.conflicts.map(u=>`${u.at.slice(0,10)} by ${u.by}`).join("; ")} (in --json under conflicts). Write the merged text with kadence doc edit ${i.label} --file <path> to settle it.`];return{ok:!0,exitCode:0,warnings:[...r,...c],message:l.join(`
|
|
194
|
+
`),data:{schema:"kadence/v1",ok:!0,document:No(i,a)}}}function Yn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=s.documents;if(t.task!==void 0&&t.task.trim().length>0){let l=B(s,t.task);if(l===void 0)return W(t.task);i=i.filter(c=>c.tasks.includes(l.id))}let a=fe(s);if(i.length===0)return{ok:!0,exitCode:0,warnings:r,message:`No documentation yet.
|
|
195
|
+
Write the first one:
|
|
196
|
+
kadence doc add "Auth" --body "How login works." --task KAD-1`,data:{schema:"kadence/v1",ok:!0,documents:[]}};let d=Math.max(...i.map(l=>l.label.length));return{ok:!0,exitCode:0,warnings:r,message:i.map(l=>{let c=l.tasks.map(a).filter(g=>g!==null),u=`${Math.max(1,Math.round(Ee(l.body)/1024))} KiB`,m=l.conflicts.length>0?" [conflict]":"";return`${l.label.padEnd(d)} ${l.title} (${u}${c.length>0?`, ${c.join(" ")}`:""})${m}`}).join(`
|
|
197
|
+
`),data:{schema:"kadence/v1",ok:!0,documents:i.map(l=>he(l,a))}}}function Jn(e,n,t,o){let s=A(e,n);if(!j(s))return s;let{state:r,warnings:i}=C(s.root,s.actor),a=re(r,t);if(a===void 0)return qe(t);let d=B(r,o);if(d===void 0)return W(o);let l=!a.tasks.includes(d.id);l&&O(s.root,{id:R(),type:"doc.linked",entity:a.id,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{task:d.id}});let c=l?C(s.root,s.actor).state:r;return{ok:!0,exitCode:0,warnings:i,message:`${a.label} explains ${d.label}. It now arrives with kadence task show ${d.label}.`,data:{schema:"kadence/v1",ok:!0,document:he(re(c,a.id),fe(c)),task:{id:d.id,label:d.label}}}}import{readFileSync as er}from"node:fs";var Oo=/^\d{4}-\d{2}-\d{2}$/;function Ve(e,n){let t=String(n).trim(),o=t.toUpperCase();return e.milestones.find(s=>s.id===o||s.label===o||s.name.toLowerCase()===t.toLowerCase())}function qn(e,n){let t=e.milestones.map(o=>`${o.label} ${o.name}`);return y(1,"milestone_not_found",t.length===0?`No milestone "${n}".
|
|
191
198
|
Create one:
|
|
192
199
|
kadence milestone create "1.0"`:`No milestone "${n}".
|
|
193
|
-
Available: ${t.join(", ")}`,{received:n,hint:"kadence milestone list --json"})}function
|
|
194
|
-
${a} task(s) are still open; closing does not move them.`:""),data:{schema:"kadence/v1",ok:!0,milestone:{id:i.id,label:i.label,name:i.name,donePoints:i.donePoints,totalPoints:i.totalPoints}}}}function
|
|
200
|
+
Available: ${t.join(", ")}`,{received:n,hint:"kadence milestone list --json"})}function Ge(e,n,t,o){O(e.root,{id:R(),type:n,entity:t,actor:e.actor,ts:new Date().toISOString(),source:e.source,data:o})}function Vn(e,n,t,o){let s=A(e,n);if(!j(s))return s;let r=t.trim();if(r.length===0)return y(2,"invalid_argument","A milestone needs a name.",{hint:'kadence milestone create "1.0"'});if(o.due!==void 0&&!Oo.test(o.due))return y(2,"invalid_argument",`"${o.due}" is not a date. Use YYYY-MM-DD.`,{received:o.due,hint:'kadence milestone create "1.0" --due 2026-12-01'});let{state:i,warnings:a}=C(s.root,s.actor),d=Ve(i,r),l=d===void 0?[]:[`A milestone named ${d.name} already exists as ${d.label}. Both stay in the journal \u2014 reference them by label to be unambiguous.`],c=R();Ge(s,"milestone.created",c,{name:r,...o.due===void 0?{}:{due:o.due}});let u=`MS-${i.milestones.filter(m=>m.id<c).length+1}`;return{ok:!0,exitCode:0,warnings:[...a,...l],message:`${u} ${r}${o.due===void 0?"":` \u2014 due ${o.due}`}`,data:{schema:"kadence/v1",ok:!0,milestone:{id:c,label:u,name:r,due:o.due??null}}}}function Gn(e,n,t,o){let s=A(e,n);if(!j(s))return s;let{state:r,warnings:i}=C(s.root,s.actor),a=B(r,t);if(a===void 0)return W(t);let d=Ve(r,o);if(d===void 0)return qn(r,o);if(a.milestone===d.id)return{ok:!0,exitCode:0,warnings:i,message:`${a.label} is already in ${d.label} ${d.name}.`,data:{schema:"kadence/v1",ok:!0,task:{id:a.id,label:a.label}}};let l=a.milestone===null?null:r.milestones.find(c=>c.id===a.milestone);return Ge(s,"milestone.task_added",d.id,{task:a.id}),{ok:!0,exitCode:0,warnings:i,message:l==null?`${a.label} \u2192 ${d.label} ${d.name}`:`${a.label}: ${l.label} ${l.name} \u2192 ${d.label} ${d.name}`,data:{schema:"kadence/v1",ok:!0,task:{id:a.id,label:a.label},milestone:{id:d.id,label:d.label,name:d.name},...l==null?{}:{previous:l.label}}}}function Zn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=Ve(s,t);if(i===void 0)return qn(s,t);if(i.status==="closed")return{ok:!0,exitCode:0,warnings:r,message:`${i.label} ${i.name} is already closed.`,data:{schema:"kadence/v1",ok:!0,milestone:{id:i.id,label:i.label}}};Ge(o,"milestone.closed",i.id,{});let a=i.totalTasks-i.doneTasks;return{ok:!0,exitCode:0,warnings:r,message:`${i.label} ${i.name} closed at ${i.donePoints}/${i.totalPoints} points.`+(a>0?`
|
|
201
|
+
${a} task(s) are still open; closing does not move them.`:""),data:{schema:"kadence/v1",ok:!0,milestone:{id:i.id,label:i.label,name:i.name,donePoints:i.donePoints,totalPoints:i.totalPoints}}}}function Qn(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=t.all===!0?s.milestones:s.milestones.filter(a=>a.status==="open");return i.length===0?{ok:!0,exitCode:0,warnings:r,message:s.milestones.length===0?`No milestones yet.
|
|
195
202
|
Create one:
|
|
196
203
|
kadence milestone create "1.0"`:`Every milestone is closed.
|
|
197
204
|
See them all:
|
|
198
|
-
kadence milestone list --all`,data:{schema:"kadence/v1",ok:!0,milestones:[]}}:{ok:!0,exitCode:0,warnings:
|
|
199
|
-
`),data:{schema:"kadence/v1",ok:!0,milestones:i.map(
|
|
200
|
-
${
|
|
201
|
-
kadence decision list`,{received:e,hint:"kadence decision list --json"})}function
|
|
202
|
-
--why "..."`,{received:
|
|
203
|
-
It replaces ${
|
|
205
|
+
kadence milestone list --all`,data:{schema:"kadence/v1",ok:!0,milestones:[]}}:{ok:!0,exitCode:0,warnings:r,message:i.map(_o).join(`
|
|
206
|
+
`),data:{schema:"kadence/v1",ok:!0,milestones:i.map(Mo)}}}function Mo(e){return{id:e.id,label:e.label,name:e.name,due:e.due,status:e.status,doneTasks:e.doneTasks,totalTasks:e.totalTasks,donePoints:e.donePoints,totalPoints:e.totalPoints}}function _o(e){let n=e.totalPoints===0?0:Math.round(e.donePoints/e.totalPoints*100),t=Math.round(n/10),o=`${"#".repeat(t)}${".".repeat(10-t)}`,s=e.due===null?"":` due ${e.due}`,r=e.status==="closed"?" [closed]":"";return`${e.label} ${e.name}${s}${r}
|
|
207
|
+
${o} ${n}% ${e.donePoints}/${e.totalPoints} points, ${e.doneTasks}/${e.totalTasks} tasks`}import{existsSync as Po}from"node:fs";import{isAbsolute as Io,join as Lo,relative as Wo}from"node:path";function Xn(e,n){let t=n.toUpperCase();return e.decisions.find(o=>o.id===t||o.label===t)}function es(e){return y(1,"decision_not_found",`No decision ${e}.
|
|
208
|
+
kadence decision list`,{received:e,hint:"kadence decision list --json"})}function ts(e,n,t,o){let s=A(e,n);if(!j(s))return s;let r=t.trim();if(r.length===0)return y(2,"invalid_argument","A decision needs a title.",{hint:'kadence decision add "Use ULIDs" --why "Clocks disagree between machines"'});let i=o.why?.trim()??"";if(i.length===0)return y(2,"invalid_argument",`A decision needs a reason.
|
|
209
|
+
--why "..."`,{received:r,hint:'kadence decision add "Use ULIDs" --why "Clocks disagree between machines"'});let{state:a,warnings:d}=C(s.root,s.actor),l;if(o.task!==void 0){let S=B(a,o.task);if(S===void 0)return W(o.task);l=S.id}let c;if(o.supersedes!==void 0){let S=Xn(a,o.supersedes);if(S===void 0)return es(o.supersedes);c=S.id,l===void 0&&S.task!==null&&(l=S.task)}let u=(o.docs??[]).map(S=>Io(S)?Wo(s.root,S):S.replace(/^\.\//,"")),g=u.filter(S=>!Po(Lo(s.root,S))).map(S=>`No file at ${S} \u2014 the link is recorded anyway; it may arrive later.`),h=R();O(s.root,{id:h,type:"decision.recorded",entity:h,actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{title:r,why:i,...o.rejected!==void 0?{rejected:o.rejected.trim()}:{},...l!==void 0?{task:l}:{},...c!==void 0?{supersedes:c}:{},...u.length>0?{docs:u}:{}}});let b=C(s.root,s.actor).state.decisions.find(S=>S.id===h)?.label??h,x=c===void 0?"":`
|
|
210
|
+
It replaces ${o.supersedes}, and both links were written by one event \u2014 neither side can go stale.`;return{ok:!0,exitCode:0,warnings:[...d,...g],message:`${b} recorded.${x}`,data:{schema:"kadence/v1",ok:!0,decision:{id:h,label:b,title:r}}}}function ns(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=s.decisions;if(t.task!==void 0){let a=B(s,t.task);if(a===void 0)return W(t.task);i=i.filter(d=>d.task===a.id)}return t.all!==!0&&(i=i.filter(a=>a.supersededBy===null)),{ok:!0,exitCode:0,warnings:r,message:Bo(i,s),data:{schema:"kadence/v1",ok:!0,decisions:i.map(a=>os(a,s))}}}function ss(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor),i=Xn(s,t);return i===void 0?es(t):{ok:!0,exitCode:0,warnings:r,message:Fo(i,s),data:{schema:"kadence/v1",ok:!0,decision:os(i,s)}}}function Z(e,n){return n===null?null:e.decisions.find(t=>t.id===n)?.label??e.tasks.find(t=>t.id===n)?.label??n}function os(e,n){return{id:e.id,label:e.label,title:e.title,why:e.why,rejected:e.rejected,task:Z(n,e.task),docs:e.docs,supersedes:Z(n,e.supersedes),supersededBy:Z(n,e.supersededBy),superseded:e.supersededBy!==null,at:e.at,by:e.by,source:e.source}}function Bo(e,n){return e.length===0?`No decisions recorded yet.
|
|
204
211
|
Record the first one:
|
|
205
|
-
kadence decision add "Use ULIDs" --why "Clocks disagree"`:e.map(t=>{let
|
|
206
|
-
`)}function
|
|
207
|
-
`)}import{writeSync as
|
|
212
|
+
kadence decision add "Use ULIDs" --why "Clocks disagree"`:e.map(t=>{let o=t.supersededBy===null?"":` (superseded by ${Z(n,t.supersededBy)})`,s=t.source==="agent"?" [agent]":"";return`${t.label} ${t.title}${o}${s}`}).join(`
|
|
213
|
+
`)}function Fo(e,n){let t=[`${e.label} ${e.title}`];return e.supersededBy!==null&&t.push("",`!! SUPERSEDED by ${Z(n,e.supersededBy)} \u2014 this is no longer in force.`),t.push("",`Why: ${e.why}`),e.rejected!==null&&t.push(`Rejected: ${e.rejected}`),e.task!==null&&t.push(`Task: ${Z(n,e.task)}`),e.docs.length>0&&t.push(`Docs: ${e.docs.join(", ")}`),t.push(`By: ${e.by}${e.source==="agent"?" (agent)":""}`),e.supersedes!==null&&t.push(`Replaces: ${Z(n,e.supersedes)}`),t.join(`
|
|
214
|
+
`)}import{writeSync as tr}from"node:fs";import{existsSync as zo,readFileSync as Yo,writeFileSync as Jo}from"node:fs";import{join as qo}from"node:path";var Ko=`
|
|
208
215
|
:root {
|
|
209
216
|
color-scheme: light dark;
|
|
210
217
|
--bg: #ffffff; --fg: #1a1a1a; --muted: #6b6b6b; --line: #e2e2e2;
|
|
@@ -257,62 +264,67 @@ th { color: var(--muted); font-weight: 600; font-size: .78rem; text-transform: u
|
|
|
257
264
|
.criteria li.checked { color: var(--done); }
|
|
258
265
|
.empty { color: var(--muted); }
|
|
259
266
|
footer { margin-top: 2.5rem; color: var(--muted); font-size: .8rem; border-top: 1px solid var(--line); padding-top: .75rem; }
|
|
260
|
-
`;function
|
|
261
|
-
`)}var
|
|
267
|
+
`;function rs(e,n,t=""){let o=n===0?0:Math.round(e/n*100);return`<div class="bar ${t}"><span style="width:${o}%"></span></div>`}function Uo(e,n){let t=[];if(e.contestedBy.length>0?t.push(`<span class="pill danger">contested: ${v(e.contestedBy.join(", "))}</span>`):e.claimedBy!==null&&t.push(`<span class="pill">claimed ${v(e.claimedBy)}</span>`),e.blockedBy.length>0&&t.push(`<span class="pill danger">blocked by ${e.blockedBy.length}</span>`),e.criteria.length>0){let a=e.criteria.filter(l=>l.checked).length,d=a===e.criteria.length?"pill":"pill warn";t.push(`<span class="${d}">${a}/${e.criteria.length} criteria</span>`)}let o=e.milestone===null?null:n.milestones.find(a=>a.id===e.milestone)?.name??null;o!==null&&t.push(`<span class="pill">${v(o)}</span>`);let s=[e.assignee===null?"":v(e.assignee),e.estimate===null?"":`${e.estimate} pts`,e.due===null?"":`due ${v(e.due)}`].filter(a=>a.length>0),r=e.criteria.length===0?"":`<ul class="criteria">${e.criteria.map(a=>`<li class="${a.checked?"checked":""}">${a.checked?"\u2611":"\u2610"} ${v(a.text)}</li>`).join("")}</ul>`;return[`<div class="card ${e.contestedBy.length>0?"contested":e.blockedBy.length>0?"blocked":v(e.status)}">`,`<span class="label">${v(e.label)}</span>`,`<span class="title">${v(e.title)}</span>`,t.length>0?t.join(""):"",r,s.length>0?`<div class="meta">${s.join(" \xB7 ")}</div>`:"","</div>"].join("")}function is(e,n=null,t=new Date){let o=t.toISOString().slice(0,16).replace("T"," "),s=[];s.push("<h1>Board</h1>"),s.push(`<p class="stamp">Snapshot of <code>.kadence/</code> at ${v(o)} UTC. A file, not a page: nothing here is live, and regenerating it is <code>kadence board export --html</code>.</p>`);let r=e.tasks.length>0;r||s.push('<p class="empty">No tasks yet. Create the first one with <code>kadence task add "title"</code>.</p>');{let a=e.sprints.find(l=>l.status==="active");if(r&&a!==void 0){let l=ee(e,a.id);if(s.push(`<h2>Sprint: ${v(a.name)}</h2>`),l!==null&&(s.push(rs(l.velocity,l.committed,"done")),s.push(`<p class="stamp">${l.velocity} of ${l.committed} points done, ${l.carriedOver.length} carrying over.</p>`)),n!==null&&n.committed>0&&n.days.length>0){s.push("<h2>Burndown</h2>"),s.push('<div class="chart">');for(let c of n.days){let u=Math.round(c.remaining/n.committed*100),m=Math.round(c.ideal/n.committed*100);s.push(`<div><span class="day">${v(c.date.slice(5))}</span><span class="track"><span class="bar"><span style="width:${u}%"></span></span></span><span class="day">${c.remaining} / ${m}%</span></div>`)}s.push("</div>")}}if(e.milestones.length>0){s.push("<h2>Milestones</h2>"),s.push("<table><tr><th>Milestone</th><th>Due</th><th>Progress</th><th>Points</th><th>Tasks</th></tr>");for(let l of e.milestones)s.push(`<tr><td>${v(l.name)}${l.status==="closed"?' <span class="pill">closed</span>':""}</td><td>${v(l.due??"")}</td><td>${rs(l.donePoints,l.totalPoints)}</td><td>${l.donePoints}/${l.totalPoints}</td><td>${l.doneTasks}/${l.totalTasks}</td></tr>`);s.push("</table>")}if(r){s.push("<h2>Tasks</h2>"),s.push('<div class="columns">');let l=[...e.statuses,...e.orphanStatuses];for(let c of l){let u=e.tasks.filter(m=>m.status===c);if(!(u.length===0&&c===L)){s.push('<div class="column">'),s.push(`<h3>${v(c)} (${u.length})</h3>`),u.length===0&&s.push('<p class="empty">\u2014</p>');for(let m of u)s.push(Uo(m,e));s.push("</div>")}}s.push("</div>")}let d=e.decisions.filter(l=>l.supersededBy===null);if(d.length>0){s.push("<h2>Decisions in force</h2>");for(let l of d)s.push('<div class="decision">'),s.push(`<strong>${v(l.label)} ${v(l.title)}</strong>`),s.push(`<div class="why">Why: ${v(l.why)}</div>`),l.rejected!==null&&s.push(`<div class="why">Rejected: ${v(l.rejected)}</div>`),s.push("</div>")}}let i=e.tasks.filter(a=>a.status!==I&&a.status!==L);return s.push(`<footer>${e.tasks.length} tasks, ${i.length} open. Generated by kadence from the event journal. No server, no network.</footer>`),["<!doctype html>",'<html lang="en">',"<head>",'<meta charset="utf-8">','<meta name="viewport" content="width=device-width, initial-scale=1">',"<title>kadence board</title>",`<style>${Ko}</style>`,"</head>","<body>","<main>",...s,"</main>","</body>","</html>",""].join(`
|
|
268
|
+
`)}var as="<!-- kadence:board:begin -->",Ze="<!-- kadence:board:end -->";function F(e){return e.replace(/\|/g,"\\|").replace(/\n+/g," ").replace(/kadence:board:(begin|end)/g,"kadence:board:\u200B$1")}function ds(e,n,t=20){if(n===0)return`${"\u2591".repeat(t)} 0%`;let o=Math.round(e/n*100),s=Math.round(o/100*t);return`${"\u2588".repeat(s)}${"\u2591".repeat(t-s)} ${o}%`}function Ho(e,n){let t=e.criteria.length===0?"":`${e.criteria.filter(s=>s.checked).length}/${e.criteria.length}`,o=e.milestone===null?"":n.find(s=>s.id===e.milestone)?.name??"";return`| ${F(e.label)} | ${F(e.title)} | ${F(e.status)} | ${F(e.priority)} | ${e.estimate??""} | ${F(e.assignee??"")} | ${t} | ${F(o)} |`}function Qe(e,n=new Date){let t=["# Board"],o=n.toISOString().slice(0,16).replace("T"," ");t.push("",`Snapshot of \`.kadence/\` at ${o} UTC. Regenerate with \`kadence board export --md\`.`);let s=e.tasks.length>0,r=e.sprints.find(d=>d.status==="active");if(s&&r!==void 0){let d=ee(e,r.id);t.push("",`## Sprint: ${F(r.name)}`),d!==null&&(t.push(""),t.push(`${ds(d.velocity,d.committed)} \u2014 ${d.velocity} of ${d.committed} points`))}if(e.milestones.length>0){t.push("","## Milestones","","| Milestone | Due | Progress | Points | Tasks |","|---|---|---|---|---|");for(let d of e.milestones)t.push(`| ${F(d.name)}${d.status==="closed"?" (closed)":""} | ${F(d.due??"")} | ${ds(d.donePoints,d.totalPoints,10)} | ${d.donePoints}/${d.totalPoints} | ${d.doneTasks}/${d.totalTasks} |`)}if(s){t.push("","## Tasks","","| Task | Title | Status | Priority | Points | Assignee | Criteria | Milestone |","|---|---|---|---|---|---|---|---|");let d=new Map(e.statuses.map((c,u)=>[c,u])),l=[...e.tasks].sort((c,u)=>(d.get(c.status)??99)-(d.get(u.status)??99)||(c.id<u.id?-1:1));for(let c of l)t.push(Ho(c,e.milestones))}else t.push("","No tasks yet.","",' kadence task add "first task"');let i=e.decisions.filter(d=>d.supersededBy===null);if(i.length>0){t.push("","## Decisions in force");for(let d of i)t.push("",`**${d.label} ${F(d.title)}**`,"",`Why: ${F(d.why)}`),d.rejected!==null&&t.push("",`Rejected: ${F(d.rejected)}`)}let a=e.tasks.filter(d=>d.status!==I&&d.status!==L);return t.push("",`${e.tasks.length} tasks, ${a.length} open.`),`${t.join(`
|
|
262
269
|
`)}
|
|
263
|
-
`}function
|
|
270
|
+
`}function ls(e,n){let t=`${as}
|
|
264
271
|
${n.trimEnd()}
|
|
265
|
-
${
|
|
272
|
+
${Ze}`,o=e.indexOf(as),s=o===-1?-1:e.indexOf(Ze,o);if(o!==-1&&s!==-1&&s>o)return`${e.slice(0,o)}${t}${e.slice(s+Ze.length)}`;let r=e.endsWith(`
|
|
266
273
|
`)?"":`
|
|
267
|
-
`;return`${e}${
|
|
274
|
+
`;return`${e}${r}
|
|
268
275
|
${t}
|
|
269
|
-
`}var
|
|
276
|
+
`}var Xe="cancelled",Vo=["id","label","title","status","type","priority","estimate","assignee","claimedBy","contestedBy","blockedBy","sprint","milestone","due"];function us(e,n,t,o,s=!1){let r=A(e,n);if(!j(r))return r;let{fields:i,error:a}=xt(o);if(a!==null)return a;let d=i??(s?[...Vo]:null),{state:l,warnings:c}=C(r.root,r.actor),u=l.tasks.filter(k=>k.status!==Xe);if(t.assignee!==void 0){let k=t.assignee.toLowerCase(),b=k==="me"?r.actor.toLowerCase():k;u=u.filter(x=>(x.assignee??"").toLowerCase()===b)}if(t.sprint==="active"){let k=l.sprints.find(b=>b.status==="active"||b.status==="planned");u=k===void 0?[]:u.filter(b=>b.sprint===k.id)}let m={};for(let k of l.statuses)k!==Xe&&(m[k]=u.filter(b=>b.status===k));let g=l.orphanStatuses.filter(k=>k!==Xe);for(let k of g)m[k]=u.filter(b=>b.status===k);let h=g.length>0?[`Statuses not in the board configuration: ${g.join(", ")}.
|
|
270
277
|
Tasks there are still shown. Add the column or move them:
|
|
271
|
-
kadence board config --statuses "..."`]:[];return{ok:!0,exitCode:0,warnings:[...c,...
|
|
278
|
+
kadence board config --statuses "..."`]:[];return{ok:!0,exitCode:0,warnings:[...c,...h],message:ht(m,ke(n,process.stdout.isTTY===!0)),data:{schema:"kadence/v1",ok:!0,columns:Object.fromEntries(Object.entries(m).map(([k,b])=>[k,b.map(x=>St(x,d,l))]))}}}function ms(e,n,t,o,s){let r=A(e,n);if(!j(r))return r;let{state:i,warnings:a}=C(r.root,r.actor);if(t===void 0&&o===void 0&&s===void 0){let m=i.dod.length===0?"Definition of done: not set":`Definition of done: ${i.dod.join(", ")}`;return{ok:!0,exitCode:0,warnings:[...a,...cs(i.statuses,i.started)],message:`Board columns: ${i.statuses.join(", ")}
|
|
272
279
|
Started: ${i.started} (cycle time and actual hours count from here)
|
|
273
280
|
${m}
|
|
274
281
|
|
|
275
282
|
Change them with:
|
|
276
283
|
kadence board config --statuses "todo,doing,review,done"
|
|
277
284
|
kadence board config --started doing
|
|
278
|
-
kadence board config --dod "tests green,docs updated"`,data:{schema:"kadence/v1",ok:!0,statuses:i.statuses,dod:i.dod,started:i.started}}}if(t===void 0&&
|
|
279
|
-
Cycle time, work item age and a sprint's actual hours are measured from this column.`,data:{schema:"kadence/v1",ok:!0,started:
|
|
285
|
+
kadence board config --dod "tests green,docs updated"`,data:{schema:"kadence/v1",ok:!0,statuses:i.statuses,dod:i.dod,started:i.started}}}if(t===void 0&&o===void 0&&s!==void 0){let m=et(s,i.statuses);if(typeof m!="string")return m;let g=m;return g===i.started?{ok:!0,exitCode:0,warnings:a,message:`Work already counts as started at "${g}".`,data:{schema:"kadence/v1",ok:!0,started:g}}:(O(r.root,{id:R(),type:"board.configured",entity:R(),actor:r.actor,ts:new Date().toISOString(),source:r.source,data:{started:g}}),{ok:!0,exitCode:0,warnings:a,message:`Work counts as started at "${g}".
|
|
286
|
+
Cycle time, work item age and a sprint's actual hours are measured from this column.`,data:{schema:"kadence/v1",ok:!0,started:g}})}if(t===void 0){let m;if(s!==void 0){let h=et(s,i.statuses);if(typeof h!="string")return h;m=h}let g=o.split(",").map(h=>h.trim()).filter(h=>h.length>0);return g.length===i.dod.length&&g.every((h,k)=>h===i.dod[k])?{ok:!0,exitCode:0,warnings:a,message:g.length===0?"There is already no definition of done.":`Definition of done is already: ${g.join(", ")}`,data:{schema:"kadence/v1",ok:!0,dod:g}}:(O(r.root,{id:R(),type:"board.configured",entity:R(),actor:r.actor,ts:new Date().toISOString(),source:r.source,data:{dod:g,...m===void 0?{}:{started:m}}}),{ok:!0,exitCode:0,warnings:a,message:(g.length===0?"Definition of done cleared. New tasks start with no criteria.":`Definition of done: ${g.join(", ")}
|
|
280
287
|
New tasks start with these criteria. Tasks that already exist keep theirs.`)+(m===void 0?"":`
|
|
281
|
-
Work counts as started at "${m}".`),data:{schema:"kadence/v1",ok:!0,dod:
|
|
282
|
-
${l.length} task(s) remain in removed columns: ${[...new Set(l.map(m=>m.status))].join(", ")}. They are still listed.`:"";return{ok:!0,exitCode:0,warnings:[...a,...
|
|
283
|
-
Work counts as started at "${c}".`),data:{schema:"kadence/v1",ok:!0,statuses:d}}}var
|
|
288
|
+
Work counts as started at "${m}".`),data:{schema:"kadence/v1",ok:!0,dod:g,...m===void 0?{}:{started:m}}})}let d=t.split(",").map(m=>m.trim().toLowerCase().replace(/\s+/g,"_")).filter(m=>m.length>0);if(d.length===0)return y(2,"invalid_argument","At least one status is required.",{received:t});if(new Set(d).size!==d.length)return y(2,"invalid_argument","The same status is listed twice.",{received:t});if(!d.includes(I))return y(2,"invalid_argument",`The list must include "${I}" \u2014 velocity and burndown are computed from it.`,{received:t});let l=i.tasks.filter(m=>!d.includes(m.status)&&m.status!==L),c;if(s!==void 0){let m=et(s,d);if(typeof m!="string")return m;c=m}O(r.root,{id:R(),type:"board.configured",entity:R(),actor:r.actor,ts:new Date().toISOString(),source:r.source,data:{statuses:d,...o===void 0?{}:{dod:o.split(",").map(m=>m.trim()).filter(m=>m.length>0)},...c===void 0?{}:{started:c}}});let u=l.length>0?`
|
|
289
|
+
${l.length} task(s) remain in removed columns: ${[...new Set(l.map(m=>m.status))].join(", ")}. They are still listed.`:"";return{ok:!0,exitCode:0,warnings:[...a,...cs(d,c??i.started)],message:`Board columns: ${d.join(", ")}${u}`+(c===void 0?"":`
|
|
290
|
+
Work counts as started at "${c}".`),data:{schema:"kadence/v1",ok:!0,statuses:d}}}var Go="kadence-board.html",Zo="kadence-board.md";function ps(e,n,t){let o=A(e,n);if(!j(o))return o;if(t.html!==!0&&t.md!==!0)return y(2,"invalid_argument",`Which format?
|
|
284
291
|
kadence board export --html
|
|
285
|
-
kadence board export --md`,{hint:"kadence board export --html"});if(t.html===!0&&t.md===!0)return
|
|
292
|
+
kadence board export --md`,{hint:"kadence board export --html"});if(t.html===!0&&t.md===!0)return y(2,"invalid_argument","One format at a time: --html or --md.",{hint:"kadence board export --html"});if(t.readme===!0&&t.html===!0)return y(2,"invalid_argument","--readme writes markdown. Use --md with it.",{hint:"kadence board export --md --readme"});let{state:s,warnings:r}=C(o.root,o.actor);if(t.md===!0&&t.readme===!0){if(t.file!==void 0)return y(2,"invalid_argument","--readme writes into README.md, so --file has nowhere to go.",{received:t.file,hint:"kadence board export --md --file docs/board.md"});let l=qo(o.root,"README.md");if(!zo(l))return y(1,"conflicting_state",`There is no README.md here to update.
|
|
286
293
|
Write the board to a file instead:
|
|
287
|
-
kadence board export --md`,{hint:"kadence board export --md"});let c=
|
|
288
|
-
It is a snapshot: rerun this after the board changes.`,data:{schema:"kadence/v1",ok:!0,format:"md",path:l,section:!0,bytes:Buffer.byteLength(c)}}}let i=t.html===!0?
|
|
289
|
-
`+(t.html===!0?"Open it from disk \u2014 there is no server, and the page makes no requests.":"A snapshot for a README or a pull request."),data:{schema:"kadence/v1",ok:!0,format:t.html===!0?"html":"md",path:d,section:!1,bytes:a.bytes}}}function
|
|
290
|
-
kadence board config --started ${e[1]??e[0]??"doing"}`]}function
|
|
291
|
-
Available: ${n.join(", ")}`,{received:e,allowed:n,hint:"kadence board config --json"})}var
|
|
292
|
-
kadence template save bug --type bug --priority high --label triage`,{received:t}):(
|
|
293
|
-
kadence task add "title" --template ${
|
|
294
|
-
kadence template save bug --type bug --priority high`,data:{schema:"kadence/v1",ok:!0,templates:[]}}:{ok:!0,exitCode:0,warnings:s,message:
|
|
295
|
-
`),data:{schema:"kadence/v1",ok:!0,templates:
|
|
296
|
-
kadence template list`,{received:t,hint:"kadence template list --json"})}function
|
|
294
|
+
kadence board export --md`,{hint:"kadence board export --md"});let c=ls(Yo(l,"utf8"),Qe(s));return Jo(l,c,"utf8"),{ok:!0,exitCode:0,warnings:r,message:`Board section updated in ${l}.
|
|
295
|
+
It is a snapshot: rerun this after the board changes.`,data:{schema:"kadence/v1",ok:!0,format:"md",path:l,section:!0,bytes:Buffer.byteLength(c)}}}let i=t.html===!0?is(s,Qo(o.root,s)):Qe(s),a=De(o.root,t.file,t.html===!0?Go:Zo,i,"kadence board export --html --file docs/board.html");if("exitCode"in a)return a;let d=a.path;return{ok:!0,exitCode:0,warnings:r,message:`Wrote ${d}.
|
|
296
|
+
`+(t.html===!0?"Open it from disk \u2014 there is no server, and the page makes no requests.":"A snapshot for a README or a pull request."),data:{schema:"kadence/v1",ok:!0,format:t.html===!0?"html":"md",path:d,section:!1,bytes:a.bytes}}}function Qo(e,n){let t=n.sprints.find(o=>o.status==="active");return t===void 0?null:Bt(n,rt(e).events,t)}function cs(e,n){return e.includes(n)?[]:[`Work is set to start at "${n}", which is not one of the columns any more. Cycle time and actual hours will be empty until it is:
|
|
297
|
+
kadence board config --started ${e[1]??e[0]??"doing"}`]}function et(e,n){let t=e.trim().toLowerCase().replace(/\s+/g,"_");return t===I||t===L?y(2,"invalid_argument",`Work cannot start at "${t}" \u2014 that is where it ends. Cycle time would always be zero.`,{received:e,allowed:n.filter(o=>o!==I&&o!==L)}):n.includes(t)?t:y(2,"unknown_status",`"${e}" is not one of this board's columns.
|
|
298
|
+
Available: ${n.join(", ")}`,{received:e,allowed:n,hint:"kadence board config --json"})}var Xo=["description","type","priority","estimate","labels","assignee"];function hs(e,n,t,o){let s=A(e,n);if(!j(s))return s;let r=t.trim();if(r.length===0)return y(2,"invalid_argument","A template needs a name.",{hint:"kadence template list --json"});let i={};for(let a of Xo)o[a]!==void 0&&(i[a]=o[a]);return Object.keys(i).length===0?y(2,"invalid_argument",`A template needs at least one field.
|
|
299
|
+
kadence template save bug --type bug --priority high --label triage`,{received:t}):(O(s.root,{id:R(),type:"template.saved",entity:R(),actor:s.actor,ts:new Date().toISOString(),source:s.source,data:{name:r,fields:i}}),{ok:!0,exitCode:0,message:`Template "${r}" saved: ${Object.keys(i).join(", ")}.
|
|
300
|
+
kadence task add "title" --template ${r}`,data:{schema:"kadence/v1",ok:!0,template:{name:r,fields:i}}})}function fs(e,n){let t=A(e,n);if(!j(t))return t;let{state:o,warnings:s}=C(t.root,t.actor);return o.templates.length===0?{ok:!0,exitCode:0,warnings:s,message:`No templates yet.
|
|
301
|
+
kadence template save bug --type bug --priority high`,data:{schema:"kadence/v1",ok:!0,templates:[]}}:{ok:!0,exitCode:0,warnings:s,message:o.templates.map(r=>{let i=Object.entries(r.fields).map(([a,d])=>`${a}=${Array.isArray(d)?d.join("/"):String(d)}`).join(" ");return` ${r.name.padEnd(14)} ${i}`}).join(`
|
|
302
|
+
`),data:{schema:"kadence/v1",ok:!0,templates:o.templates}}}function gs(e,n,t){let o=A(e,n);if(!j(o))return o;let{state:s,warnings:r}=C(o.root,o.actor);return s.templates.some(i=>i.name===t)?(O(o.root,{id:R(),type:"template.deleted",entity:R(),actor:o.actor,ts:new Date().toISOString(),source:o.source,data:{name:t}}),{ok:!0,exitCode:0,warnings:r,message:`Template "${t}" deleted.`}):y(1,"template_not_found",`No template "${t}".
|
|
303
|
+
kadence template list`,{received:t,hint:"kadence template list --json"})}function ks(e,n,t){let o=A(e,n);if(!j(o))return{error:o};let{state:s}=C(o.root,o.actor),r=s.templates.find(i=>i.name===t);if(r===void 0){let i=s.templates.map(a=>a.name);return{error:y(1,"template_not_found",`No template "${t}".`+(i.length>0?`
|
|
297
304
|
Available: ${i.join(", ")}`:`
|
|
298
|
-
kadence template save ...`),{received:t,...i.length>0?{allowed:i}:{}})}}return{fields:
|
|
299
|
-
`);if(n){let t=e.data??{schema:"kadence/v1",ok:e.ok,...e.ok?{}:{error:e.error??{message:e.message}}};
|
|
300
|
-
`)}else
|
|
301
|
-
`);process.exit(e.exitCode)}function
|
|
305
|
+
kadence template save ...`),{received:t,...i.length>0?{allowed:i}:{}})}}return{fields:r.fields}}function ge(e){return Array.isArray(e)?e.at(-1)??"":e}function nr(e){return Array.isArray(e)?e.join("; "):e}function Ne(e,n){let t=Buffer.from(n,"utf8"),o=0;for(;o<t.length;)try{o+=tr(e,t,o,t.length-o)}catch(s){if(s.code!=="EAGAIN")throw s}}var D=rn("kadence");function p(e,n){for(let t of e.warnings??[])Ne(2,`${t}
|
|
306
|
+
`);if(n){let t=e.data??{schema:"kadence/v1",ok:e.ok,...e.ok?{}:{error:e.error??{message:e.message}}};Ne(1,`${JSON.stringify(t)}
|
|
307
|
+
`)}else Ne(e.ok?1:2,`${e.message}
|
|
308
|
+
`);process.exit(e.exitCode)}function bs(e,n,t,o){if(e!==void 0)return e;Qt(process.env,process.stdout.isTTY===!0)||p(w(`No terminal available for an editor.
|
|
302
309
|
Pass the text directly:
|
|
303
|
-
--description "..."`),
|
|
310
|
+
--description "..."`),o);let s=Zt(process.env,n,t);return s.error!==null&&p({ok:!1,exitCode:1,message:s.error},o),s.text===null&&p({ok:!0,exitCode:0,message:"Aborted \u2014 nothing changed."},o),s.text}function sr(e,n=process.argv){let t,o=`--${e}`;for(let s=0;s<n.length;s++){let r=n[s];r===o?t=n[s+1]:r.startsWith(`${o}=`)&&(t=r.slice(o.length+1))}return t}function Oe(e,n=process.argv){let t=`--${e}`;for(let o=0;o<n.length;o++){let s=n[o];if(s===t)return n[o+1];if(s.startsWith(`${t}=`))return s.slice(t.length+1)}}var or=["add","list","show","edit","move","assign","comment","log","parent","block","unblock","claim","release","ac","doc","cancel","delete"],rr=["create","add","edit","start","close","status","list","burndown"],ir=["save","list","delete"],ar=["create","add","list","close"],dr=["add","list","show"],ys=["add","edit","show","list","link"];function w(e,n={}){return y(2,"invalid_argument",e,n)}function lr(e){let n=e.commands,t=e.errors;return`kadence/v1 \u2014 ${n.length} commands, ${t.length} error codes.
|
|
304
311
|
${e.stability}
|
|
305
312
|
|
|
306
313
|
The machine-readable form is what agents read:
|
|
307
|
-
kadence schema --json`}D.command("milestone [action] [arg]","Milestones: create | add | list | close \u2014 grouping by outcome").option("--due <date>","Target date, YYYY-MM-DD").option("--milestone <ref>","Which milestone, by MS-N or name").option("--all","Include closed milestones, hidden by default").option("--json","Machine-readable output for agents").example(' kadence milestone create "1.0" --due 2026-12-01').example(" kadence milestone add KAD-1 --milestone 1.0").example(" kadence milestone list --json").example(" kadence milestone close 1.0").action((e,n,t)=>{let
|
|
308
|
-
kadence milestone create "1.0"`),
|
|
309
|
-
kadence milestone add KAD-1 --milestone 1.0`),
|
|
310
|
-
kadence milestone close 1.0`),
|
|
314
|
+
kadence schema --json`}D.command("milestone [action] [arg]","Milestones: create | add | list | close \u2014 grouping by outcome").option("--due <date>","Target date, YYYY-MM-DD").option("--milestone <ref>","Which milestone, by MS-N or name").option("--all","Include closed milestones, hidden by default").option("--json","Machine-readable output for agents").example(' kadence milestone create "1.0" --due 2026-12-01').example(" kadence milestone add KAD-1 --milestone 1.0").example(" kadence milestone list --json").example(" kadence milestone close 1.0").action((e,n,t)=>{let o=t.json===!0,s=process.cwd();switch(e){case"create":n===void 0&&p(w(`A milestone needs a name:
|
|
315
|
+
kadence milestone create "1.0"`),o),p(Vn(s,process.env,n,t.due===void 0?{}:{due:Oe("due")??String(t.due)}),o);break;case"add":(n===void 0||t.milestone===void 0)&&p(w(`A task and a milestone are required:
|
|
316
|
+
kadence milestone add KAD-1 --milestone 1.0`),o),p(Gn(s,process.env,n,Oe("milestone")??String(t.milestone)),o);break;case"close":n===void 0&&p(w(`Which milestone?
|
|
317
|
+
kadence milestone close 1.0`),o),p(Zn(s,process.env,n),o);break;case"list":case void 0:p(Qn(s,process.env,{...t.all===!0?{all:!0}:{},json:o}),o);break;default:p(w(`Unknown milestone action "${e}".`,{received:e,allowed:ar}),o)}});D.command("note [text]","Record something learned; `note list` reads them back").option("--task <ref>","The task it came out of").option("--limit <n>","At most this many, newest first").option("--json","Machine-readable output for agents").example(' kadence note "Tests need a git identity"').example(' kadence note "The redirect drops the cookie" --task KAD-1').example(" kadence note list --limit 5").action((e,n)=>{let t=n.json===!0,o=process.cwd(),s=n.limit===void 0?void 0:Number(n.limit);if(s!==void 0&&(!Number.isFinite(s)||s<1)&&p(w(`--limit must be a positive number, got "${n.limit}".`),t),e==="list"){p(Bn(o,process.env,{...n.task===void 0?{}:{task:n.task},...s===void 0?{}:{limit:s},json:t}),t);return}e===void 0&&p(w(`A note needs text:
|
|
311
318
|
kadence note "Tests need a git identity"
|
|
312
|
-
kadence note list`),t),
|
|
313
|
-
kadence decision add "Use ULIDs" --why "..."`),
|
|
314
|
-
kadence decision show DEC-1`),
|
|
315
|
-
Available: add, list, show`,{...e===void 0?{}:{received:e},allowed:
|
|
319
|
+
kadence note list`),t),p(Wn(o,process.env,e,n.task===void 0?{}:{task:n.task}),t)});D.command("decision [action] [arg]","Decisions: add | list | show \u2014 the why behind the work").option("--why <text>","Why this was chosen. Required \u2014 without it this is a changelog line").option("--rejected <text>","The alternative that was turned down").option("--task <ref>","The task this decision came out of").option("--supersedes <ref>","The decision this one replaces").option("--doc <path>","A document that carries the detail; repeat for several").option("--all","Include superseded decisions, hidden by default").option("--json","Machine-readable output for agents").example(' kadence decision add "Use ULIDs" --why "Clocks disagree between machines"').example(' kadence decision add "Use Avro" --why "..." --supersedes DEC-1').example(" kadence decision list --json").action((e,n,t)=>{let o=t.json===!0,s=process.cwd(),r=t.doc===void 0?void 0:Array.isArray(t.doc)?t.doc:[t.doc];switch(e){case"add":n===void 0&&p(w(`A title is required:
|
|
320
|
+
kadence decision add "Use ULIDs" --why "..."`),o),p(ts(s,process.env,n,{...t.why!==void 0?{why:ge(t.why)}:{},...t.rejected!==void 0?{rejected:nr(t.rejected)}:{},...t.task!==void 0?{task:ge(t.task)}:{},...t.supersedes!==void 0?{supersedes:ge(t.supersedes)}:{},...r!==void 0?{docs:r}:{}}),o);break;case void 0:case"list":p(ns(s,process.env,{...t.all===!0?{all:!0}:{},...t.task!==void 0?{task:ge(t.task)}:{}}),o);break;case"show":n===void 0&&p(w(`Which decision?
|
|
321
|
+
kadence decision show DEC-1`),o),p(ss(s,process.env,n),o);break;default:p(w(`Unknown action "${e}".
|
|
322
|
+
Available: add, list, show`,{...e===void 0?{}:{received:e},allowed:dr}),o)}});D.command("doc [action] [arg] [arg2]","Documentation: add | edit | show | list | link \u2014 kept in the journal, not in files").option("--body <text>","The text").option("--stdin","Read the text from standard input \u2014 for text too long for an argument").option("--file <path>","Read the text from a file; the file is not kept or linked").option("--title <text>","A new title, for edit").option("--task <ref>","The task this explains (add), or narrow the list to one task").option("--json","Machine-readable output for agents").example(' kadence doc add "Auth" --body "How login works." --task KAD-1').example(" kadence doc edit DOC-1 --file draft.txt").example(" kadence doc show DOC-1 --json").example(" kadence doc link DOC-1 KAD-2").action((e,n,t,o)=>{let s=o.json===!0,r=process.cwd(),i=(m,g)=>g===void 0?void 0:sr(m)??String(ge(g)),a=i("body",o.body),d=i("file",o.file),l=i("task",o.task),c=i("title",o.title),u={...a!==void 0?{body:a}:{},...d!==void 0?{file:d}:{},...o.stdin===!0?{stdin:er(0,"utf8")}:{}};switch(e){case"add":n===void 0&&p(w(`A document needs a title:
|
|
323
|
+
kadence doc add "Auth" --body "How login works."`),s),p(Un(r,process.env,String(n),{...u,...l!==void 0?{task:l}:{}}),s);break;case"edit":n===void 0&&p(w(`Which document?
|
|
324
|
+
kadence doc edit DOC-1 --body "\u2026"`),s),p(Hn(r,process.env,String(n),{...u,...c!==void 0?{title:c}:{}}),s);break;case"show":n===void 0&&p(w(`Which document?
|
|
325
|
+
kadence doc show DOC-1`),s),p(zn(r,process.env,String(n)),s);break;case void 0:case"list":p(Yn(r,process.env,l!==void 0?{task:l}:{}),s);break;case"link":(n===void 0||t===void 0)&&p(w(`A link needs a document and a task:
|
|
326
|
+
kadence doc link DOC-1 KAD-2`),s),p(Jn(r,process.env,String(n),String(t)),s);break;default:p(w(`Unknown action "${e}".
|
|
327
|
+
Available: ${ys.join(", ")}`,{received:e,allowed:ys}),s)}});D.command("schema","The machine-readable --json contract, for agents").option("--json","Machine-readable output for agents").example(" kadence schema --json").action(e=>{let n=e.json===!0,t=ct("0.6.0");p({ok:!0,exitCode:0,message:lr(t),data:{schema:"kadence/v1",ok:!0,contract:t}},n)});D.command("prime","Everything a session needs before it starts. Short by design").option("--json","Machine-readable output for agents").example(" kadence prime").example(" kadence prime --json").action(e=>{p(kn(process.cwd(),process.env,{json:e.json===!0}),e.json===!0)});D.command("ready","What can be started right now: open, unblocked, unclaimed").option("-a, --assignee <who>",'Only this person; "me" for yourself').option("--limit <n>","At most this many tasks").option("--json","Machine-readable output for agents").example(" kadence ready").example(" kadence ready --assignee me --json").action(e=>{let n=e.limit===void 0?void 0:Number(e.limit);n!==void 0&&(!Number.isFinite(n)||n<1)&&p(w(`--limit must be a positive number, got "${e.limit}".`),e.json===!0),p(pn(process.cwd(),process.env,{...e.assignee===void 0?{}:{assignee:e.assignee},...n===void 0?{}:{limit:n},json:e.json===!0}),e.json===!0)});D.command("stats","Where the project stands: counts, blockers, contested claims, velocity").option("--json","Machine-readable output for agents").example(" kadence stats").action(e=>{p(yn(process.cwd(),process.env,{json:e.json===!0}),e.json===!0)});D.command("report [name]",`Reports folded from the journal: ${Te.join(" | ")}`).option("--list","Name every report and what each one answers").option("--since <days>","flow, cfd, attention: window ending today, in calendar days (default 30d)").option("--sprint <name>","burndown: a sprint by name, rather than the active one").option("--html","Write one self-contained page instead of printing; charts included, no network").option("--file <path>","html: where to write it (default kadence-<report>.html)").option("--json","Machine-readable output for agents").example(" kadence report --list every report, and what it answers").example(" kadence report flow cycle time, throughput, aging work").example(" kadence report flow --since 90d").example(" kadence report cfd tasks per column, per day").example(" kadence report attention work in flight that nobody is moving").example(" kadence report burndown the active sprint against an even burn").example(" kadence report velocity committed against finished, sprint by sprint").example(" kadence report workload who is carrying what right now").example(" kadence report flow --html the same numbers as a page, with charts").example(" kadence report cfd --html --file docs/cfd.html").action((e,n)=>{p(_n(process.cwd(),process.env,e,{...n.since===void 0?{}:{since:Oe("since")??String(n.since)},...n.list===!0?{list:!0}:{},...n.sprint===void 0?{}:{sprint:String(n.sprint)},...n.html===!0?{html:!0}:{},...n.file===void 0?{}:{file:String(n.file)},json:n.json===!0}),n.json===!0)});D.command("compact","Fold old months into one file each; cold start on a long journal drops from ~200 ms to ~20 ms").option("--keep-months <n>","Months to keep as separate files, counting this one (default 2)").option("--dry-run","Say what would be archived and write nothing").option("--json","Machine-readable output for agents").example(" kadence compact --dry-run").example(" kadence compact --keep-months 3").action(e=>{let n=Oe("keep-months"),t=e.keepMonths===void 0?void 0:Number(n??e.keepMonths);p($n(process.cwd(),process.env,{...t===void 0?{}:{keepMonths:t,keepMonthsRaw:n??String(e.keepMonths)},...e.dryRun===!0?{dryRun:!0}:{},json:e.json===!0}),e.json===!0)});D.command("completion [action]",'Shell completion; "install" writes it where your shell looks').option("--shell <name>",`Shell: ${oe.join(" | ")}; detected from $SHELL by default`).option("--force","Overwrite a completion file kadence did not write").option("--json","Machine-readable output for agents").example(" kadence completion print the script").example(" kadence completion install --shell zsh").action((e,n)=>{let t=n.json===!0;e!==void 0&&e!=="install"&&p(w(`Unknown completion action "${e}".`,{received:e,allowed:["install"]}),t),p(In(process.env,{...n.shell===void 0?{}:{shell:n.shell},...e==="install"?{install:!0}:{},...n.force===!0?{force:!0}:{},isTty:process.stdout.isTTY===!0}),t)});D.command("init","Set up kadence in this repository").option("--hooks","Also add a SessionStart hook running `kadence prime` to .claude/settings.json").example(" kadence init").example(" kadence init --hooks").action(e=>{let n=un(process.cwd(),"0.6.0",{hooks:e.hooks===!0});p({ok:n.ok,message:n.message,exitCode:n.ok?0:1},!1)});D.command("task [action] [arg] [value] [extra]","Tasks: add | list | show | move | assign | ac | doc").option("--title <text>","New title (for edit)").option("-d, --description <text>","Full description; use quotes for multiple lines").option("--type <type>",`Type: ${ut.join(" | ")}`).option("--priority <level>",`Priority: ${mt.join(" | ")}`).option("-a, --assignee <who>","Assignee, e.g. dev@example.com").option("--label <name>","Label; repeat the flag for several. On edit, the set becomes exactly this").option("--add-label <name>","Add one label, leaving the rest; repeat for several").option("--remove-label <name>","Remove one label, leaving the rest; repeat 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: ${_e.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: ${yt.join(" | ")}`).option("--tree","Show parent/child structure").option("--branch","Only the work this branch introduced").option("--base <name>","What --branch compares against; main by default").option("--parent <task>",'Parent task, e.g. KAD-1 (use "none" to detach)').option("--template <name>","Pre-fill fields from a saved template").option("--no-dod","Skip the board's definition of done for this task").option("--fields <list>","JSON only: comma-separated task fields to return").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 list --branch what this branch is about").example(" kadence task list --branch --base release/1.0").example(" kadence task list --json --fields id,label,status").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 claim take the top of `kadence ready`").example(" kadence task claim KAD-1").example(" kadence task release KAD-1").example(' kadence task ac add KAD-1 "tests green"').example(" kadence task ac check KAD-1 1").example(" kadence task ac list KAD-1").example(" kadence task doc add KAD-1 docs/design.md create it and link it").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((e,n,t,o,s)=>{let r=s.json===!0,i=process.cwd();switch(e===void 0&&p(w(`Which action?
|
|
316
328
|
kadence task add "Fix login"
|
|
317
329
|
kadence task list
|
|
318
330
|
kadence task show KAD-1
|
|
@@ -321,53 +333,56 @@ Available: add, list, show`,{...e===void 0?{}:{received:e},allowed:Mr}),r)}});D.
|
|
|
321
333
|
kadence task assign KAD-1 dev@example.com
|
|
322
334
|
kadence task comment KAD-1 "text"
|
|
323
335
|
kadence task cancel KAD-1
|
|
324
|
-
kadence task delete KAD-1`),
|
|
325
|
-
kadence task add "Fix login"`),
|
|
326
|
-
kadence task add "Fix login" --estimate 3`),
|
|
336
|
+
kadence task delete KAD-1`),r),e){case"add":{n===void 0&&p(w(`A title is required:
|
|
337
|
+
kadence task add "Fix login"`),r);let a=s.estimate===void 0?void 0:Number(s.estimate);a!==void 0&&(!Number.isFinite(a)||a<0)&&p(w(`Estimate must be a positive number, got "${s.estimate}".
|
|
338
|
+
kadence task add "Fix login" --estimate 3`),r);let d={};if(s.template!==void 0){let c=ks(i,process.env,s.template);"error"in c?p(c.error,r):d=c.fields}let l=s.label===void 0?void 0:Array.isArray(s.label)?s.label:[s.label];p($t(i,process.env,n,{...d,...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}:{},...l!==void 0?{labels:l}:{},...s.due!==void 0?{due:s.due}:{},...s.parent!==void 0?{parent:s.parent}:{},...a!==void 0?{estimate:a}:{},...s.dod===!1?{noDod:!0}:{}}),r);break}case"doc":{let a=n==="add",d=a?t:n,l=a?o:t;(d===void 0||l===void 0)&&p(w(`A task and a path are required:
|
|
327
339
|
kadence task doc KAD-1 docs/design.md link an existing file
|
|
328
|
-
kadence task doc add KAD-1 docs/design.md create it and link it`),
|
|
340
|
+
kadence task doc add KAD-1 docs/design.md create it and link it`),r),p(Rt(i,process.env,d,l,a),r);break}case"log":(n===void 0||t===void 0)&&p(w(`A task and a duration are required:
|
|
329
341
|
kadence task log KAD-1 2h
|
|
330
|
-
kadence task log KAD-1 90m`),
|
|
342
|
+
kadence task log KAD-1 90m`),r),p(Ie(i,process.env,n,t),r);break;case"parent":(n===void 0||t===void 0)&&p(w(`A task and a parent are required:
|
|
331
343
|
kadence task parent KAD-2 KAD-1
|
|
332
|
-
kadence task parent KAD-2 none to detach`),
|
|
344
|
+
kadence task parent KAD-2 none to detach`),r),p(It(i,process.env,n,t),r);break;case"ac":{if((n===void 0||t===void 0)&&p(w(`An action and a task are required:
|
|
333
345
|
kadence task ac add KAD-1 "tests green"
|
|
334
346
|
kadence task ac check KAD-1 1
|
|
335
347
|
kadence task ac uncheck KAD-1 1
|
|
336
|
-
kadence task ac list KAD-1`,{...n===void 0?{}:{received:n},allowed:["add","check","uncheck","list"]}),
|
|
348
|
+
kadence task ac list KAD-1`,{...n===void 0?{}:{received:n},allowed:["add","check","uncheck","list"]}),r),n==="list"){p(_t(i,process.env,t),r);break}if(o===void 0&&p(w(n==="add"?`The criterion text is missing:
|
|
337
349
|
kadence task ac add ${t} "tests green"`:`Which criterion?
|
|
338
|
-
kadence task ac ${n} ${t} 1`,{received:n}),
|
|
339
|
-
kadence task release KAD-1`),
|
|
350
|
+
kadence task ac ${n} ${t} 1`,{received:n}),r),n==="add"){p(Ot(i,process.env,t,o),r);break}if(n==="check"||n==="uncheck"){p(Mt(i,process.env,t,o,n==="uncheck"),r);break}p(w(`Unknown criteria action "${n}".`,{received:n,allowed:["add","check","uncheck","list"]}),r);break}case"claim":p(Et(i,process.env,n,s.assignee===void 0?{}:{assignee:s.assignee}),r);break;case"release":n===void 0&&p(w(`Which task?
|
|
351
|
+
kadence task release KAD-1`),r),p(Nt(i,process.env,n),r);break;case"block":case"unblock":(n===void 0||t===void 0)&&p(w(`A task and a blocker are required:
|
|
340
352
|
kadence task block KAD-2 KAD-1 KAD-2 waits for KAD-1
|
|
341
|
-
kadence task unblock KAD-2 KAD-1`),
|
|
342
|
-
kadence task edit KAD-1 --priority high`),
|
|
343
|
-
kadence task comment KAD-1 "text"`),
|
|
344
|
-
kadence task cancel KAD-1`),
|
|
345
|
-
kadence task delete KAD-1`),
|
|
346
|
-
kadence task show KAD-1`),
|
|
353
|
+
kadence task unblock KAD-2 KAD-1`),r),p(Lt(i,process.env,n,t,e==="unblock"),r);break;case"edit":{n===void 0&&p(w(`Which task?
|
|
354
|
+
kadence task edit KAD-1 --priority high`),r);let a=s.estimate===void 0?void 0:Number(s.estimate);a!==void 0&&(!Number.isFinite(a)||a<0)&&p(w(`Estimate must be a positive number, got "${s.estimate}".`),r);let d=h=>h===void 0?void 0:Array.isArray(h)?h:[h],l=d(s.label),c=d(s.addLabel),u=d(s.removeLabel),m=s.title!==void 0||s.description!==void 0||s.type!==void 0||s.priority!==void 0||s.due!==void 0||a!==void 0||l!==void 0||c!==void 0||u!==void 0||t!==void 0,g=s.description;if(!m){let h=Pe(i,process.env,n);h.ok||p(h,r);let k=h.data.task??{description:null};g=bs(void 0,k.description??"",`Editing the description of ${n}.`,r)}p(At(i,process.env,n,{...s.title!==void 0?{title:s.title}:t!==void 0?{title:t}:{},...g!==void 0?{description:g}:{},...s.type!==void 0?{type:s.type}:{},...s.priority!==void 0?{priority:s.priority}:{},...s.due!==void 0?{due:s.due}:{},...a!==void 0?{estimate:a}:{},...l!==void 0?{labels:l}:{},...c!==void 0?{addLabels:c}:{},...u!==void 0?{removeLabels:u}:{}}),r);break}case"comment":{n===void 0&&p(w(`Which task?
|
|
355
|
+
kadence task comment KAD-1 "text"`),r);let a=bs(t,"",`Comment on ${n}.`,r);p(Pt(i,process.env,n,a??""),r);break}case"cancel":n===void 0&&p(w(`Which task?
|
|
356
|
+
kadence task cancel KAD-1`),r),p(jt(i,process.env,n),r);break;case"delete":n===void 0&&p(w(`Which task?
|
|
357
|
+
kadence task delete KAD-1`),r),p(Dt(i,process.env,n),r);break;case"list":p(wt(i,process.env,{...s.status!==void 0?{status:s.status}:{},...s.search!==void 0?{search:s.search}:{},...s.type!==void 0?{type:s.type}:{},...s.priority!==void 0?{priority:s.priority}:{},...s.assignee!==void 0?{assignee:s.assignee}:{},...s.label!==void 0?{label:Array.isArray(s.label)?s.label.at(-1):s.label}:{},...s.overdue===!0?{overdue:!0}:{},...s.dueBefore!==void 0?{dueBefore:s.dueBefore}:{},...s.sort!==void 0?{sort:s.sort}:{},...s.tree===!0?{tree:!0}:{},...s.branch===!0?{branch:!0}:{},...s.base!==void 0?{base:s.base}:{},...r&&s.fields!==void 0?{fields:s.fields}:{}}),r);break;case"show":n===void 0&&p(w(`Which task?
|
|
358
|
+
kadence task show KAD-1`),r),p(Pe(i,process.env,n),r);break;case"move":(n===void 0||t===void 0)&&p(w(`A task and a target status are required:
|
|
347
359
|
kadence task move KAD-1 done
|
|
348
|
-
Statuses: ${
|
|
360
|
+
Statuses: ${_e.join(", ")}`),r),p(vt(i,process.env,n,t),r);break;case"assign":(n===void 0||t===void 0)&&p(w(`A task and an assignee are required:
|
|
349
361
|
kadence task assign KAD-1 dev@example.com
|
|
350
|
-
kadence task assign KAD-1 none to unassign`),
|
|
362
|
+
kadence task assign KAD-1 none to unassign`),r),p(Ct(i,process.env,n,t),r);break;default:p(w(`Unknown action "${e}".
|
|
351
363
|
Available: add, list, show, edit, move, assign, comment, log,
|
|
352
364
|
parent, block, unblock, cancel, delete
|
|
353
|
-
kadence task --help`,{received:e,allowed:
|
|
365
|
+
kadence task --help`,{received:e,allowed:or}),r)}});D.command("board [action]",'Kanban board in the terminal; "config" edits it, "export" writes a snapshot').option("--fields <list>","JSON only: comma-separated task fields to return").option("--statuses <list>",'Comma-separated columns, e.g. "todo,doing,done"').option("--dod <list>",'Criteria every new task starts with, e.g. "tests green,docs updated"').option("--started <status>","The column where work counts as started; cycle time is measured from it").option("--summary","JSON only: column state without history or comments").option("--html","export: one self-contained HTML file, no server and no network").option("--md","export: markdown for a README or a pull request").option("--readme","export: update the section between markers in README.md").option("--file <path>","export: where to write it").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 --json --fields label,status,assignee").example(" kadence board --json --summary the state, without the history").example(" kadence board config").example(' kadence board config --statuses "todo,doing,review,done"').example(' kadence board config --dod "tests green,docs updated"').example(" kadence board config --started doing where cycle time starts counting").example(" kadence board export --html").example(" kadence board export --md --readme").action((e,n)=>{if(e==="export"){p(ps(process.cwd(),process.env,{...n.html===!0?{html:!0}:{},...n.md===!0?{md:!0}:{},...n.readme===!0?{readme:!0}:{},...n.file===void 0?{}:{file:n.file}}),n.json===!0);return}e==="config"&&p(ms(process.cwd(),process.env,n.statuses,n.dod,n.started),n.json===!0),e!==void 0&&p(w(`Unknown action "${e}".
|
|
354
366
|
Available: config, export
|
|
355
|
-
kadence board --help`,{received:e,allowed:["config","export"]}),n.json===!0),
|
|
367
|
+
kadence board --help`,{received:e,allowed:["config","export"]}),n.json===!0),p(us(process.cwd(),process.env,{...n.assignee!==void 0?{assignee:n.assignee}:{},...n.sprint===!0?{sprint:"active"}:{}},n.json===!0?n.fields:void 0,n.json===!0&&n.summary===!0),n.json===!0)});D.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((e,n,t)=>{let o=t.json===!0,s=process.cwd();switch(e===void 0&&p(w(`Which action?
|
|
356
368
|
kadence sprint create "Sprint 1"
|
|
357
369
|
kadence sprint add KAD-1
|
|
358
370
|
kadence sprint edit --start 2026-09-01
|
|
359
371
|
kadence sprint start
|
|
360
372
|
kadence sprint close
|
|
361
373
|
kadence sprint status
|
|
362
|
-
kadence sprint list`),
|
|
363
|
-
kadence sprint create "Sprint 1"`),
|
|
374
|
+
kadence sprint list`),o),e){case"create":n===void 0&&p(w(`A sprint name is required:
|
|
375
|
+
kadence sprint create "Sprint 1"`),o),p(Kt(s,process.env,n),o);break;case"add":n===void 0&&p(w(`Which task?
|
|
364
376
|
kadence sprint add KAD-1
|
|
365
|
-
kadence sprint add KAD-1 --sprint "Sprint 2"`),
|
|
377
|
+
kadence sprint add KAD-1 --sprint "Sprint 2"`),o),p(Ut(s,process.env,n,t.sprint===void 0?{}:{sprint:t.sprint}),o);break;case"edit":p(qt(s,process.env,n,{...t.name!==void 0?{name:t.name}:{},...t.description!==void 0?{description:t.description}:{},...t.start!==void 0?{startDate:t.start}:{},...t.end!==void 0?{endDate:t.end}:{}}),o);break;case"start":p(Yt(s,process.env,n),o);break;case"close":p(Ht(s,process.env),o);break;case"status":p(zt(s,process.env),o);break;case"list":p(Jt(s,process.env),o);break;case"burndown":p(Gt(s,process.env,n),o);break;default:p(w(`Unknown action "${e}".
|
|
366
378
|
Available: create, add, edit, start, close, status, list, burndown
|
|
367
|
-
kadence sprint --help`,{received:e,allowed:
|
|
368
|
-
kadence template save bug --type bug`),
|
|
369
|
-
kadence template delete bug`),
|
|
370
|
-
Available: save, list, delete`,{received:e,allowed:
|
|
371
|
-
kadence task add "Fix login" --estimate 3
|
|
372
|
-
`),process.exit(
|
|
373
|
-
|
|
379
|
+
kadence sprint --help`,{received:e,allowed:rr}),o)}});D.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((e,n,t)=>{let o=t.json===!0,s=process.cwd();switch(e){case"save":{n===void 0&&p(w(`A template name is required:
|
|
380
|
+
kadence template save bug --type bug`),o);let r=t.label===void 0?void 0:Array.isArray(t.label)?t.label:[t.label];p(hs(s,process.env,n,{...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}:{},...r!==void 0?{labels:r}:{},...t.estimate!==void 0?{estimate:Number(t.estimate)}:{}}),o);break}case"list":case void 0:p(fs(s,process.env),o);break;case"delete":n===void 0&&p(w(`Which template?
|
|
381
|
+
kadence template delete bug`),o),p(gs(s,process.env,n),o);break;default:p(w(`Unknown action "${e}".
|
|
382
|
+
Available: save, list, delete`,{received:e,allowed:ir}),o)}});D.command("ui","Interactive kanban board").alias("board:ui").example(" kadence ui").action(async()=>{let{runUi:e}=await import("./chunks/ui-OTWFK76P.js"),n=await e(process.cwd(),process.env);n.ok||p(n,!1)});var $s=["init","prime","ready","task","decision","note","doc","board","ui","schema","sprint","milestone","template","report","stats","compact","completion"],ws=e=>{let n=$s.indexOf(e);return n===-1?$s.length:n};D.commands.sort((e,n)=>ws(e.name)-ws(n.name));D.help();D.version("0.6.0");var Q=process.argv;if(Q[2]==="task"&&Q[3]==="log"&&Q[4]!==void 0&&Q[5]!==void 0){let e=Ie(process.cwd(),process.env,Q[4],Q[5]),n=Q.includes("--json");p(e,n)}var nt=process.argv.slice(2).includes("--json"),tt=process.argv.findIndex((e,n)=>e.startsWith("-")&&/^-\d+(\.\d+)?$/.test(e)&&process.argv[n-1]==="--estimate");tt!==-1&&p(w(`Estimate must be a positive number, got "${process.argv[tt]}".
|
|
383
|
+
kadence task add "Fix login" --estimate 3`,{received:process.argv[tt]}),nt);var cr=new Set(["label","addLabel","removeLabel","rejected","doc"]);function ur(e){for(let[n,t]of Object.entries(e))n==="--"||cr.has(n)||!Array.isArray(t)||(e[n]=t.at(-1))}function vs(e){e.name!=="CACError"&&(Ne(2,`${e.stack??e.message}
|
|
384
|
+
`),process.exit(1));let n=D.matchedCommandName,t=/Unknown option `([^`]+)`/.exec(e.message)?.[1],o=n===void 0?"kadence --help":`kadence ${n} --help`;p(w(`${e.message}.
|
|
385
|
+
See what it takes:
|
|
386
|
+
${o}`,t===void 0?{}:{received:t}),nt)}try{D.parse(process.argv,{run:!1});let e=D.options.help===!0||D.options.version===!0;if(D.matchedCommand===void 0&&!e){let t=D.args[0];t===void 0&&(D.outputHelp(),process.exit(0)),p(w(`Unknown command "${String(t)}".
|
|
387
|
+
See all commands:
|
|
388
|
+
kadence --help`,{received:String(t),allowed:D.commands.map(o=>o.name)}),nt)}ur(D.options);let n=D.runMatchedCommand();n instanceof Promise&&n.catch(t=>vs(t))}catch(e){vs(e)}
|