kaizen-agent 1.40.1 → 1.40.3
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/cli/sources.test.ts +3 -0
- package/cli/sources.ts +7 -2
- package/package.json +2 -1
- package/skills/kaizen/spec-build.md +3 -1
- package/web/board/markdown.ts +8 -5
- package/web/board.js +2 -2
- package/web/notebook.js +1 -1
- package/web/term.js +104 -21
- package/web/term.ts +13 -1
package/cli/sources.test.ts
CHANGED
|
@@ -146,6 +146,9 @@ test("split: a header row holding a `#`, a year or a date cell is still the head
|
|
|
146
146
|
for (const head of ["#\tRequest\tStatus", "No\tRequest\tStatus\t2026", "No\tRequest\tStatus\t2026-09-30", "No\tRequest\tStatus\t17-Sep-2026", "\tRequest\tStatus"]) {
|
|
147
147
|
const body = `${head}\n1\tFix login page\tOpen\n2\tAdd export\tDone\n`;
|
|
148
148
|
expect(sift("sheet", body)).toEqual({ items: [{ text: "Fix login page", notes: "1 · Open", row: 2 }], done: 1 });
|
|
149
|
+
// a Done task merged over two rows: the export leaves NO and status blank below
|
|
150
|
+
const merged = "NO\tRequest\tStatus\n1\tExport button missing\tDone\n\tExport keeps old filter\t\n2\tAdd dark mode\t\n";
|
|
151
|
+
expect(sift("sheet", merged)).toEqual({ items: [{ text: "Add dark mode", notes: "2", row: 4 }], done: 2 });
|
|
149
152
|
}
|
|
150
153
|
// A numbered row is data even when one of its cells is a header word said once.
|
|
151
154
|
expect(split("sheet", "1\tIssue\tLogin fails on Safari\n2\tBug\tExport drops rows\n3\tBug\tSearch is slow\n").map((i) => i.text))
|
package/cli/sources.ts
CHANGED
|
@@ -507,10 +507,15 @@ export function sift(kind: Kind, body: string, pics?: Map<number | string, strin
|
|
|
507
507
|
const head = filled.slice(0, 5).find((row) => !/^\d{1,3}[.)]?$/.test(row.find(Boolean) ?? "") && (named(row, HEADER) >= 0 || named(row, STATUS) >= 0));
|
|
508
508
|
const data = head ? filled.slice(filled.indexOf(head) + 1) : filled;
|
|
509
509
|
const status = head ? named(head, STATUS) : -1;
|
|
510
|
+
// A task merged over several rows has its number and status in the top row only:
|
|
511
|
+
// the export leaves both blank below, so such a row takes the status above it.
|
|
512
|
+
let above = "";
|
|
513
|
+
const state = new Map(data.map((row) => { const own = row[status] ?? ""; if (own || row[0]) above = own; return [row, own || above]; }));
|
|
514
|
+
const finished = (row: string[]) => status >= 0 && DONE.test(state.get(row) ?? "");
|
|
510
515
|
// One column for the whole sheet, the one holding the most text that reads like a
|
|
511
516
|
// request. Never a cell per row, which takes `Open` or a name.
|
|
512
517
|
// Finished rows do not vote: their replies outweigh the requests still open.
|
|
513
|
-
const open = data.filter((row) =>
|
|
518
|
+
const open = data.filter((row) => !finished(row));
|
|
514
519
|
const text = (i: number) => i === status ? 0 : open.reduce((sum, row) => sum + (wordy(row[i] ?? "") ? row[i]!.length : 0), 0);
|
|
515
520
|
let wordiest = -1;
|
|
516
521
|
for (let i = 0, most = 0; i < Math.max(0, ...data.map((row) => row.length)); i++) if (text(i) > most) { most = text(i); wordiest = i; }
|
|
@@ -524,7 +529,7 @@ export function sift(kind: Kind, body: string, pics?: Map<number | string, strin
|
|
|
524
529
|
const items = data.flatMap((row) => {
|
|
525
530
|
const text = row[col] ?? "";
|
|
526
531
|
if (!text || (known < 0 && !wordy(text))) return [];
|
|
527
|
-
if (
|
|
532
|
+
if (finished(row)) { done++; return []; }
|
|
528
533
|
const rest = row.filter((c, i) => c && i !== col).join(" · ");
|
|
529
534
|
// The export keeps every row from the top, so a row's index is its number less one.
|
|
530
535
|
return [with_({ text, ...(rest ? { notes: rest } : {}), row: cells.indexOf(row) + 1 }, cells.indexOf(row) + 1)];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaizen-agent",
|
|
3
|
-
"version": "1.40.
|
|
3
|
+
"version": "1.40.3",
|
|
4
4
|
"description": "Staged workflow for AI agents — code, writing, research, operations: plan, human approval, build, independent review, bounded fix loop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@codemirror/view": "6.43.13",
|
|
56
56
|
"@lezer/highlight": "1.2.5",
|
|
57
57
|
"@xterm/addon-fit": "0.11.0",
|
|
58
|
+
"@xterm/addon-webgl": "0.19.0",
|
|
58
59
|
"@xterm/xterm": "6.0.0",
|
|
59
60
|
"prettier": "3.9.10"
|
|
60
61
|
}
|
|
@@ -115,7 +115,9 @@ screen; a document gets one of it rendered; a CLI gets one of the terminal runni
|
|
|
115
115
|
the real output also pasted in a code block. Only a result with no screen at all — a
|
|
116
116
|
library, an API — may give command output alone. A report with no screenshot is incomplete. Save each under
|
|
117
117
|
`runs/<id>/attachments/` (letters, digits, `.`, `-`, `_` only) and embed it as
|
|
118
|
-
``; the board shows them in the Preview tab.
|
|
118
|
+
``; the board shows them in the Preview tab. A link
|
|
119
|
+
the user should open from the board (a video, a captions file) goes there too, as
|
|
120
|
+
`[label](attachments/<name>)`: the board serves nothing else, and shows any other relative link as its path.
|
|
119
121
|
A headless browser does it: `playwright screenshot <url> runs/<id>/attachments/<name>.png`,
|
|
120
122
|
or `chromium --headless --screenshot=<abs path>.png --window-size=1280,900 <url>` where
|
|
121
123
|
playwright has no browser installed. A file (document, diff, output) opens as `file://<path>`.
|
package/web/board/markdown.ts
CHANGED
|
@@ -9,12 +9,15 @@ function section(impl, name) {
|
|
|
9
9
|
}
|
|
10
10
|
export const preview = (impl) => section(impl, "Preview");
|
|
11
11
|
// Links to a card's attachments/ (notes, or screenshots the builder put in Preview) via /file.
|
|
12
|
+
// Any other relative link (../video.mp4, out/x.srt) would resolve against the board's URL
|
|
13
|
+
// and open "not found": the board serves attachments only, so it shows as its path instead.
|
|
12
14
|
export const attach = (t, c) =>
|
|
13
|
-
t.replace(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
t.replace(/(!?)\[([^\]]*)\]\(([^)\s]+)\)/g, (all, img, label, p) => {
|
|
16
|
+
if (/^attachments\/[^)]+$/.test(p))
|
|
17
|
+
return `${img}[${label}](/file?dir=${encodeURIComponent(c.state)}&p=${encodeURIComponent((c.kind === "run" ? `runs/${c.id}/` : "") + p)})`;
|
|
18
|
+
if (/^([a-z][\w+.-]*:|\/|#)/i.test(p)) return all;
|
|
19
|
+
return `${label} (\`${p}\`)`;
|
|
20
|
+
});
|
|
18
21
|
export const commitMsg = (impl) => (section(impl, "Commit") || "").replace(/^```\w*\n|\n```$/g, "").trim();
|
|
19
22
|
// A plan's Open questions as a pick list: `Q: question` lines with `- option` lines under
|
|
20
23
|
// each, "(recommended)" marking the default and "multi-select" in the question allowing
|
package/web/board.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* kaizen board
|
|
1
|
+
/* kaizen board 265128943e598fdd -- generated by bun run build:web from web/board/main.ts; do not edit */
|
|
2
2
|
(()=>{var a={S:{project:null,projects:[],cards:[],now:Date.now(),all:!1},all:new URLSearchParams(location.search).get("all")!=="0",dir:null,openKey:null,mode:null,modeKey:null,menuKey:null,tab:"request",lastTab:"request",runDoc:null,clearMenu:!1,wantTerm:null,setQ:"",pageGen:0,PL:[],shown:new Set((()=>{try{return JSON.parse(localStorage.getItem("kz-show"))||[]}catch(e){return[]}})())};var t=(e)=>document.getElementById(e),p=(e)=>String(e).replace(/[&<>"]/g,(n)=>({"&":"&","<":"<",">":">",'"':"""})[n]),q=(e)=>`<svg><use href="#i-${e}"/></svg>`,ht='<div aria-busy="true" aria-label="Loading"><span class="skel" style="height:16px;width:35%;margin:20px 0 14px"></span>'+'<span class="skel" style="height:44px;margin-bottom:10px"></span>'.repeat(4)+"</div>";var bn;function S(e,n){let o=t("toast");if(o.textContent=e,o.classList.toggle("rep",!!n),n){let r=document.createElement("a");r.href="/issue?"+new URLSearchParams(n),r.target="_blank",r.rel="noopener",r.textContent="Report",o.append(" ",r)}o.classList.add("on"),clearTimeout(bn),bn=setTimeout(()=>o.classList.remove("on"),n?8000:4000)}function be(){try{if(typeof Notification<"u"&&Notification.permission==="default")Notification.requestPermission()}catch(e){}}function yn(e){try{if(typeof Notification<"u"&&Notification.permission==="granted")new Notification("kaizen",{body:e,icon:"/logo.png"})}catch(n){}}var fs="https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.3.0",vn={tiny:"onnx-community/whisper-tiny",base:"onnx-community/whisper-base",small:"onnx-community/whisper-small","large-v3-turbo":"onnx-community/whisper-large-v3-turbo"},Nt=null,hs=`import{pipeline}from"${fs}";let asr=null;
|
|
3
3
|
onmessage=async e=>{const m=e.data;try{
|
|
4
4
|
if(m.type==="load"){const prog=p=>{if(p.status==="progress")postMessage({type:"progress",file:p.file,pct:p.progress||0})};
|
|
@@ -8,7 +8,7 @@ onmessage=async e=>{const m=e.data;try{
|
|
|
8
8
|
catch(e){if(gpu)postMessage({type:"fallback",why:String(e&&e.message||e)});asr=await pipeline("automatic-speech-recognition",m.model,{...cpu,progress_callback:prog})}
|
|
9
9
|
postMessage({type:"ready"})}
|
|
10
10
|
if(m.type==="run"){const r=await asr(m.audio,{chunk_length_s:30,return_timestamps:false});postMessage({type:"text",sid:m.sid,seq:m.seq,text:(r.text||"").trim()})}
|
|
11
|
-
}catch(err){postMessage({type:"error",sid:m.sid,seq:m.seq,error:String(err&&err.message||err)})}}`,ms='class T extends AudioWorkletProcessor{process(i){const c=i[0]&&i[0][0];if(c)this.port.postMessage(c.slice(0));return true}}registerProcessor("kz-tap",T)',gs=!!(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&window.AudioWorkletNode&&window.WebAssembly&&window.Worker),ye=null,Le=null,mt=()=>{},pe=null,He=!1,gt=new Set;async function bs(){let e="small";try{e=((await fetch("/settings").then((o)=>o.json())).rows.find((o)=>o.key==="dictation.model")||{}).value||e}catch(n){}if(!vn[e])e="small";if(Le&&Nt!==e){try{ye.terminate()}catch(n){}ye=null,Le=null,gt.clear(),pe=null}if(Le)return Le;return Nt=e,Le=new Promise(async(n,o)=>{ye=new Worker(URL.createObjectURL(new Blob([hs],{type:"text/javascript"})),{type:"module"});let r={};ye.onmessage=(c)=>{let g=c.data;if(g.type==="progress"){r[g.file]=g.pct;let v=Object.values(r);mt(Math.round(v.reduce((k,h)=>k+h,0)/v.length))}else if(g.type==="ready")n();else if(g.type==="fallback")S("GPU could not run the model, using the CPU: "+g.why);else if(g.type==="error"&&g.seq==null)o(Error(g.error));for(let v of gt)v.onmsg(g)},ye.onerror=(c)=>o(Error(c.message||"worker failed"));let l=null;try{l=navigator.gpu&&await navigator.gpu.requestAdapter()}catch(c){}if(!l)S("No WebGPU: dictation will run on the CPU and be slower");ye.postMessage({type:"load",model:vn[Nt],webgpu:!!l,f16:!!(l&&l.features.has("shader-f16"))})}),Le.catch(()=>{Le=null;try{ye.terminate()}catch(n){}ye=null}),Le}function fe(e){if(pe&&(e||!pe.field.isConnected))pe.stop()}function et(e){if(!gs)return null;let n=document.createElement("button");n.className="ib sm mic",n.title="Dictate",n.setAttribute("aria-label","Dictate"),n.type="button";let o=()=>{n.innerHTML=q("mic"),n.classList.remove("on","busy")};o();let r=e[0];return e.forEach((l)=>l.addEventListener("focus",()=>r=l)),n.onclick=async(l)=>{if(l.preventDefault(),l.stopPropagation(),pe){let E=pe.btn===n;if(pe.stop(),E)return}if(He)return;He=!0,n.classList.add("busy"),mt=(E)=>{n.innerHTML=`<i>${E}%</i>`};try{await bs()}catch(E){o(),mt=()=>{},He=!1,S("Dictation model could not load: "+E.message);return}if(mt=()=>{},n.innerHTML=q("mic"),!n.isConnected){o(),He=!1;return}let c;try{c=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,noiseSuppression:!0,echoCancellation:!0}})}catch(E){o(),He=!1,S("Microphone not available: "+(E.name==="NotAllowedError"?"permission denied":E.message));return}if(pe)pe.stop();let g=new AudioContext({sampleRate:16000});await g.audioWorklet.addModule(URL.createObjectURL(new Blob([ms],{type:"text/javascript"})));let v=g.createMediaStreamSource(c),k=new AudioWorkletNode(g,"kz-tap");v.connect(k);let h=r,b=h.selectionStart??h.value.length,u=document.createElement("span");u.className="vu",u.setAttribute("aria-hidden","true"),u.innerHTML=[0.5,0.9,1.3,0.8,0.45].map((E)=>`<i style="--w:${E}"></i>`).join("");let f=[],d=0,m=0,x=0,N=0,T=0,I=new Map,O=!1,me=16000,L=6*me,H=0.8*me,G=1*me,U=(E)=>{if(!E||!h.isConnected)return;let F=h.value;if(document.activeElement===h)b=h.selectionStart;b=Math.min(b,F.length);let te=F.slice(0,b),re=te&&!/\s$/.test(te)?" ":"";h.value=te+re+E+F.slice(b),b=te.length+re.length+E.length,h.selectionStart=h.selectionEnd=b,h.dispatchEvent(new Event("input",{bubbles:!0}))},_=()=>{if(!d||m<G){f=[],d=0,m=0,x=0;return}let E=new Float32Array(d),F=0;for(let te of f)E.set(te,F),F+=te.length;f=[],d=0,m=0,x=0,I.set(N,null),ye.postMessage({type:"run",sid:D,seq:N,audio:E},[E.buffer]),N++,n.classList.add("busy")},K=()=>{while(I.has(T)&&I.get(T)!==null)U(I.get(T)),I.delete(T),T++;if(!I.size){if(n.classList.remove("busy"),O)o(),gt.delete(ae)}};k.port.onmessage=(E)=>{let F=E.data;f.push(F),d+=F.length;let te=0;for(let le=0;le<F.length;le++)te+=F[le]*F[le];let re=Math.sqrt(te/F.length);if(re>0.01)m+=F.length,x=0;else x+=F.length;{let le=Math.min(1,re*8).toFixed(2);h.style.setProperty("--lvl",le),u.style.setProperty("--lvl",le)}if(d>=L||m>=G&&x>=H)_()};let D=Math.random().toString(36).slice(2),ae={btn:n,field:h,onmsg:(E)=>{if(E.sid!==D)return;if(E.type==="text")I.set(E.seq,E.text),K();else if(E.type==="error"&&E.seq!=null)I.set(E.seq,""),S("Dictation failed: "+E.error),K()},stop:()=>{if(O)return;O=!0,n.classList.remove("on"),h.classList.remove("dictating"),h.style.removeProperty("--lvl"),n.innerHTML=q("mic");try{k.port.onmessage=null,v.disconnect(),k.disconnect(),c.getTracks().forEach((E)=>E.stop()),g.close()}catch(E){}pe=null,_(),K()}};gt.add(ae),pe=ae,He=!1,n.classList.remove("busy"),n.classList.add("on"),h.classList.add("dictating"),n.replaceChildren(u),h.focus()},n}var kn="kz-d:";function Me(e,n){try{let o=sessionStorage.getItem("kz-d:"+n);if(o!=null)e.value=o}catch(o){}e.addEventListener("input",()=>{try{sessionStorage.setItem("kz-d:"+n,e.value)}catch(o){}})}function wn(e){try{Object.keys(sessionStorage).forEach((n)=>{if(n.startsWith("kz-d:"+e))sessionStorage.removeItem(n)})}catch(n){}}var $n=86400000,xn=(e,n)=>{let o=n-e;return o<3600000?Math.round(o/60000)+"m":o<86400000?Math.round(o/3600000)+"h":Math.round(o/86400000)+"d"},Ht={claude:"Claude Code",codex:"Codex",agy:"Antigravity",opencode:"OpenCode",gemini:"Gemini",cursor:"Cursor",yolo:"yolo",unrechecked:"fix not rechecked"},Sn={claude:1,codex:1,agy:1,opencode:1,gemini:1,cursor:1,full:1,lite:1},qn=["Ideas","Planning","Building","Review","Done"],Ce={idea:"idea",starting:"start",running:"run",stalled:"stall",waiting:"wait",done:"done",abandoned:"aband"},ys={"approvals.plan":"plan needs your approval","approvals.review":"review needs your approval"},tt=(e)=>ys[e]||e,Ie={idea:"idea",starting:"starting",running:"running",stalled:"stalled",waiting:"waiting on you",done:"done",abandoned:"abandoned"};function Ln(e,n){let o=e&&e.match(new RegExp(`^##\\s+${n}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$(?![\\s\\S]))`,"m"));return o?o[1].trim():null}var bt=(e)=>Ln(e,"Preview"),yt=(e,n)=>e.replace(
|
|
11
|
+
}catch(err){postMessage({type:"error",sid:m.sid,seq:m.seq,error:String(err&&err.message||err)})}}`,ms='class T extends AudioWorkletProcessor{process(i){const c=i[0]&&i[0][0];if(c)this.port.postMessage(c.slice(0));return true}}registerProcessor("kz-tap",T)',gs=!!(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&window.AudioWorkletNode&&window.WebAssembly&&window.Worker),ye=null,Le=null,mt=()=>{},pe=null,He=!1,gt=new Set;async function bs(){let e="small";try{e=((await fetch("/settings").then((o)=>o.json())).rows.find((o)=>o.key==="dictation.model")||{}).value||e}catch(n){}if(!vn[e])e="small";if(Le&&Nt!==e){try{ye.terminate()}catch(n){}ye=null,Le=null,gt.clear(),pe=null}if(Le)return Le;return Nt=e,Le=new Promise(async(n,o)=>{ye=new Worker(URL.createObjectURL(new Blob([hs],{type:"text/javascript"})),{type:"module"});let r={};ye.onmessage=(c)=>{let g=c.data;if(g.type==="progress"){r[g.file]=g.pct;let v=Object.values(r);mt(Math.round(v.reduce((k,h)=>k+h,0)/v.length))}else if(g.type==="ready")n();else if(g.type==="fallback")S("GPU could not run the model, using the CPU: "+g.why);else if(g.type==="error"&&g.seq==null)o(Error(g.error));for(let v of gt)v.onmsg(g)},ye.onerror=(c)=>o(Error(c.message||"worker failed"));let l=null;try{l=navigator.gpu&&await navigator.gpu.requestAdapter()}catch(c){}if(!l)S("No WebGPU: dictation will run on the CPU and be slower");ye.postMessage({type:"load",model:vn[Nt],webgpu:!!l,f16:!!(l&&l.features.has("shader-f16"))})}),Le.catch(()=>{Le=null;try{ye.terminate()}catch(n){}ye=null}),Le}function fe(e){if(pe&&(e||!pe.field.isConnected))pe.stop()}function et(e){if(!gs)return null;let n=document.createElement("button");n.className="ib sm mic",n.title="Dictate",n.setAttribute("aria-label","Dictate"),n.type="button";let o=()=>{n.innerHTML=q("mic"),n.classList.remove("on","busy")};o();let r=e[0];return e.forEach((l)=>l.addEventListener("focus",()=>r=l)),n.onclick=async(l)=>{if(l.preventDefault(),l.stopPropagation(),pe){let E=pe.btn===n;if(pe.stop(),E)return}if(He)return;He=!0,n.classList.add("busy"),mt=(E)=>{n.innerHTML=`<i>${E}%</i>`};try{await bs()}catch(E){o(),mt=()=>{},He=!1,S("Dictation model could not load: "+E.message);return}if(mt=()=>{},n.innerHTML=q("mic"),!n.isConnected){o(),He=!1;return}let c;try{c=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,noiseSuppression:!0,echoCancellation:!0}})}catch(E){o(),He=!1,S("Microphone not available: "+(E.name==="NotAllowedError"?"permission denied":E.message));return}if(pe)pe.stop();let g=new AudioContext({sampleRate:16000});await g.audioWorklet.addModule(URL.createObjectURL(new Blob([ms],{type:"text/javascript"})));let v=g.createMediaStreamSource(c),k=new AudioWorkletNode(g,"kz-tap");v.connect(k);let h=r,b=h.selectionStart??h.value.length,u=document.createElement("span");u.className="vu",u.setAttribute("aria-hidden","true"),u.innerHTML=[0.5,0.9,1.3,0.8,0.45].map((E)=>`<i style="--w:${E}"></i>`).join("");let f=[],d=0,m=0,x=0,N=0,T=0,I=new Map,O=!1,me=16000,L=6*me,H=0.8*me,G=1*me,U=(E)=>{if(!E||!h.isConnected)return;let F=h.value;if(document.activeElement===h)b=h.selectionStart;b=Math.min(b,F.length);let te=F.slice(0,b),re=te&&!/\s$/.test(te)?" ":"";h.value=te+re+E+F.slice(b),b=te.length+re.length+E.length,h.selectionStart=h.selectionEnd=b,h.dispatchEvent(new Event("input",{bubbles:!0}))},_=()=>{if(!d||m<G){f=[],d=0,m=0,x=0;return}let E=new Float32Array(d),F=0;for(let te of f)E.set(te,F),F+=te.length;f=[],d=0,m=0,x=0,I.set(N,null),ye.postMessage({type:"run",sid:D,seq:N,audio:E},[E.buffer]),N++,n.classList.add("busy")},K=()=>{while(I.has(T)&&I.get(T)!==null)U(I.get(T)),I.delete(T),T++;if(!I.size){if(n.classList.remove("busy"),O)o(),gt.delete(ae)}};k.port.onmessage=(E)=>{let F=E.data;f.push(F),d+=F.length;let te=0;for(let le=0;le<F.length;le++)te+=F[le]*F[le];let re=Math.sqrt(te/F.length);if(re>0.01)m+=F.length,x=0;else x+=F.length;{let le=Math.min(1,re*8).toFixed(2);h.style.setProperty("--lvl",le),u.style.setProperty("--lvl",le)}if(d>=L||m>=G&&x>=H)_()};let D=Math.random().toString(36).slice(2),ae={btn:n,field:h,onmsg:(E)=>{if(E.sid!==D)return;if(E.type==="text")I.set(E.seq,E.text),K();else if(E.type==="error"&&E.seq!=null)I.set(E.seq,""),S("Dictation failed: "+E.error),K()},stop:()=>{if(O)return;O=!0,n.classList.remove("on"),h.classList.remove("dictating"),h.style.removeProperty("--lvl"),n.innerHTML=q("mic");try{k.port.onmessage=null,v.disconnect(),k.disconnect(),c.getTracks().forEach((E)=>E.stop()),g.close()}catch(E){}pe=null,_(),K()}};gt.add(ae),pe=ae,He=!1,n.classList.remove("busy"),n.classList.add("on"),h.classList.add("dictating"),n.replaceChildren(u),h.focus()},n}var kn="kz-d:";function Me(e,n){try{let o=sessionStorage.getItem("kz-d:"+n);if(o!=null)e.value=o}catch(o){}e.addEventListener("input",()=>{try{sessionStorage.setItem("kz-d:"+n,e.value)}catch(o){}})}function wn(e){try{Object.keys(sessionStorage).forEach((n)=>{if(n.startsWith("kz-d:"+e))sessionStorage.removeItem(n)})}catch(n){}}var $n=86400000,xn=(e,n)=>{let o=n-e;return o<3600000?Math.round(o/60000)+"m":o<86400000?Math.round(o/3600000)+"h":Math.round(o/86400000)+"d"},Ht={claude:"Claude Code",codex:"Codex",agy:"Antigravity",opencode:"OpenCode",gemini:"Gemini",cursor:"Cursor",yolo:"yolo",unrechecked:"fix not rechecked"},Sn={claude:1,codex:1,agy:1,opencode:1,gemini:1,cursor:1,full:1,lite:1},qn=["Ideas","Planning","Building","Review","Done"],Ce={idea:"idea",starting:"start",running:"run",stalled:"stall",waiting:"wait",done:"done",abandoned:"aband"},ys={"approvals.plan":"plan needs your approval","approvals.review":"review needs your approval"},tt=(e)=>ys[e]||e,Ie={idea:"idea",starting:"starting",running:"running",stalled:"stalled",waiting:"waiting on you",done:"done",abandoned:"abandoned"};function Ln(e,n){let o=e&&e.match(new RegExp(`^##\\s+${n}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$(?![\\s\\S]))`,"m"));return o?o[1].trim():null}var bt=(e)=>Ln(e,"Preview"),yt=(e,n)=>e.replace(/(!?)\[([^\]]*)\]\(([^)\s]+)\)/g,(o,r,l,c)=>{if(/^attachments\/[^)]+$/.test(c))return`${r}[${l}](/file?dir=${encodeURIComponent(n.state)}&p=${encodeURIComponent((n.kind==="run"?`runs/${n.id}/`:"")+c)})`;if(/^([a-z][\w+.-]*:|\/|#)/i.test(c))return o;return`${l} (\`${c}\`)`}),Cn=(e)=>(Ln(e,"Commit")||"").replace(/^```\w*\n|\n```$/g,"").trim();function An(e){let n=(e||"").split(`
|
|
12
12
|
`),o=n.findIndex((k)=>/^#+\s*(\d+\.\s*)?open questions/i.test(k.trim()));if(o<0)return[];let r=/^#+/.exec(n[o].trim())[0].length,l=[],c=null,g=!1;for(let k of n.slice(o+1)){let h=k.trim(),b=/^#+(?=\s)/.exec(h);if(b&&b[0].length<=r)break;if(!b&&h&&!/^```/.test(h)&&!/^none\.?$/i.test(h))g=!0;let u=/^\**Q\d*\s*[:.)]\**\s*(.+)$/.exec(h);if(u){l.push(c={q:u[1].trim(),multi:/multi-?select/i.test(u[1]),options:[]});continue}let f=/^[-*]\s+(.+)$/.exec(h);if(f&&c){let d=f[1].trim();c.options.push({text:d,rec:/\(recommended\)/i.test(d),label:d.replace(/\s*\(recommended\)/i,"").split(/\s+[—–-]\s+|:\s/)[0].trim()})}else if(c&&c.options.length)c=null}let v=l.filter((k)=>k.options.length);return v.length||!g?v:null}function Ae(e){let n=/(^|[.!?)]\s+|\s)([A-Z][\w-]*(?: [a-z][\w-]*){0,3}):\s+/g,o=[],r;while(r=n.exec(e))if(!/^\s+$/.test(r[1])||!o.length&&!r[2].includes(" "))o.push([r.index+r[1].length,r[2],n.lastIndex]);if(o.length<2)return{head:e,parts:[]};let l=o.map(([,c,g],v)=>{let k=e.slice(g,v+1<o.length?o[v+1][0]:e.length).trim(),h=k.split(/\s*\((\d+)\)\s+/);if(h.length<5)return{label:c,body:k};let b=[];for(let f=1;f<h.length;f+=2)b.push([h[f],h[f+1]]);let u=b.every(([f],d)=>+f===d+1);return{label:c,body:(h[0]?h[0]+`
|
|
13
13
|
`:"")+b.map(([f,d],m)=>u?`${m+1}. ${d}`:`- (${f}) ${d}`).join(`
|
|
14
14
|
`)}});return{head:e.slice(0,o[0][0]).trim()||`${l[0].label}: ${e.slice(o[0][2],o[1][0]).trim()}`,parts:l}}function je(e,n){let o=e.split(`
|
package/web/notebook.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* kaizen notebook
|
|
1
|
+
/* kaizen notebook 265128943e598fdd -- generated by bun run build:web from web/notebook.ts; do not edit */
|
|
2
2
|
var Ss=[],ua=[];(()=>{let e="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,1n,9,16,o,,x,1i,3,,i,,7,a,2,t,3,1k,,,7,2,2,2,3,9,,a,2,q,,2,3,1k,,,5,4,2,2,3,3,,u,2,3,,b,3,1k,,,8,,3,,3,k,2,m,6,,3,1k,,,7,2,2,2,3,7,3,a,2,u,,1n,5,3,3,,4,9,,14,5,1j,,,7,,3,,4,7,2,b,2,t,3,1k,,,7,,3,,4,7,2,b,2,f,,c,4,1j,2,,7,,3,,4,9,,a,2,t,3,1y,,4,6,,,,8,i,2,1p,,,8,c,8,2q,,,a,b,7,21,2,r,,,,,,4,2,1d,k,,2,5,b,,10,9,,2u,b,,6,n,4,4,3,g,4,d,,,3,6,,f,,jj,3,qa,4,s,3,t,2,u,2,1s,w,9,,19,3,,,39,2,y,,3a,c,4,c,63,5,1l,a,,,,,2,o,2,,1c,1a,2,c,k,5,1b,h,12,9,c,3,u,d,1k,e,1c,k,48,3,,l,4,,6,,2,3,5i,1s,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,n,5,4,,2b,2,1e,i,q,i,d,,12,8,p,d,18,4,1b,e,10,,1v,e,c,,8,2,1a,,1f,,,3,2,2,5,2,,,15,5,5,2,6k,8,,2,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,1t,5,8t,2,25,6,1y,b,1d,4,3e,3,1h,f,15,,2,2,a,4,19,b,7,,1p,3,10,e,g,2,18,,c,3,1c,e,8,4,,2,2k,c,6,,2,,4d,c,l,4,1j,2,,7,2,2,2,3,9,,a,2,2,7,3,5,1v,9,,,2,,,4,,5,,,e,2,2a,i,n,,29,k,6j,7,2,9,r,2,2a,h,2y,d,2t,3,2,a,74,f,6t,6,,2,2,4,,,,2,3x,7,2,7,3,,s,a,14,7,,4,8,,9,b,1a,g,5i,8,5j,8,,8,2a,m,,e,3e,6,3,,,2,,7,,,1u,5,,2,,5,9n,4,9,2,,,1c,7,3,5,n,,44l,,6,f,8ug,i,1xc,5,1n,7,t4,,,1j,7,4,29,,b,2,f57,2,3mp,1a,2,n,f2,5,3,6,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,2s,,4g,7,af,,1p,4,e4,4,72,2,6r,,2,,7,2,5,,d6,7,31,7,240,5".split(",").map((t)=>t?parseInt(t,36):1);for(let t=0,i=0;t<e.length;t++)(t%2?ua:Ss).push(i=i+e[t])})();function op(e){if(e<768)return!1;for(let t=0,i=Ss.length;;){let n=t+i>>1;if(e<Ss[n])i=n;else if(e>=ua[n])t=n+1;else return!0;if(t==i)return!1}}function ha(e){return e>=127462&&e<=127487}var fa=8205;function da(e,t,i=!0,n=!0){return(i?Oa:lp)(e,t,n)}function Oa(e,t,i){if(t==e.length)return t;if(t&&pa(e.charCodeAt(t))&&ma(e.charCodeAt(t-1)))t--;let n=bs(e,t);t+=ca(n);while(t<e.length){let r=bs(e,t);if(n==fa||r==fa||i&&op(r))t+=ca(r),n=r;else if(ha(r)){let s=0,o=t-2;while(o>=0&&ha(bs(e,o)))s++,o-=2;if(s%2==0)break;else t+=2}else break}return t}function lp(e,t,i){while(t>1){let n=Oa(e,t-2,i);if(n<t)return n;t--}return 0}function bs(e,t){let i=e.charCodeAt(t);if(!ma(i)||t+1==e.length)return i;let n=e.charCodeAt(t+1);if(!pa(n))return i;return(i-55296<<10)+(n-56320)+65536}function pa(e){return e>=56320&&e<57344}function ma(e){return e>=55296&&e<56320}function ca(e){return e<65536?1:2}class _{lineAt(e){if(e<0||e>this.length)throw RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,t,i){[e,t]=vi(this,e,t);let n=[];if(this.decompose(0,e,n,2),i.length)i.decompose(0,i.length,n,3);return this.decompose(t,this.length,n,1),ft.from(n,this.length-(t-e)+i.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,t=this.length){[e,t]=vi(this,e,t);let i=[];return this.decompose(e,t,i,0),ft.from(i,t-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let t=this.scanIdentical(e,1),i=this.length-this.scanIdentical(e,-1),n=new wi(this),r=new wi(e);for(let s=t,o=t;;){if(n.next(s),r.next(s),s=0,n.lineBreak!=r.lineBreak||n.done!=r.done||n.value!=r.value)return!1;if(o+=n.value.length,n.done||o>=i)return!0}}iter(e=1){return new wi(this,e)}iterRange(e,t=this.length){return new Ts(this,e,t)}iterLines(e,t){let i;if(e==null)i=this.iter();else{if(t==null)t=this.lines+1;let n=this.line(e).from;i=this.iterRange(n,Math.max(n,t==this.lines+1?this.length:t<=1?0:this.line(t-1).to))}return new As(i)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(e){if(e.length==0)throw RangeError("A document must have at least one line");if(e.length==1&&!e[0])return _.empty;return e.length<=32?new oe(e):ft.from(oe.split(e,[]))}}class oe extends _{constructor(e,t=ap(e)){super();this.text=e,this.length=t}get lines(){return this.text.length}get children(){return null}lineInner(e,t,i,n){for(let r=0;;r++){let s=this.text[r],o=n+s.length;if((t?i:o)>=e)return new ka(n,o,i,s);n=o+1,i++}}decompose(e,t,i,n){let r=e<=0&&t>=this.length?this:new oe(ga(this.text,e,t),Math.min(t,this.length)-Math.max(0,e));if(n&1){let s=i.pop(),o=cr(r.text,s.text.slice(),0,r.length);if(o.length<=32)i.push(new oe(o,s.length+r.length));else{let l=o.length>>1;i.push(new oe(o.slice(0,l)),new oe(o.slice(l)))}}else i.push(r)}replace(e,t,i){if(!(i instanceof oe))return super.replace(e,t,i);[e,t]=vi(this,e,t);let n=cr(this.text,cr(i.text,ga(this.text,0,e)),t),r=this.length+i.length-(t-e);if(n.length<=32)return new oe(n,r);return ft.from(oe.split(n,[]),r)}sliceString(e,t=this.length,i=`
|
|
3
3
|
`){[e,t]=vi(this,e,t);let n="";for(let r=0,s=0;r<=t&&s<this.text.length;s++){let o=this.text[s],l=r+o.length;if(r>e&&s)n+=i;if(e<l&&t>r)n+=o.slice(Math.max(0,e-r),t-r);r=l+1}return n}flatten(e){for(let t of this.text)e.push(t)}scanIdentical(){return 0}static split(e,t){let i=[],n=-1;for(let r of e)if(i.push(r),n+=r.length+1,i.length==32)t.push(new oe(i,n)),i=[],n=-1;if(n>-1)t.push(new oe(i,n));return t}}class ft extends _{constructor(e,t){super();this.children=e,this.length=t,this.lines=0;for(let i of e)this.lines+=i.lines}lineInner(e,t,i,n){for(let r=0;;r++){let s=this.children[r],o=n+s.length,l=i+s.lines-1;if((t?l:o)>=e)return s.lineInner(e,t,i,n);n=o+1,i=l+1}}decompose(e,t,i,n){for(let r=0,s=0;s<=t&&r<this.children.length;r++){let o=this.children[r],l=s+o.length;if(e<=l&&t>=s){let a=n&((s<=e?1:0)|(l>=t?2:0));if(s>=e&&l<=t&&!a)i.push(o);else o.decompose(e-s,t-s,i,a)}s=l+1}}replace(e,t,i){if([e,t]=vi(this,e,t),i.lines<this.lines)for(let n=0,r=0;n<this.children.length;n++){let s=this.children[n],o=r+s.length;if(e>=r&&t<=o){let l=s.replace(e-r,t-r,i),a=this.lines-s.lines+l.lines;if(l.lines<a>>4&&l.lines>a>>6){let h=this.children.slice();return h[n]=l,new ft(h,this.length-(t-e)+i.length)}return super.replace(r,o,l)}r=o+1}return super.replace(e,t,i)}sliceString(e,t=this.length,i=`
|
|
4
4
|
`){[e,t]=vi(this,e,t);let n="";for(let r=0,s=0;r<this.children.length&&s<=t;r++){let o=this.children[r],l=s+o.length;if(s>e&&r)n+=i;if(e<l&&t>s)n+=o.sliceString(e-s,t-s,i);s=l+1}return n}flatten(e){for(let t of this.children)t.flatten(e)}scanIdentical(e,t){if(!(e instanceof ft))return 0;let i=0,[n,r,s,o]=t>0?[0,0,this.children.length,e.children.length]:[this.children.length-1,e.children.length-1,-1,-1];for(;;n+=t,r+=t){if(n==s||r==o)return i;let l=this.children[n],a=e.children[r];if(l!=a)return i+l.scanIdentical(a,t);i+=l.length+1}}static from(e,t=e.reduce((i,n)=>i+n.length+1,-1)){let i=0;for(let u of e)i+=u.lines;if(i<32){let u=[];for(let d of e)d.flatten(u);return new oe(u,t)}let n=Math.max(32,i>>5),r=n<<1,s=n>>1,o=[],l=0,a=-1,h=[];function f(u){let d;if(u.lines>r&&u instanceof ft)for(let O of u.children)f(O);else if(u.lines>s&&(l>s||!l))c(),o.push(u);else if(u instanceof oe&&l&&(d=h[h.length-1])instanceof oe&&u.lines+d.lines<=32)l+=u.lines,a+=u.length+1,h[h.length-1]=new oe(d.text.concat(u.text),d.length+1+u.length);else{if(l+u.lines>n)c();l+=u.lines,a+=u.length+1,h.push(u)}}function c(){if(l==0)return;o.push(h.length==1?h[0]:ft.from(h,a)),a=-1,l=h.length=0}for(let u of e)f(u);return c(),o.length==1?o[0]:new ft(o,t)}}_.empty=new oe([""],0);function ap(e){let t=-1;for(let i of e)t+=i.length+1;return t}function cr(e,t,i=0,n=1e9){for(let r=0,s=0,o=!0;s<e.length&&r<=n;s++){let l=e[s],a=r+l.length;if(a>=i){if(a>n)l=l.slice(0,n-r);if(r<i)l=l.slice(i-r);if(o)t[t.length-1]+=l,o=!1;else t.push(l)}r=a+1}return t}function ga(e,t,i){return cr(e,[""],t,i)}class wi{constructor(e,t=1){this.dir=t,this.done=!1,this.lineBreak=!1,this.value="",this.nodes=[e],this.offsets=[t>0?1:(e instanceof oe?e.text.length:e.children.length)<<1]}nextInner(e,t){this.done=this.lineBreak=!1;for(;;){let i=this.nodes.length-1,n=this.nodes[i],r=this.offsets[i],s=r>>1,o=n instanceof oe?n.text.length:n.children.length;if(s==(t>0?o:0)){if(i==0)return this.done=!0,this.value="",this;if(t>0)this.offsets[i-1]++;this.nodes.pop(),this.offsets.pop()}else if((r&1)==(t>0?0:1)){if(this.offsets[i]+=t,e==0)return this.lineBreak=!0,this.value=`
|