kandown 0.35.0 → 0.35.1
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 +17 -0
- package/bin/kandown.js +1 -1
- package/bin/tui.js +1 -1
- package/dist/index.html +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.35.1 — 2026-07-26 — "Light Identity"
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Homepage video storyboard**: Replaced the hand-built board and terminal mocks with black recording frames that specify the exact scenario, duration, aspect ratio, and filename for six real product clips: the hero workflow, a two-agent handoff, Markdown-to-board synchronization, and dedicated Web, TUI, and CLI demonstrations. The three interface briefs share one interactive tabbed stage so the final page will never autoplay three videos at once.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Agent-first homepage narrative**: Reordered and rewrote the landing page around long-running work that survives agent sessions, durable Markdown ownership, completion reports, handoffs, and one shared board across the Web UI, TUI, and CLI. The feature grid, final call to action, shared metadata, footer, and recording documentation now follow the same product promise.
|
|
12
|
+
- **One permanent light website identity**: The marketing and documentation website now uses a single warm light palette regardless of the device preference. Native controls declare `color-scheme: light`, browser chrome uses a fixed white theme color, syntax highlighting emits only the GitHub Light palette, and the animated hero shader uses one documented color path.
|
|
13
|
+
- **Light embedded demo**: The in-browser demo project now starts explicitly in light mode rather than inheriting `prefers-color-scheme`, keeping the transition from the website into the real Kandown application visually consistent while installed projects retain the full product theme system.
|
|
14
|
+
- **Video production guide**: Expanded the website README with the six expected WebM filenames, target durations, 16:10 recording dimensions, loop guidance, and the exact actions to capture in every clip.
|
|
15
|
+
|
|
16
|
+
### Removed
|
|
17
|
+
|
|
18
|
+
- **Website dark-mode runtime**: Removed the header theme toggle, localStorage preference, pre-paint theme script, OS dark-mode listeners, `data-theme` selectors, dark CSS tokens, dual Shiki palette, shader theme observer, and View Transition wipe. A device can no longer select a different visual identity for the site.
|
|
19
|
+
|
|
3
20
|
## 0.35.0 — 2026-07-25 — "House Green"
|
|
4
21
|
|
|
5
22
|
- **Added**: **Kandown finally has its own theme, and it is the default** — a `kandown` preset built from the brand palette registered on the website: `#88E138` brand lime (the logo arrow) as the dark-mode primary, `#7AD12A` as its light-background variant, `#0CE931` (the hero shader green) reused as the `success` token, `#F1FFB8` for accent surfaces and `#EBEBEB` for neutral borders, on 4px radius to match the website. Because lime cannot carry white text at any usable contrast, `primary-foreground` is a near-black green in both modes (7.9:1 light, 11.2:1 dark) rather than the usual white. Every other foreground/background pair passes WCAG AA in both modes.
|
package/bin/kandown.js
CHANGED
package/bin/tui.js
CHANGED
|
@@ -54963,7 +54963,7 @@ import { spawn, execSync } from "child_process";
|
|
|
54963
54963
|
import { homedir as homedir2 } from "os";
|
|
54964
54964
|
|
|
54965
54965
|
// src/lib/version.ts
|
|
54966
|
-
var KANDOWN_VERSION = "0.35.
|
|
54966
|
+
var KANDOWN_VERSION = "0.35.1";
|
|
54967
54967
|
|
|
54968
54968
|
// src/cli/lib/updater.ts
|
|
54969
54969
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
package/dist/index.html
CHANGED
|
@@ -215,7 +215,7 @@ ${v}`:""}`}function vH(t,e){const n=e.trim().toLowerCase();if(!n)return[];const
|
|
|
215
215
|
|
|
216
216
|
## Subtasks
|
|
217
217
|
|
|
218
|
-
`}}async function CH(t,e){try{return await(await(await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}async function vpe(t,e){try{return await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`),!0}catch{return!1}}async function NH(t,e){try{return await t.getDirectoryHandle("archive",{create:e})}catch{return null}}async function ype(t){if(Mt())return _S();const e=new Set;for await(const n of t.values())n.kind==="file"&&n.name.endsWith(".md")&&e.add(n.name.slice(0,-3));try{const n=await t.getDirectoryHandle("archive",{create:!1});for await(const a of n.values())a.kind==="file"&&a.name.endsWith(".md")&&e.add(a.name.slice(0,-3))}catch{}return[...e].sort((n,a)=>n.localeCompare(a,void 0,{numeric:!0}))}async function Ms(t,e){if(Mt())try{const i=await kS(e);return Ug(i)}catch{return ZL(e)}const a=await(async i=>{try{return await(await(await i.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}})(t)??await CH(t,e);return a!==null?Ug(a):ZL(e)}async function SH(t,e){if(Mt())try{const a=await kS(e);return{ok:!0,task:Ug(a)}}catch(a){return a.name==="NotFoundError"?{ok:!1,reason:"not-found"}:{ok:!1,reason:"unknown",error:a}}let n=null;try{n=await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{}if(n===null)try{n=await CH(t,e)}catch(a){return{ok:!1,reason:"unknown",error:a}}if(n===null)return{ok:!1,reason:"not-found"};if(n.trim()==="")return{ok:!1,reason:"corrupted",error:new Error(`Task file ${e}.md is empty`)};try{return{ok:!0,task:Ug(n)}}catch(a){return{ok:!1,reason:"corrupted",error:a}}}async function mu(t,e,n,a){const i=bS(n,a);if(Mt())return cpe(e,i);try{const o=await(await(await vpe(t,e)?await NH(t,!0):t).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}}catch(r){throw Rh(r,`${e}.md`)}}async function Z2(t,e){if(Mt())return ppe(e);try{await t.removeEntry(`${e}.md`)}catch{}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}async function _pe(t,e){await bi(`/api/tasks/${encodeURIComponent(t)}/archive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function kpe(t,e){await bi(`/api/tasks/${encodeURIComponent(t)}/unarchive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function GL(t,e,n,a){const i=bS(n,a);if(Mt())return _pe(e,i);try{const o=await(await(await NH(t,!0)).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}try{await t.removeEntry(`${e}.md`)}catch{}}catch(r){throw Rh(r,`archive/${e}.md`)}}async function wpe(t,e,n,a){const i=bS(n,a);if(Mt())return kpe(e,i);try{const s=await(await t.getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await s.write(i)}finally{await s.close()}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}catch(r){throw Rh(r,`${e}.md`)}}const xpe="kanban-md",Ape=1,cp="recentProjects";function wS(){return new Promise((t,e)=>{const n=indexedDB.open(xpe,Ape);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result),n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains(cp)||a.createObjectStore(cp,{keyPath:"id"})}})}async function G2(t){if(f0())return;const e=await wS();return new Promise((n,a)=>{const i=e.transaction(cp,"readwrite");i.objectStore(cp).put(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function Uy(){if(f0())return[];const t=await wS();return new Promise((e,n)=>{const i=t.transaction(cp,"readonly").objectStore(cp).getAll();i.onsuccess=()=>{const r=i.result||[];r.sort((s,o)=>o.lastOpened-s.lastOpened),e(r.slice(0,10))},i.onerror=()=>n(i.error)})}async function Cpe(t){if(f0())return;const e=await wS();return new Promise((n,a)=>{const i=e.transaction(cp,"readwrite");i.objectStore(cp).delete(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function WL(t,e=!0){const n={mode:e?"readwrite":"read"};try{return await t.queryPermission(n)==="granted"||await t.requestPermission(n)==="granted"}catch(a){return console.warn("[FS] verifyPermission: handle is no longer valid:",a),!1}}async function Npe(){try{return await(await bi("/api/update/check")).json()}catch{return null}}async function $H(){try{return await(await bi("/api/update/apply",{method:"POST"})).json()}catch{return null}}function g0(t=Ti){const e=t.board.columns;return e[e.length-1]??"Done"}function Spe(t,e=Ti){return t===g0(e)||t.toLowerCase()==="archived"}class $pe{dirHandle=null;tasksDirHandle=null;intervalId=null;configHash=null;taskHashes=new Map;knownTaskIds=new Set;listeners=new Map;debounceTimers=new Map;debounceDelay=150;consecutiveErrors=0;maxConsecutiveErrors=5;disabled=!1;eventSource=null;start(e,n){this.dirHandle=e,this.tasksDirHandle=n,this.consecutiveErrors=0,this.disabled=!1,Mt()&&this.startServerSse(),e&&n&&(this.initHashes(),this.intervalId=setInterval(()=>void this.tick(),300))}startServerSse(){if(typeof window>"u"||!Mt()||this.eventSource)return;const e=window.__KANDOWN_TOKEN__,n=e?`/api/events?token=${encodeURIComponent(e)}`:"/api/events";try{this.eventSource=new EventSource(n),this.eventSource.onmessage=a=>{try{const i=JSON.parse(a.data);i.type==="change"&&(i.taskId?this.emit("taskChanged",i.taskId):(this.emit("configChanged"),this.emit("taskChanged","")))}catch{}}}catch(a){console.warn("[Watcher] EventSource init failed:",a)}}stop(){this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.configHash=null,this.taskHashes.clear(),this.knownTaskIds.clear(),this.listeners.clear(),this.debounceTimers.forEach(e=>clearTimeout(e)),this.debounceTimers.clear(),this.consecutiveErrors=0,this.disabled=!1}isDisabled(){return this.disabled}on(e,n){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(n),()=>{this.listeners.get(e)?.delete(n)}}getKnownTaskIds(){return Array.from(this.knownTaskIds)}async initHashes(){if(!(!this.dirHandle||!this.tasksDirHandle))try{const e=await KL(this.dirHandle);e!==null&&(this.configHash=await this.hash(e)),await this.syncTaskDir(!1)}catch(e){console.warn("[Watcher] initHashes error:",e)}}async tick(){if(!(!this.dirHandle||!this.tasksDirHandle)&&!this.disabled)try{const e=await KL(this.dirHandle);if(e!==null){const n=await this.hash(e);this.configHash!==null&&n!==this.configHash&&(this.configHash=n,this.debouncedEmit("configChanged"))}for(const n of[...this.knownTaskIds])try{const a=await YL(this.tasksDirHandle,n);if(a!==null){const i=await this.hash(a),r=this.taskHashes.get(n);r!==void 0&&i!==r&&(this.taskHashes.set(n,i),this.debouncedEmit("taskChanged",n))}}catch(a){console.warn(`[Watcher] Error reading task ${n}:`,a)}await this.syncTaskDir(!0),this.consecutiveErrors=0}catch(e){this.consecutiveErrors++,console.error(`[Watcher] Tick failed (${this.consecutiveErrors}/${this.maxConsecutiveErrors}):`,e),this.consecutiveErrors>=this.maxConsecutiveErrors&&this.disable(`File watcher stopped after ${this.maxConsecutiveErrors} consecutive errors: ${e.message}`)}}disable(e){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.disabled=!0,this.emit("watcherError",e)}debouncedEmit(e,...n){const a=e+JSON.stringify(n),i=this.debounceTimers.get(a);i&&clearTimeout(i);const r=setTimeout(()=>{this.debounceTimers.delete(a),this.emit(e,...n)},this.debounceDelay);this.debounceTimers.set(a,r)}async syncTaskDir(e){if(!this.tasksDirHandle)return;let n;try{n=this.tasksDirHandle.values()}catch(a){throw a}for await(const a of n){if(a.kind!=="file"||!a.name.endsWith(".md"))continue;const i=a.name.replace(".md","");if(!this.knownTaskIds.has(i))try{this.knownTaskIds.add(i);const r=await YL(this.tasksDirHandle,i);r!==null&&(this.taskHashes.set(i,await this.hash(r)),e&&this.debouncedEmit("newTaskDetected",i))}catch(r){console.warn(`[Watcher] syncTaskDir: failed to read ${i}:`,r)}}}async hash(e){const a=new TextEncoder().encode(e),i=await crypto.subtle.digest("SHA-256",a);return Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("")}emit(e,...n){this.listeners.get(e)?.forEach(i=>{if(e==="configChanged"){i();return}if(e==="taskChanged"){const[s]=n;i(s);return}if(e==="newTaskDetected"){const[s]=n;i(s);return}const[r]=n;i(r)})}}async function KL(t){try{return await(await(await t.getFileHandle("kandown.json")).getFile()).text()}catch{return null}}async function YL(t,e){try{return await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}const jo=new $pe,Epe={soft:[{frequency:520,durationMs:90,delayMs:0,type:"sine"},{frequency:720,durationMs:120,delayMs:95,type:"sine"}],chime:[{frequency:660,durationMs:120,delayMs:0,type:"triangle"},{frequency:880,durationMs:160,delayMs:125,type:"triangle"}],ping:[{frequency:920,durationMs:110,delayMs:0,type:"sine"}],pop:[{frequency:260,durationMs:55,delayMs:0,type:"square"},{frequency:520,durationMs:80,delayMs:60,type:"square"}]};let XL=null;function EH(){return"Notification"in window?Notification.permission:"unsupported"}async function Tpe(){return"Notification"in window?await Notification.requestPermission():"unsupported"}function W2({title:t,body:e,config:n}){if(n.notifications.webhookUrl&&fetch(n.notifications.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"kandown_notification",title:t,body:e,timestamp:new Date().toISOString()})}).catch(()=>{}),n.notifications.sound&&Ppe(n.notifications.soundId),!(!n.notifications.browser||EH()!=="granted"))try{new Notification(t,{body:e})}catch{}}function Ppe(t){const e=Epe[t],n=window.AudioContext??window.webkitAudioContext;if(!(!n||e.length===0))try{XL??=new n;const a=XL;a.state==="suspended"&&a.resume();const i=a.currentTime+.01;e.forEach(r=>{const s=a.createOscillator(),o=a.createGain(),c=i+r.delayMs/1e3,p=c+r.durationMs/1e3;s.type=r.type??"sine",s.frequency.setValueAtTime(r.frequency,c),o.gain.setValueAtTime(1e-4,c),o.gain.exponentialRampToValueAtTime(.08,c+.01),o.gain.exponentialRampToValueAtTime(1e-4,p),s.connect(o),o.connect(a.destination),s.start(c),s.stop(p+.02)})}catch{}}async function rl(t,e={}){const{maxAttempts:n=3,baseDelayMs:a=500,retryableCheck:i=ape}=e;let r;for(let s=1;s<=n;s++)try{return await t()}catch(o){if(r=o,!i(o))throw o;if(s<n){const c=a*Math.pow(2,s-1);await new Promise(p=>setTimeout(p,c))}}throw r}function Mpe(t){const e=t.toLowerCase(),n=new Date;if(e==="today")return n.toISOString().split("T")[0];if(e==="tomorrow"){const i=new Date(n);return i.setDate(i.getDate()+1),i.toISOString().split("T")[0]}const a=["sunday","monday","tuesday","wednesday","thursday","friday","saturday"];if(a.includes(e)){const i=a.indexOf(e),r=new Date(n);let s=i-r.getDay();return s<=0&&(s+=7),r.setDate(r.getDate()+s),r.toISOString().split("T")[0]}return t}function Lpe(t){let e=t.trim(),n;const a=[];let i,r;const s=[];return e=e.replace(/(?:^|\s)p([1-4])(?:\s|$)/i,(c,p)=>(n=`P${p}`," ")),e=e.replace(/(?:^|\s)#([a-zA-Z0-9_-]+)/g,(c,p)=>(a.push(p.toLowerCase())," ")),e=e.replace(/(?:^|\s)@([a-zA-Z0-9_-]+)/g,(c,p)=>(i=p," ")),e=e.replace(/(?:^|\s)due:([^\s]+)/i,(c,p)=>(r=Mpe(p)," ")),e=e.replace(/(?:^|\s)\+([a-zA-Z0-9_-]+)/g,(c,p)=>(s.push(p)," ")),{title:e.replace(/\s+/g," ").trim()||t,...n?{priority:n}:{},...a.length>0?{tags:a}:{},...i?{assignee:i}:{},...r?{due:r}:{},...s.length>0?{depends_on:s}:{}}}const jpe=/^[A-Za-z0-9_-]+$/;function K2(t){if(!t)return null;const e=t.trim().replace(/^\/+|\/+$/g,"").replace(/^#/,"");return!e||e.includes("/")||e.includes(".")||!jpe.test(e)?null:/^\d+$/.test(e)?`t${e}`:e}function Dpe(t){const e=new URLSearchParams(t.search).get("p");if(!e)return null;const[n]=e.split("/").filter(Boolean);return n||null}function qy(t){const e=new URLSearchParams(t.search),n=K2(e.get("task"));if(n)return n;const a=e.get("p");if(a){const[,...r]=a.split("/").filter(Boolean),s=K2(r.join("/"));if(s)return s}return K2(decodeURIComponent(t.pathname))}function I3(t){return t?`/?p=${encodeURIComponent(t)}`:"/"}function xS(t,e){const n=t.replace(/^t(?=\d+$)/,""),a=`/${encodeURIComponent(n)}`;return e?`${a}?p=${encodeURIComponent(e)}`:a}function Vy(t,e=!1){typeof window>"u"||`${window.location.pathname}${window.location.search}`===t||(e?window.history.replaceState({},"",t):window.history.pushState({},"",t),window.dispatchEvent(new Event("kandown:urlchange")))}function zv(t){typeof window<"u"&&qy(window.location)||Vy(I3(t))}function Ipe(t,e=[]){let n=-1;for(const a of[...t.flatMap(i=>i.tasks),...e]){const i=a.id.match(/^t(\d+)$/);if(i){const r=parseInt(i[1],10);r>n&&(n=r)}}return"t"+(n+1)}async function Rpe(){const t=await _S();return await Promise.all(t.map(async n=>{const{frontmatter:a,body:i}=await AH(n),r={...a,id:a.id||n,status:a.status||"Backlog"},{subtasks:s,bodyWithoutSubtasks:o}=Os(i);return{id:n,frontmatter:r,body:o,subtasks:s}}))}async function Ope(t){const e=await ype(t),n=await Promise.all(e.map(async r=>{const s=await SH(t,r);return{id:r,result:s}})),a=[],i=[];for(const{id:r,result:s}of n)if(s.ok){const o={...s.task.frontmatter,id:s.task.frontmatter.id||r,status:s.task.frontmatter.status||"Backlog"},{subtasks:c,bodyWithoutSubtasks:p}=Os(s.task.body);a.push({id:r,frontmatter:o,body:p,subtasks:c})}else{if(s.reason==="not-found")continue;i.push(r)}return{tasks:a,failedIds:i}}async function QL(t,e,n){const a=[];for(const s of e){const o=s.name;s.tasks.forEach((c,p)=>{const d=(async()=>{const{frontmatter:u,body:f}=await Ms(t,c.id);await mu(t,c.id,{...u,id:c.id,status:o,order:p},f)})();a.push({id:c.id,promise:d})})}const i=await Promise.allSettled(a.map(s=>s.promise)),r=[];return i.forEach((s,o)=>{s.status==="rejected"&&r.push(a[o].id)}),{failedIds:r}}function ul(t){kH(t.ui.theme,t.ui.skin,t.ui.font,t.ui.background)}function R3(t){return{title:t.frontmatter.title||t.id,status:t.frontmatter.status||"Backlog",body:t.body,subtasks:t.subtasks}}function Y2(t){xu.clear(),t.forEach(e=>{xu.set(e.id,R3(e))})}function Fpe(t){const e=t.split(/[\\/]+/).filter(Boolean),n=e[e.length-1];return n===".kandown"?e[e.length-2]??"Project":n??"Project"}function zpe(t,e){return e.reduce((n,a,i)=>{const r=t[i]?.done??!1;return n+(a.done&&!r?1:0)},0)}function Hpe(t,e){const n=t.subtasks.map(i=>({text:i.text,description:i.description??"",report:i.report??""})),a=e.subtasks.map(i=>({text:i.text,description:i.description??"",report:i.report??""}));return t.title!==e.title||t.body!==e.body||JSON.stringify(n)!==JSON.stringify(a)}let Bpe=0;const xu=new Map,Ff=new Map;let X2=null,Qd=!1;function JL(t){return[...new Set(t.filter(e=>typeof e=="string"&&e.trim().length>0))]}const re=qce((t,e)=>({isOpen:!1,loading:!1,dirHandle:null,projectName:null,tasksDirHandle:null,boardTitle:"Project Kanban",columns:[],archivedTasks:[],showArchives:!1,showMetadata:!0,taskContents:new Map,searchMatches:new Map,viewMode:localStorage.getItem("kandown:view")||"board",density:localStorage.getItem("kandown:density")||"comfortable",filters:{search:"",priority:null,tag:null,assignee:null,ownerType:null},commandOpen:!1,cheatsheetOpen:!1,drawerTaskId:null,drawerData:null,currentPage:"board",config:Ti,recentProjects:[],toasts:[],agentHook:null,isReloading:!1,lastReloadError:null,failedTaskIds:[],watcherError:null,hasUnsavedDrawerEdits:!1,lastSaveError:null,drawerRecoveryData:new Map,selectedTaskIds:[],toggleTaskSelection:n=>{t(a=>({selectedTaskIds:a.selectedTaskIds.includes(n)?a.selectedTaskIds.filter(s=>s!==n):[...a.selectedTaskIds,n]}))},clearTaskSelection:()=>t({selectedTaskIds:[]}),bulkMoveTasks:async n=>{const{selectedTaskIds:a,columns:i,moveTask:r}=e();for(const s of a){let o="Backlog";for(const c of i)if(c.tasks.some(p=>p.id===s)){o=c.name;break}await r(s,o,n)}t({selectedTaskIds:[]})},bulkDeleteTasks:async n=>{const{selectedTaskIds:a,tasksDirHandle:i,drawerTaskId:r}=e(),s=JL(n??a);if(!(s.length===0||!i&&!Mt())){if(Qd){e().toast("Another bulk action is already running","warning");return}Qd=!0;try{const o=await Promise.allSettled(s.map(d=>rl(()=>Z2(i||null,d),{maxAttempts:3}))),c=s.filter((d,u)=>o[u]?.status==="fulfilled"),p=s.filter((d,u)=>o[u]?.status==="rejected");r&&c.includes(r)&&e().closeDrawer(),t(d=>({selectedTaskIds:d.selectedTaskIds.filter(u=>!c.includes(u))})),await e().reloadBoard(),p.length>0?e().toast(`${c.length} deleted, ${p.length} could not be deleted`,"warning",8e3):e().toast(`Deleted ${c.length} task${c.length===1?"":"s"}`)}finally{Qd=!1}}},bulkArchiveTasks:async n=>{const{tasksDirHandle:a,drawerTaskId:i}=e(),r=JL(n);if(!(r.length===0||!a&&!Mt())){if(Qd){e().toast("Another bulk action is already running","warning");return}Qd=!0;try{const s=await Promise.allSettled(r.map(async p=>{const d=await SH(a||null,p);if(!d.ok)throw new Error(`Task ${p} could not be read (${d.reason})`);await rl(()=>GL(a||null,p,{...d.task.frontmatter,id:p,archived:!0},d.task.body),{maxAttempts:3})})),o=r.filter((p,d)=>s[d]?.status==="fulfilled"),c=r.filter((p,d)=>s[d]?.status==="rejected");i&&o.includes(i)&&e().closeDrawer(),t(p=>({selectedTaskIds:p.selectedTaskIds.filter(d=>!o.includes(d))})),await e().reloadBoard(),c.length>0?e().toast(`${o.length} archived, ${c.length} could not be archived`,"warning",8e3):e().toast(`Archived ${o.length} task${o.length===1?"":"s"}`)}finally{Qd=!1}}},drawerBaseVersion:null,conflictState:null,showConflictModal:!1,openFolder:async()=>{if(!wH()){const c=navigator.userAgent||"this browser";e().toast(new npe(c).message,"error",8e3);return}let n;try{n=await mpe()}catch(c){c instanceof yS?e().toast("Permission denied — please grant access to the project folder","error"):e().toast("Failed to open folder: "+c.message,"error");return}if(!n)return;const{projectHandle:a,kandownHandle:i,tasksHandle:r}=n,s=a.name;t({dirHandle:i,tasksDirHandle:r,projectName:s}),zv(s);const o=Mt()?V2():null;try{await G2({id:a.name,name:a.name,handle:a,lastOpened:Date.now(),...o?{kandownDir:o}:{}})}catch(c){console.warn("[Store] Failed to save recent project:",c)}await e().loadConfig(),await e().reloadBoard();try{const c=await Uy();t({recentProjects:c})}catch(c){console.warn("[Store] Failed to load recent projects:",c)}e().setupWatcher()},openRecentProject:async n=>{const a={dirHandle:e().dirHandle,tasksDirHandle:e().tasksDirHandle,projectName:e().projectName};if(!await WL(n.handle,!0)){let r=!1;try{await By(n.handle),r=!0}catch{r=!1}if(!r){e().toast(`"${n.name}" is no longer accessible. Removed from recent projects.`,"warning",8e3);try{await Cpe(n.id);const s=await Uy();t({recentProjects:s})}catch{}return}e().toast("Permission denied — please grant access to the folder","error");return}try{const r=await By(n.handle),s=await D3(n.handle),o=n.handle.name;t({dirHandle:r,tasksDirHandle:s,projectName:o}),zv(o);try{await G2({...n,lastOpened:Date.now()})}catch(c){console.warn("[Store] Failed to update recent project:",c)}await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()}catch(r){t(a),e().toast(`Failed to open project: ${r.message}`,"error")}},openServerProject:async()=>{t({loading:!0});try{const n=V2();if(!n)throw new Error("No server root");await VL();const a=Fpe(n),i=await xH();ul(i);const r=await _S(),s=await Promise.all(r.map(async f=>{const{frontmatter:h,body:v}=await AH(f),k={...h,id:h.id||f,status:h.status||"Backlog"},{subtasks:w,bodyWithoutSubtasks:x}=Os(v);return{id:f,frontmatter:k,body:x,subtasks:w}}));Y2(s);const o=s.map(f=>({frontmatter:f.frontmatter,body:Xd(f.body,f.subtasks)})),c=B2(o,i.board.columns),p=U2(o),d=c.reduce((f,h)=>f+h.tasks.length,0),u=new Map;if(d<=10)for(const f of s)u.set(f.frontmatter.id,{frontmatter:f.frontmatter,subtasks:f.subtasks,body:f.body});t({loading:!1,isOpen:!0,config:i,columns:c,archivedTasks:p,boardTitle:"Project Kanban",projectName:a,taskContents:u,searchMatches:new Map}),zv(a),e().setupWatcher(),e().refreshAgentHook()}catch{t({loading:!1,isOpen:!1}),e().toast("Impossible de charger le projet. Relancez `kandown`.","error")}},tryAutoOpenServerProject:async()=>{if(!Mt())return;const n=V2();if(!n)return;await VL();const a=await Uy(),i=a.find(p=>p.kandownDir===n);if(!i){await e().openServerProject();return}if(!await WL(i.handle,!0)){await e().openServerProject();return}const s=await By(i.handle),o=await D3(i.handle),c=i.handle.name;t({dirHandle:s,tasksDirHandle:o,projectName:c,recentProjects:a,isOpen:!0}),zv(c),await G2({...i,lastOpened:Date.now()}),await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()},loadConfig:async()=>{const{dirHandle:n}=e();if(!(!n&&!Mt()))try{const a=await fpe(n);if(a.ok){t({config:a.config}),ul(a.config);return}if(a.reason==="corrupted"){if(a.rawContent&&n)try{const r=await(await n.getFileHandle("kandown.json.backup",{create:!0})).createWritable();try{await r.write(a.rawContent)}finally{await r.close()}}catch{}e().toast("kandown.json is corrupted — using default settings. A backup was saved as kandown.json.backup.","warning",1e4)}t({config:Ti}),ul(Ti)}catch{t({config:Ti}),ul(Ti)}},updateConfig:async n=>{const{dirHandle:a,config:i}=e();if(!a&&!Mt())return;const r=n(i);t({config:r}),ul(r);try{await gpe(a,r)}catch(s){const o=s;o instanceof Po?e().toast("Disk is full — settings were not saved.","error",8e3):e().toast("Failed to save config: "+o.message,"error")}},reloadBoard:async()=>{const{tasksDirHandle:n,config:a}=e();t({isReloading:!0,lastReloadError:null});try{if(Mt()){const i=await Rpe();Y2(i);const r=i.map(d=>({frontmatter:d.frontmatter,body:Xd(d.body,d.subtasks)})),s=B2(r,a.board.columns),o=U2(r);t({boardTitle:"Project Kanban",columns:s,archivedTasks:o});const c=s.reduce((d,u)=>d+u.tasks.length,0),p=new Map;if(c<=10)for(const d of i)p.set(d.frontmatter.id,{frontmatter:d.frontmatter,subtasks:d.subtasks,body:d.body});t({taskContents:p,searchMatches:new Map,failedTaskIds:[],isReloading:!1})}else if(n){const{tasks:i,failedIds:r}=await Ope(n);Y2(i);const s=i.map(u=>({frontmatter:u.frontmatter,body:Xd(u.body,u.subtasks)})),o=B2(s,a.board.columns),c=U2(s);t({boardTitle:"Project Kanban",columns:o,archivedTasks:c});const p=o.reduce((u,f)=>u+f.tasks.length,0),d=new Map;if(p<=10)for(const u of i)d.set(u.frontmatter.id,{frontmatter:u.frontmatter,subtasks:u.subtasks,body:u.body});if(r.length>0){const u=r.length===1?`Task ${r[0]} could not be loaded`:`${r.length} tasks could not be loaded`;e().toast(u,"warning",8e3)}t({taskContents:d,searchMatches:new Map,failedTaskIds:r,isReloading:!1})}else t({isReloading:!1})}catch(i){const r=i.message||String(i);t({isReloading:!1,lastReloadError:`Failed to reload board: ${r}`}),e().toast(`Board reload failed — showing last loaded state (${r})`,"warning",8e3)}},moveTask:async(n,a,i,r)=>{const{columns:s,config:o,taskContents:c,searchMatches:p}=e(),d=Mt();if(!d&&!e().tasksDirHandle)return;const u=s.find(E=>E.name===a),f=s.find(E=>E.name===i);if(!u||!f)return;const h=u.tasks.findIndex(E=>E.id===n);if(h===-1)return;const v=u.tasks[h];if(!v)return;if(Spe(i,o)){const E=new Map,P=g0(o).toLowerCase();for(const M of s)for(const D of M.tasks){const z=D.frontmatter&&(D.frontmatter.archived===!0||D.frontmatter.archived==="true");E.set(D.id,{exists:!0,resolved:z||D.id===n||M.name.toLowerCase()===P})}const L=[];for(const M of v.dependsOn){if(typeof M!="string"||!M.trim()||M===n)continue;const D=E.get(M);(!D||!D.resolved)&&L.push(M)}if(L.length>0){const M=L.length===1?L[0]:`${L.slice(0,-1).join(", ")} and ${L[L.length-1]}`;e().toast(`Cannot move ${n} to ${i}: blocked by ${M}`,"error");return}}const k=s.map(E=>({...E,tasks:[...E.tasks]})),w=k.find(E=>E.name===a),x=k.find(E=>E.name===i),[$]=w.tasks.splice(h,1);/done|termin|closed|complet/i.test(i)?$.checked=!0:$.checked=!1,r!==void 0?x.tasks.splice(r,0,$):x.tasks.push($),t({columns:k});try{const{tasksDirHandle:E}=e();if(!E&&!d)return;const P=a===i?k.filter(M=>M.name===i):k.filter(M=>M.name===a||M.name===i),{failedIds:L}=await rl(()=>QL(E??null,P,o.board.columns),{maxAttempts:3});if(L.length>0){const M=L.length===1?`Could not save move for ${L[0]}`:`${L.length} tasks could not be moved`;e().toast(M,"warning",8e3),await e().reloadBoard()}}catch(E){const P=E;P instanceof Po?e().toast("Disk is full — move was not saved. Free up space and try again.","error",8e3):e().toast("Failed to save: "+P.message,"error"),t({columns:s,taskContents:c,searchMatches:p})}},reorderInColumn:async(n,a,i)=>{const{columns:r,tasksDirHandle:s,config:o,taskContents:c,searchMatches:p}=e();if(!s&&!Mt())return;const d=r.map(h=>({...h,tasks:[...h.tasks]})),u=d.find(h=>h.name===n);if(!u)return;const[f]=u.tasks.splice(a,1);u.tasks.splice(i,0,f),t({columns:d});try{const{tasksDirHandle:h}=e(),v=Mt();if(!h&&!v)return;const{failedIds:k}=await rl(()=>QL(h??null,[u],o.board.columns),{maxAttempts:3});k.length>0&&(e().toast(`Could not save reorder for ${k.length} task(s)`,"warning",8e3),await e().reloadBoard())}catch(h){const v=h;v instanceof Po?e().toast("Disk is full — reorder was not saved.","error",8e3):e().toast("Failed to save: "+v.message,"error"),t({columns:r,taskContents:c,searchMatches:p})}},addColumn:async n=>{const a=n.trim();if(!a)return;const{config:i}=e();i.board.columns.some(r=>r.toLowerCase()===a.toLowerCase())||(await e().updateConfig(r=>({...r,board:{...r.board,columns:[...r.board.columns,a]}})),await e().reloadBoard())},renameColumn:async(n,a)=>{const i=a.trim(),{columns:r,tasksDirHandle:s,config:o}=e();if(!s||!i||i.toLowerCase()===n.toLowerCase())return;if(r.some(d=>d.name.toLowerCase()===i.toLowerCase())){e().toast("Column already exists","error");return}const c=r,p=r.map(d=>d.name===n?{...d,name:i}:d);t({columns:p});try{const d=c.find(u=>u.name===n);if(d){const f=(await Promise.allSettled(d.tasks.map(async(h,v)=>{const{frontmatter:k,body:w}=await Ms(s,h.id);await mu(s,h.id,{...k,id:h.id,status:i,order:v},w)}))).filter(h=>h.status==="rejected").length;f>0&&e().toast(`${f} task(s) could not be renamed`,"warning",8e3)}await e().updateConfig(u=>{const f={...u.board.columnColors??{}},h=f[n.toLowerCase()];h&&(f[i.toLowerCase()]=h,delete f[n.toLowerCase()]);const v=u.board.columns.some(k=>k.toLowerCase()===n.toLowerCase())?u.board.columns:[...u.board.columns,n];return{...u,board:{...u.board,columns:v.map(k=>k.toLowerCase()===n.toLowerCase()?i:k),columnColors:f}}}),await e().reloadBoard()}catch(d){e().toast("Failed to rename column: "+d.message,"error"),t({columns:c})}},reorderColumns:async(n,a)=>{const{config:i,columns:r,tasksDirHandle:s}=e();if(n<0||a<0||n>=r.length||a>=r.length||n===a||!s&&!Mt())return;const o=Array.from(r),[c]=o.splice(n,1);o.splice(a,0,c),t({columns:o});const p=o.map(d=>d.name);try{await e().updateConfig(d=>({...d,board:{...d.board,columns:p}})),await e().reloadBoard()}catch(d){e().toast("Failed to reorder columns: "+d.message,"error"),t({columns:r})}},deleteColumn:async n=>{const{columns:a,tasksDirHandle:i}=e();if(!i&&!Mt())return;const r=a.find(o=>o.name===n);if(!r)return;const s=a;t({columns:a.filter(o=>o.name!==n)});try{const c=(await Promise.allSettled(r.tasks.map(p=>Z2(i,p.id)))).filter(p=>p.status==="rejected").length;c>0&&e().toast(`${c} task(s) could not be deleted`,"warning",8e3),await e().updateConfig(p=>{const d={...p.board.columnColors??{}};return delete d[n.toLowerCase()],{...p,board:{...p.board,columns:p.board.columns.filter(u=>u.toLowerCase()!==n.toLowerCase()),columnColors:d}}}),await e().reloadBoard(),e().toast("Column deleted")}catch(o){e().toast("Failed to delete column: "+o.message,"error"),t({columns:s})}},createTask:async(n,a)=>{const{columns:i,tasksDirHandle:r,config:s,taskContents:o,searchMatches:c,archivedTasks:p}=e();if(!r&&!Mt()||!i.length)return null;const d=n||s.board.columns[0]||i[0].name,u=Ipe(i,p),f=i.find(E=>E.name===d)?.tasks.length??0,h=a?Lpe(a):null,v={id:u,title:h?.title||"",checked:!1,dependsOn:h?.depends_on||[],tags:h?.tags||[],assignee:h?.assignee||null,priority:h?.priority||(s.fields.priority?s.board.defaultPriority:null),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",progress:null,frontmatter:{}},k=i.map(E=>E.name===d?{...E,tasks:[...E.tasks,v]}:E),w=new Map(o),x={id:u,title:h?.title||"",status:d,order:f,priority:h?.priority||(s.fields.priority?s.board.defaultPriority:""),tags:h?.tags||[],assignee:h?.assignee||"",due:h?.due||"",depends_on:h?.depends_on||[],created:new Date().toISOString().slice(0,10),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",tools:""},$="";w.set(u,{frontmatter:x,subtasks:[],body:$}),t({columns:k,taskContents:w});try{const E=r||null;return await rl(()=>mu(E,u,x,$),{maxAttempts:3}),e().toast(`Created ${u.replace(/^t/,"")}`),await e().openDrawer(u),u}catch(E){const P=E;return P instanceof Po?e().toast("Disk is full — task was not created.","error",8e3):e().toast("Failed to create: "+P.message,"error"),t({columns:i,taskContents:o,searchMatches:c}),null}},deleteTask:async n=>{const{columns:a,tasksDirHandle:i,taskContents:r,searchMatches:s}=e();if(!i&&!Mt())return;const o=a.map(d=>({...d,tasks:d.tasks.filter(u=>u.id!==n)}));t({columns:o});const c=new Map(r);c.delete(n);const p=new Map(s);p.delete(n),t({taskContents:c,searchMatches:p});try{await Z2(i||null,n),e().toast("Deleted")}catch(d){const u=d;e().toast("Failed to delete: "+u.message,"error"),t({columns:a,taskContents:r,searchMatches:s})}},archiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Mt()))try{const{frontmatter:i,body:r}=await Ms(a||null,n);await GL(a||null,n,{...i,archived:!0},r),e().drawerTaskId===n&&e().closeDrawer(),await e().reloadBoard(),e().toast("Archived")}catch(i){const r=i;r instanceof Po?e().toast("Disk is full — task was not archived.","error",8e3):e().toast("Failed to archive: "+r.message,"error")}},unarchiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Mt()))try{const{frontmatter:i,body:r}=await Ms(a||null,n),s={...i};delete s.archived,await wpe(a||null,n,s,r),await e().reloadBoard(),e().toast("Restored")}catch(i){const r=i;r instanceof Po?e().toast("Disk is full — task was not restored.","error",8e3):e().toast("Failed to restore: "+r.message,"error")}},setShowArchives:n=>t({showArchives:n}),setShowMetadata:n=>t({showMetadata:n}),openDrawer:async(n,a={})=>{const{tasksDirHandle:i,projectName:r}=e();if(!(!i&&!Mt()))try{const{frontmatter:s,body:o}=await Ms(i,n),{subtasks:c,bodyWithoutSubtasks:p}=Os(o),d={frontmatter:s,subtasks:c,body:p,savedAt:Date.now()},u=e().drawerRecoveryData.get(n),f=u?{frontmatter:u.frontmatter,subtasks:u.subtasks,body:u.body}:{frontmatter:s,subtasks:c,body:p},h=new Map(e().drawerRecoveryData);h.delete(n),a.syncUrl!==!1&&Vy(xS(n,r),a.replace),t({drawerTaskId:n,drawerData:f,drawerBaseVersion:d,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!!u,lastSaveError:null,drawerRecoveryData:h}),u&&e().toast("Restored your unsaved edits for this task","info")}catch(s){e().toast("Failed to open: "+s.message,"error")}},closeDrawer:(n={})=>{n.syncUrl!==!1&&Vy(I3(e().projectName),n.replace),t({drawerTaskId:null,drawerData:null,drawerBaseVersion:null,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!1,lastSaveError:null})},markDrawerDirty:()=>t({hasUnsavedDrawerEdits:!0}),forceCloseDrawer:()=>{const{drawerTaskId:n,drawerData:a}=e();if(n&&a){const i=new Map(e().drawerRecoveryData);i.set(n,{frontmatter:a.frontmatter,subtasks:a.subtasks,body:a.body}),t({drawerRecoveryData:i})}e().closeDrawer()},updateDrawerData:n=>{const{drawerData:a}=e();a&&t({drawerData:n(a)})},saveDrawer:async()=>{const{drawerTaskId:n,drawerData:a,tasksDirHandle:i,taskContents:r}=e();if(!n||!a)return;const s=Xd(a.body,a.subtasks),o={...a.frontmatter,id:n};try{await rl(()=>mu(i||null,n,o,s),{maxAttempts:3}),e().toast("Saved");const c=new Map(e().drawerRecoveryData);c.delete(n),Vy(I3(e().projectName)),t({drawerTaskId:null,drawerData:null,hasUnsavedDrawerEdits:!1,lastSaveError:null,drawerRecoveryData:c});const p=new Map(r);p.set(n,{frontmatter:o,subtasks:a.subtasks,body:a.body}),t({taskContents:p}),await e().reloadBoard()}catch(c){const p=c,d=p instanceof Po?"Disk is full — your edits are kept. Free up space and retry.":"Failed to save: "+p.message;e().toast(d,"error",8e3),t({lastSaveError:d})}},saveDrawerMetadata:async()=>{const{drawerTaskId:n,drawerData:a,tasksDirHandle:i,taskContents:r}=e();if(!(!n||!a))try{const s=Xd(a.body,a.subtasks),o={...a.frontmatter,id:n};await rl(()=>mu(i||null,n,o,s),{maxAttempts:3});const c=new Map(r);c.set(n,{frontmatter:o,subtasks:a.subtasks,body:a.body}),t({taskContents:c,hasUnsavedDrawerEdits:!1,lastSaveError:null}),await e().reloadBoard()}catch(s){const o=s,c=o instanceof Po?"Disk is full — your edits are kept.":"Failed to save: "+o.message;t({hasUnsavedDrawerEdits:!0,lastSaveError:c})}},setViewMode:n=>{localStorage.setItem("kandown:view",n),t({viewMode:n})},setDensity:n=>{localStorage.setItem("kandown:density",n),t({density:n})},setFilter:(n,a)=>{if(t(i=>({filters:{...i.filters,[n]:a}})),n==="search"){const{columns:i,tasksDirHandle:r,taskContents:s}=e(),o=a,c=i.flatMap(p=>p.tasks.map(d=>d.id));if(r){const p=c.filter(d=>!s.has(d));p.length>0?e().loadTaskContents(p).then(()=>{e().computeSearchMatches(o)}):e().computeSearchMatches(o)}}},clearFilters:()=>t({filters:{search:"",priority:null,tag:null,assignee:null,ownerType:null},searchMatches:new Map}),setCommandOpen:n=>t({commandOpen:n}),setCheatsheetOpen:n=>t({cheatsheetOpen:n}),refreshAgentHook:async()=>{if(!Mt()){t({agentHook:null});return}const n=await lpe();t({agentHook:n?.agentHook??null})},sendTaskToAgent:async n=>{const a=e().agentHook;if(!a){e().toast("Agent hook not configured","error");return}e().toast(`Sending to ${a.label}…`);const i=await dpe(n);if(i===null){e().toast("Could not reach the daemon","error");return}i.ok?e().toast(`Sent to ${a.label}`):e().toast(i.error||"Agent hook failed","error")},setCurrentPage:n=>t({currentPage:n}),loadTaskContents:async n=>{const{tasksDirHandle:a}=e();if(!a)return;const i=new Map(e().taskContents);await Promise.all(n.map(async r=>{if(!i.has(r))try{const{frontmatter:s,body:o}=await Ms(a,r),{subtasks:c,bodyWithoutSubtasks:p}=Os(o);i.set(r,{frontmatter:s,subtasks:c,body:p})}catch{}})),t({taskContents:i})},computeSearchMatches:n=>{if(!n.trim()){t({searchMatches:new Map});return}const{taskContents:a}=e(),i=new Map,r=n.toLowerCase();for(const[s,o]of a){const c=vH(o,r);c.length>0&&i.set(s,c)}t({searchMatches:i})},toast:(n,a="success",i)=>{const r=++Bpe,s=i??(a==="error"||a==="warning"?6e3:2500);t(o=>({toasts:[...o.toasts,{id:r,message:n,type:a}]})),setTimeout(()=>{t(o=>({toasts:o.toasts.filter(c=>c.id!==r)}))},s)},dismissToast:n=>t(a=>({toasts:a.toasts.filter(i=>i.id!==n)})),resolveConflict:async n=>{const{conflictState:a,drawerData:i,tasksDirHandle:r,drawerTaskId:s,drawerBaseVersion:o}=e();if(!(!a||!r||!s))if(n==="reload"){const{frontmatter:c,body:p}=await Ms(r,s),{subtasks:d,bodyWithoutSubtasks:u}=Os(p);t({drawerData:{frontmatter:c,subtasks:d,body:u},drawerBaseVersion:{frontmatter:c,subtasks:d,body:u,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Reloaded from disk")}else if(n==="overwrite"){if(i&&s&&o){const c=Xd(i.body,i.subtasks),p={...i.frontmatter,id:s};try{await mu(r,s,p,c),t({drawerBaseVersion:{...i,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Overwritten remote changes")}catch(d){e().toast("Failed to overwrite: "+d.message,"error")}}}else t({conflictState:null,showConflictModal:!1})},setupWatcher:()=>{if(Mt()){X2&&clearInterval(X2),X2=setInterval(()=>{e().reloadBoard()},2e3);return}const{dirHandle:n,tasksDirHandle:a}=e();if(!n||!a)return;jo.stop(),Ff.forEach(s=>clearTimeout(s)),Ff.clear(),jo.start(n,a);const i=(s,o)=>{const c=Ff.get(s);c&&clearTimeout(c);const p=Math.max(2e3,e().config.notifications.editDebounceMs),d=setTimeout(()=>{Ff.delete(s);const u=e().config;u.notifications.taskEdits&&W2({title:"Task edited",body:`${o} changed on disk.`,config:u})},p);Ff.set(s,d)},r=async s=>{const{tasksDirHandle:o,config:c}=e();if(!o)return;let p,d;try{({frontmatter:p,body:d}=await Ms(o,s))}catch(x){console.warn(`[Watcher] notifyTaskChange: failed to read ${s}:`,x);return}const{subtasks:u,bodyWithoutSubtasks:f}=Os(d),h={id:s,frontmatter:{...p,id:p.id||s,status:p.status||"Backlog"},body:f,subtasks:u},v=R3(h),k=xu.get(s);if(!k){xu.set(s,v);return}c.notifications.statusChanges&&k.status!==v.status&&W2({title:"Task status changed",body:`${v.title}: ${k.status} → ${v.status}`,config:c});const w=zpe(k.subtasks,v.subtasks);c.notifications.subtaskCompletions&&w>0&&W2({title:"Subtask completed",body:w===1?`${v.title}: 1 subtask completed.`:`${v.title}: ${w} subtasks completed.`,config:c}),Hpe(k,v)&&i(s,v.title),xu.set(s,v)};jo.on("configChanged",()=>{try{e().loadConfig(),e().toast("Settings updated externally","info")}catch(s){console.error("[Watcher] configChanged handler error:",s)}}),jo.on("taskChanged",async s=>{try{const{drawerTaskId:o,drawerBaseVersion:c,tasksDirHandle:p}=e();if(await r(s),o===s&&c&&p){let d,u;try{({frontmatter:d,body:u}=await Ms(p,s))}catch(E){console.warn(`[Watcher] taskChanged: failed to re-read ${s}:`,E);return}const{subtasks:f,bodyWithoutSubtasks:h}=Os(u),v=c,k=JSON.stringify(v.frontmatter)!==JSON.stringify(d),w=v.body!==h,x=JSON.stringify(v.subtasks)!==JSON.stringify(f);if(!k&&!w&&!x)return;let $="none";k&&(w||x)?$="full":k?$="metadata-only":(w||x)&&($="body-only"),t({conflictState:{taskId:s,type:$,local:v,remote:{frontmatter:d,body:h,subtasks:f}},showConflictModal:$==="full"})}else await e().reloadBoard()}catch(o){console.error(`[Watcher] taskChanged handler error for ${s}:`,o)}}),jo.on("newTaskDetected",async s=>{try{const{tasksDirHandle:o}=e();if(o){let c,p;try{({frontmatter:c,body:p}=await Ms(o,s))}catch(f){console.warn(`[Watcher] newTaskDetected: failed to read ${s}:`,f),e().toast(`New task ${s} detected but could not be loaded`,"warning");return}const{subtasks:d,bodyWithoutSubtasks:u}=Os(p);xu.set(s,R3({id:s,frontmatter:{...c,id:c.id||s,status:c.status||"Backlog"},body:u,subtasks:d}))}await e().reloadBoard()}catch(o){console.error(`[Watcher] newTaskDetected handler error for ${s}:`,o)}}),jo.on("watcherError",s=>{t({watcherError:s}),e().toast(s,"warning",1e4)})},restartWatcher:()=>{const{dirHandle:n,tasksDirHandle:a}=e();!n||!a||(t({watcherError:null}),e().setupWatcher(),e().toast("File watcher restarted"))}}));Uy().then(t=>{re.setState({recentProjects:t})}).catch(t=>{console.warn("[Store] Failed to hydrate recent projects:",t)});ul(Ti);window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{ul(re.getState().config)});const Upe=Object.freeze(Object.defineProperty({__proto__:null,useStore:re},Symbol.toStringTag,{value:"Module"}));function qpe({icon:t,value:e,label:n,isActive:a,onClick:i,layoutId:r}){return b.jsxs("button",{type:"button",className:j1("relative flex size-8 cursor-default items-center justify-center rounded-full transition-all [&_svg]:size-4",a?"text-zinc-950 dark:text-zinc-50":"text-zinc-400 hover:text-zinc-950 dark:text-zinc-500 dark:hover:text-zinc-50"),role:"radio","aria-checked":a,"aria-label":`Switch to ${n} theme`,onClick:()=>i(e),children:[t,a&&b.jsx(Lt.div,{layoutId:r,transition:{type:"spring",bounce:.3,duration:.6},className:"absolute inset-0 rounded-full border border-zinc-200 dark:border-zinc-700"})]})}const Vpe=[{icon:b.jsx(Tce,{}),value:"auto",label:"system"},{icon:b.jsx(Oce,{}),value:"light",label:"light"},{icon:b.jsx(Mce,{}),value:"dark",label:"dark"}];function Zpe({value:t,onChange:e,className:n}){const a=re(d=>d.config.ui.theme),i=re(d=>d.updateConfig),r=`theme-option-${S.useId()}`,[s,o]=S.useState(!1);S.useEffect(()=>{o(!0)},[]);const c=t??a,p=e??(d=>{i(u=>({...u,ui:{...u.ui,theme:d}}))});return s?b.jsx(Lt.div,{initial:{opacity:0},animate:{opacity:1},transition:{duration:.3},className:j1("inline-flex items-center overflow-hidden rounded-full bg-white ring-1 ring-zinc-200 ring-inset dark:bg-zinc-950 dark:ring-zinc-700",n),role:"radiogroup","aria-label":"Theme mode",children:Vpe.map(d=>b.jsx(qpe,{icon:d.icon,value:d.value,label:d.label,isActive:c===d.value,onClick:p,layoutId:r},d.value))},String(s)):b.jsx("div",{className:j1("flex h-8 w-24",n)})}function Gpe(t){const e=boe(t,{stiffness:180,damping:22,mass:.8});return S.useEffect(()=>{e.set(t)},[t,e]),Xz(e,a=>Math.round(a).toString())}const O3="0.35.0",Lc=[.16,1,.3,1],Ka={fade:{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18,ease:Lc}},toast:{initial:{opacity:0,y:12,scale:.97},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:6,scale:.97},transition:{duration:.22,ease:Lc}},progressBar:t=>({initial:!1,animate:{width:`${t}%`},transition:{duration:.32,ease:Lc}}),heroStagger:t=>({initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.32,ease:Lc,delay:.05+t*.05}}),headerCrossfade:{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18,ease:Lc}},panel:{initial:{height:0,opacity:0},animate:{height:"auto",opacity:1},exit:{height:0,opacity:0},transition:{duration:.18,ease:Lc}},rotate:t=>({animate:{rotate:t?90:0},transition:{duration:.15,ease:Lc}}),chip:{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.9},transition:{duration:.15,ease:Lc}}};function TH({className:t="w-6 h-6"}){return b.jsxs("svg",{viewBox:"0 0 150 150",className:t,version:"1.1",xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",style:{fillRule:"evenodd",clipRule:"evenodd",strokeLinejoin:"round",strokeMiterlimit:2},children:[b.jsx("path",{d:"M148,21.594L148,128.406C148,139.22 139.22,148 128.406,148L21.594,148C10.78,148 2,139.22 2,128.406L2,21.594C2,10.78 10.78,2 21.594,2C139.22,2 148,10.78 148,21.594Z",style:{fill:"url(#_KandownLinear1)"}}),b.jsxs("g",{transform:"matrix(0.823551,0,0,0.823551,12.830775,11.282318)",children:[b.jsx("g",{transform:"matrix(1.620982,0,0,1.566239,-41.718998,-41.628205)",children:b.jsx("path",{d:"M56.491,62.601C57.2,61.897 57.602,60.925 57.606,59.908C57.627,53.936 57.7,33.2 57.7,33.2C57.6,29.7 55,27.6 52,27.6L42.075,27.6C38.544,27.6 35.673,30.547 35.644,34.201C35.528,48.996 35.327,83.484 35.956,83.013C35.956,83.013 52.072,66.994 56.491,62.601Z",style:{fill:"rgb(252,255,239)",fillRule:"nonzero"}})}),b.jsx("g",{transform:"matrix(1.566239,0,0,1.566239,-39.774573,-41.628205)",children:b.jsx("path",{d:"M87.6,43.8C84.2,43.9 80.5,45.1 77.7,47.5L39.2,86.2C37.1,88.3 35.8,91 35.7,93.7L35.7,116.574C35.7,117.219 36.088,117.802 36.683,118.051C37.278,118.3 37.965,118.167 38.425,117.714C50.467,105.842 98.836,58.16 110.608,46.555C111.047,46.122 111.185,45.468 110.956,44.894C110.728,44.321 110.178,43.94 109.561,43.928C106.663,43.871 103.089,43.8 103.089,43.8L87.6,43.8Z",style:{fill:"rgb(241,255,184)",fillRule:"nonzero"}})}),b.jsx("g",{transform:"matrix(0.766318,0.766329,-1.302872,1.302853,170.442469,-47.541879)",children:b.jsx("path",{d:"M38.038,101.45C35.808,101.45 34,100.387 34,99.075C34,95.326 34,88.102 34,84.58C34,84.042 34.364,83.525 35.011,83.145C35.658,82.764 36.536,82.55 37.452,82.55C46.372,82.55 69.5,82.55 69.5,82.55C69.5,82.55 69.5,77.52 69.5,74.389C69.5,73.947 69.936,73.545 70.617,73.359C71.298,73.173 72.101,73.236 72.675,73.521C80.028,77.17 98.075,86.125 104.279,89.204C104.832,89.479 105.168,89.876 105.206,90.301C105.245,90.727 104.982,91.143 104.481,91.45C98.972,94.832 83.072,104.591 75.013,109.539C74.195,110.041 72.946,110.206 71.841,109.959C70.737,109.712 69.99,109.101 69.946,108.406C69.744,105.262 69.5,101.45 69.5,101.45L38.038,101.45Z",style:{fill:"rgb(136,225,56)"}})})]}),b.jsx("defs",{children:b.jsxs("linearGradient",{id:"_KandownLinear1",x1:"0",y1:"0",x2:"1",y2:"0",gradientUnits:"userSpaceOnUse",gradientTransform:"matrix(62,131,-131,62,9,8)",children:[b.jsx("stop",{offset:"0",style:{stopColor:"rgb(12,29,23)",stopOpacity:1}}),b.jsx("stop",{offset:"1",style:{stopColor:"rgb(24,41,35)",stopOpacity:1}})]})})]})}function Wpe(){const{t}=xn(),e=re(ee=>ee.dirHandle),n=re(ee=>ee.isOpen),a=re(ee=>ee.projectName),i=re(ee=>ee.closeDrawer),r=re(ee=>ee.drawerTaskId),s=re(ee=>ee.saveDrawer),o=re(ee=>ee.archivedTasks.length),c=re(ee=>ee.showArchives),p=re(ee=>ee.setShowArchives),d=re(ee=>ee.columns),u=re(ee=>ee.openFolder),f=re(ee=>ee.reloadBoard),h=re(ee=>ee.createTask),v=re(ee=>ee.setCommandOpen),k=re(ee=>ee.viewMode),w=re(ee=>ee.setViewMode),x=re(ee=>ee.density),$=re(ee=>ee.setDensity),E=re(ee=>ee.setCurrentPage),P=re(ee=>ee.recentProjects),L=re(ee=>ee.openRecentProject),M=re(ee=>ee.filters),D=re(ee=>ee.setFilter),z=re(ee=>ee.clearFilters),I=re(ee=>ee.config.fields),j=re(ee=>ee.lastReloadError),G=re(ee=>ee.watcherError),J=re(ee=>ee.restartWatcher),[ne,U]=S.useState(!1),[F,B]=S.useState(!0),Y=S.useRef(null),X=S.useRef(null),oe=d.reduce((ee,K)=>ee+K.tasks.length,0),O=Gpe(oe),Z=[];I.priority&&M.priority&&Z.push({type:"priority",label:M.priority,value:M.priority}),I.tags&&M.tag&&Z.push({type:"tag",label:"#"+M.tag,value:M.tag}),I.assignee&&M.assignee&&Z.push({type:"assignee",label:"@"+M.assignee,value:M.assignee});const q=[{label:t("filterBar.ownerAll"),value:""},{label:t("filterBar.ownerHuman"),value:"human"},{label:t("filterBar.ownerAI"),value:"ai"}],R=Z.length>0||M.search||I.ownerType&&M.ownerType;return S.useEffect(()=>{if(!ne)return;const ee=K=>{Y.current&&!Y.current.contains(K.target)&&U(!1)};return document.addEventListener("mousedown",ee),()=>document.removeEventListener("mousedown",ee)},[ne]),S.useEffect(()=>{const ee=setTimeout(()=>B(!1),5e3);return()=>clearTimeout(ee)},[]),S.useEffect(()=>{document.title=a?`${a} · Kandown`:"Kandown"},[a]),b.jsxs(b.Fragment,{children:[(j||G)&&b.jsxs("div",{className:"flex items-center gap-2 px-5 py-1.5 bg-amber-500/10 border-b border-amber-500/30 text-[12px] text-amber-700 dark:text-amber-300",children:[b.jsx("span",{className:"flex-1 truncate",children:G?`⚠ ${G}`:`⚠ ${j}`}),G&&b.jsx("button",{type:"button",onClick:J,className:"px-2 py-0.5 rounded bg-amber-500/20 hover:bg-amber-500/30 text-[11.5px] font-medium",children:"Restart watcher"}),b.jsx("button",{type:"button",onClick:f,className:"px-2 py-0.5 rounded bg-amber-500/20 hover:bg-amber-500/30 text-[11.5px] font-medium",children:"Reload"})]}),b.jsxs("header",{className:"flex items-center justify-between px-5 h-[64px] border-b border-border bg-card/80 backdrop-blur-xl relative z-10",children:[b.jsxs("div",{className:"flex items-center gap-4 min-w-0",children:[b.jsxs("div",{className:"flex items-center gap-2.5 flex-shrink-0",children:[b.jsxs("button",{onClick:()=>{r?s():i({replace:!0})},className:"flex items-center gap-2 cursor-pointer",children:[b.jsx(TH,{className:"w-[34px] h-[34px] dark:text-white text-black"}),b.jsx(ya,{mode:"wait",initial:!1,children:F?b.jsxs(Lt.span,{...Ka.headerCrossfade,className:"flex items-center gap-2",children:[b.jsx("span",{className:"text-[15px] font-semibold tracking-tight text-fg",children:"kandown"}),b.jsxs("span",{className:"inline-flex items-center h-5 px-1.5 text-[10.5px] font-semibold text-red-600 bg-red-50 dark:text-red-400 dark:bg-red-500/15 rounded-md",children:["v",O3]})]},"boot"):a?b.jsx(Lt.span,{...Ka.headerCrossfade,className:"text-[15px] font-semibold tracking-tight text-fg truncate max-w-[240px]",children:a},"project"):null})]}),r&&b.jsxs("button",{type:"button",onClick:()=>{s()},className:"hidden md:inline-flex items-center gap-2 rounded-xl border border-border bg-bg px-3 py-2 text-[13px] font-semibold text-fg shadow-sm transition-colors hover:border-border-strong hover:bg-bg-2",title:t("taskWorkspace.backToCards"),children:[b.jsx(nn.ArrowLeft,{size:15}),b.jsx("span",{children:t("common.back")})]})]}),e&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"w-px h-[20px] bg-black/[0.08] dark:bg-white/[0.08] flex-shrink-0"}),b.jsxs("div",{className:"flex items-center gap-2 px-3 h-9 bg-secondary/60 border border-border rounded-xl min-w-[200px] max-w-[280px] focus-within:border-border-focus focus-within:bg-secondary transition-all",children:[b.jsx(nn.Search,{size:14,className:"text-fg-muted/60 flex-shrink-0"}),b.jsx("input",{ref:X,type:"text",placeholder:t("filterBar.searchPlaceholder"),value:M.search,onChange:ee=>D("search",ee.target.value),className:"bg-transparent border-none outline-none text-fg text-[13px] w-full placeholder:text-fg-muted/60"}),M.search?b.jsx("button",{onClick:()=>D("search",""),className:"text-fg-muted/60 hover:text-fg flex-shrink-0",children:b.jsx(nn.X,{size:14})}):b.jsx("kbd",{className:"inline-flex items-center h-5 px-1.5 text-[10px] font-medium text-fg-muted/50 bg-black/[0.04] dark:bg-white/[0.08] rounded border border-black/[0.06] dark:border-white/[0.1]",children:"⌘K"})]}),b.jsxs("div",{className:"flex items-center gap-1.5 flex-wrap overflow-hidden",children:[b.jsx(ya,{children:Z.map(ee=>b.jsxs(Lt.button,{...Ka.chip,onClick:()=>D(ee.type,null),className:"inline-flex items-center gap-1 h-6 px-2.5 text-[12px] text-fg bg-black/[0.05] dark:bg-white/[0.1] border border-black/[0.08] dark:border-white/[0.12] rounded-lg hover:bg-black/[0.08] dark:hover:bg-white/[0.15] transition-colors",children:[ee.label,b.jsx(nn.X,{size:10,className:"text-fg-muted/60"})]},ee.type+ee.value))}),I.ownerType&&b.jsx("div",{className:"flex items-center h-6 border border-black/[0.06] dark:border-white/[0.1] rounded-lg overflow-hidden",children:q.map(ee=>b.jsx("button",{onClick:()=>D("ownerType",ee.value),className:`h-full px-2.5 text-[12px] transition-colors ${M.ownerType===ee.value?"bg-black/[0.06] dark:bg-white/[0.12] text-fg":"text-fg-muted/70 hover:text-fg"}`,children:ee.label},ee.value))}),R&&b.jsx("button",{onClick:z,className:"text-[12px] text-fg-muted/60 hover:text-fg transition-colors",children:t("filterBar.clearAll")})]})]}),e&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"w-px h-[20px] bg-black/[0.08] dark:bg-white/[0.08] flex-shrink-0"}),b.jsxs("div",{className:"relative flex-shrink-0",ref:Y,children:[b.jsxs("button",{onClick:()=>U(ee=>!ee),className:"flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] text-fg-muted hover:text-fg hover:bg-black/[0.04] dark:hover:bg-white/[0.06] rounded-lg transition-colors border border-transparent hover:border-black/[0.06] dark:hover:border-white/[0.1]",children:[b.jsx(nn.Folder,{size:13,className:"text-fg-muted/70"}),b.jsxs("span",{className:"font-medium",children:[".",e.name]}),b.jsx(nn.ChevronDown,{size:11,className:"opacity-50"})]}),b.jsx(ya,{children:ne&&b.jsx(Lt.div,{...Ka.fade,initial:{opacity:0,y:-4},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:-4},transition:{duration:.12,ease:Ka.fade.transition.ease},className:"absolute top-full left-0 mt-2 min-w-[240px] glass rounded-xl shadow-[0_16px_48px_rgba(0,0,0,0.5)] overflow-hidden z-50",children:b.jsxs("div",{className:"py-1.5",children:[P.length>0&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-fg-muted/60",children:t("header.recentProjects")}),P.map(ee=>b.jsxs("button",{onClick:()=>{U(!1),L(ee)},className:"w-full flex items-center gap-2 px-3 py-2 text-[13.5px] text-left hover:bg-black/[0.04] dark:hover:bg-white/[0.06] transition-colors",children:[b.jsx(nn.Folder,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{className:"truncate",children:ee.name}),ee.id===e.name&&b.jsx(nn.Check,{size:12,className:"ml-auto text-emerald-500"})]},ee.id)),b.jsx("div",{className:"h-px bg-black/[0.06] dark:bg-white/[0.08] my-1.5 mx-2"})]}),b.jsxs("button",{onClick:()=>{U(!1),u()},className:"w-full flex items-center gap-2 px-3 py-2 text-[13.5px] text-left hover:bg-black/[0.04] dark:hover:bg-white/[0.06] transition-colors",children:[b.jsx(nn.Plus,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{children:t("header.openFolder...")})]})]})})})]})]})]}),b.jsx("div",{className:"flex items-center gap-2 flex-shrink-0",children:n||e?b.jsxs(b.Fragment,{children:[b.jsxs("div",{className:"flex items-center gap-2 mr-2 text-[12.5px] text-fg-muted/70",children:[b.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full bg-emerald-500"}),b.jsx(Lt.span,{className:"tabular-nums font-medium transition-colors duration-200",children:O}),b.jsx("span",{children:t("header.tasks")})]}),b.jsxs("div",{className:"flex items-center bg-black/[0.04] dark:bg-white/[0.06] border border-black/[0.06] dark:border-white/[0.1] rounded-xl p-0.5 h-10",children:[b.jsx("button",{onClick:()=>w("board"),className:`w-9 h-9 inline-flex items-center justify-center rounded-lg transition-all ${k==="board"?"bg-card text-fg shadow-sm":"text-fg-muted/70 hover:text-fg"}`,title:t("common.board"),children:b.jsx(nn.LayoutBoard,{size:18})}),b.jsx("button",{onClick:()=>w("list"),className:`w-9 h-9 inline-flex items-center justify-center rounded-lg transition-all ${k==="list"?"bg-card text-fg shadow-sm":"text-fg-muted/70 hover:text-fg"}`,title:t("common.list"),children:b.jsx(nn.LayoutList,{size:18})})]}),b.jsx(an,{variant:"icon",icon:"Archive",onClick:()=>p(!c),title:c?t("header.backToBoard"):`${t("header.archives")} (${o})`,className:c?"text-accent":""}),b.jsx(an,{variant:"icon",icon:"Density",onClick:()=>$(x==="compact"?"comfortable":"compact"),title:`Density: ${x}`}),b.jsx(an,{variant:"icon",icon:"Settings",onClick:()=>E("settings"),title:t("common.settings")}),b.jsx(Zpe,{}),b.jsx("div",{className:"w-px h-5 bg-black/[0.08] dark:bg-white/[0.08] mx-1"}),b.jsx(an,{variant:"secondary",icon:"Search",label:t("common.search"),shortcut:"⌘K",onClick:()=>v(!0),title:"Command palette (⌘K)"}),b.jsx(an,{variant:"icon",icon:"Refresh",onClick:f,title:`${t("common.reload")} (R)`}),b.jsx(an,{variant:"primary",icon:"Plus",label:t("common.newTask"),shortcut:"N",onClick:()=>h()})]}):b.jsx(an,{variant:"primary",label:t("common.openFolder"),onClick:u})})]})]})}/**
|
|
218
|
+
`}}async function CH(t,e){try{return await(await(await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}async function vpe(t,e){try{return await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`),!0}catch{return!1}}async function NH(t,e){try{return await t.getDirectoryHandle("archive",{create:e})}catch{return null}}async function ype(t){if(Mt())return _S();const e=new Set;for await(const n of t.values())n.kind==="file"&&n.name.endsWith(".md")&&e.add(n.name.slice(0,-3));try{const n=await t.getDirectoryHandle("archive",{create:!1});for await(const a of n.values())a.kind==="file"&&a.name.endsWith(".md")&&e.add(a.name.slice(0,-3))}catch{}return[...e].sort((n,a)=>n.localeCompare(a,void 0,{numeric:!0}))}async function Ms(t,e){if(Mt())try{const i=await kS(e);return Ug(i)}catch{return ZL(e)}const a=await(async i=>{try{return await(await(await i.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}})(t)??await CH(t,e);return a!==null?Ug(a):ZL(e)}async function SH(t,e){if(Mt())try{const a=await kS(e);return{ok:!0,task:Ug(a)}}catch(a){return a.name==="NotFoundError"?{ok:!1,reason:"not-found"}:{ok:!1,reason:"unknown",error:a}}let n=null;try{n=await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{}if(n===null)try{n=await CH(t,e)}catch(a){return{ok:!1,reason:"unknown",error:a}}if(n===null)return{ok:!1,reason:"not-found"};if(n.trim()==="")return{ok:!1,reason:"corrupted",error:new Error(`Task file ${e}.md is empty`)};try{return{ok:!0,task:Ug(n)}}catch(a){return{ok:!1,reason:"corrupted",error:a}}}async function mu(t,e,n,a){const i=bS(n,a);if(Mt())return cpe(e,i);try{const o=await(await(await vpe(t,e)?await NH(t,!0):t).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}}catch(r){throw Rh(r,`${e}.md`)}}async function Z2(t,e){if(Mt())return ppe(e);try{await t.removeEntry(`${e}.md`)}catch{}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}async function _pe(t,e){await bi(`/api/tasks/${encodeURIComponent(t)}/archive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function kpe(t,e){await bi(`/api/tasks/${encodeURIComponent(t)}/unarchive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function GL(t,e,n,a){const i=bS(n,a);if(Mt())return _pe(e,i);try{const o=await(await(await NH(t,!0)).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}try{await t.removeEntry(`${e}.md`)}catch{}}catch(r){throw Rh(r,`archive/${e}.md`)}}async function wpe(t,e,n,a){const i=bS(n,a);if(Mt())return kpe(e,i);try{const s=await(await t.getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await s.write(i)}finally{await s.close()}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}catch(r){throw Rh(r,`${e}.md`)}}const xpe="kanban-md",Ape=1,cp="recentProjects";function wS(){return new Promise((t,e)=>{const n=indexedDB.open(xpe,Ape);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result),n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains(cp)||a.createObjectStore(cp,{keyPath:"id"})}})}async function G2(t){if(f0())return;const e=await wS();return new Promise((n,a)=>{const i=e.transaction(cp,"readwrite");i.objectStore(cp).put(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function Uy(){if(f0())return[];const t=await wS();return new Promise((e,n)=>{const i=t.transaction(cp,"readonly").objectStore(cp).getAll();i.onsuccess=()=>{const r=i.result||[];r.sort((s,o)=>o.lastOpened-s.lastOpened),e(r.slice(0,10))},i.onerror=()=>n(i.error)})}async function Cpe(t){if(f0())return;const e=await wS();return new Promise((n,a)=>{const i=e.transaction(cp,"readwrite");i.objectStore(cp).delete(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function WL(t,e=!0){const n={mode:e?"readwrite":"read"};try{return await t.queryPermission(n)==="granted"||await t.requestPermission(n)==="granted"}catch(a){return console.warn("[FS] verifyPermission: handle is no longer valid:",a),!1}}async function Npe(){try{return await(await bi("/api/update/check")).json()}catch{return null}}async function $H(){try{return await(await bi("/api/update/apply",{method:"POST"})).json()}catch{return null}}function g0(t=Ti){const e=t.board.columns;return e[e.length-1]??"Done"}function Spe(t,e=Ti){return t===g0(e)||t.toLowerCase()==="archived"}class $pe{dirHandle=null;tasksDirHandle=null;intervalId=null;configHash=null;taskHashes=new Map;knownTaskIds=new Set;listeners=new Map;debounceTimers=new Map;debounceDelay=150;consecutiveErrors=0;maxConsecutiveErrors=5;disabled=!1;eventSource=null;start(e,n){this.dirHandle=e,this.tasksDirHandle=n,this.consecutiveErrors=0,this.disabled=!1,Mt()&&this.startServerSse(),e&&n&&(this.initHashes(),this.intervalId=setInterval(()=>void this.tick(),300))}startServerSse(){if(typeof window>"u"||!Mt()||this.eventSource)return;const e=window.__KANDOWN_TOKEN__,n=e?`/api/events?token=${encodeURIComponent(e)}`:"/api/events";try{this.eventSource=new EventSource(n),this.eventSource.onmessage=a=>{try{const i=JSON.parse(a.data);i.type==="change"&&(i.taskId?this.emit("taskChanged",i.taskId):(this.emit("configChanged"),this.emit("taskChanged","")))}catch{}}}catch(a){console.warn("[Watcher] EventSource init failed:",a)}}stop(){this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.configHash=null,this.taskHashes.clear(),this.knownTaskIds.clear(),this.listeners.clear(),this.debounceTimers.forEach(e=>clearTimeout(e)),this.debounceTimers.clear(),this.consecutiveErrors=0,this.disabled=!1}isDisabled(){return this.disabled}on(e,n){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(n),()=>{this.listeners.get(e)?.delete(n)}}getKnownTaskIds(){return Array.from(this.knownTaskIds)}async initHashes(){if(!(!this.dirHandle||!this.tasksDirHandle))try{const e=await KL(this.dirHandle);e!==null&&(this.configHash=await this.hash(e)),await this.syncTaskDir(!1)}catch(e){console.warn("[Watcher] initHashes error:",e)}}async tick(){if(!(!this.dirHandle||!this.tasksDirHandle)&&!this.disabled)try{const e=await KL(this.dirHandle);if(e!==null){const n=await this.hash(e);this.configHash!==null&&n!==this.configHash&&(this.configHash=n,this.debouncedEmit("configChanged"))}for(const n of[...this.knownTaskIds])try{const a=await YL(this.tasksDirHandle,n);if(a!==null){const i=await this.hash(a),r=this.taskHashes.get(n);r!==void 0&&i!==r&&(this.taskHashes.set(n,i),this.debouncedEmit("taskChanged",n))}}catch(a){console.warn(`[Watcher] Error reading task ${n}:`,a)}await this.syncTaskDir(!0),this.consecutiveErrors=0}catch(e){this.consecutiveErrors++,console.error(`[Watcher] Tick failed (${this.consecutiveErrors}/${this.maxConsecutiveErrors}):`,e),this.consecutiveErrors>=this.maxConsecutiveErrors&&this.disable(`File watcher stopped after ${this.maxConsecutiveErrors} consecutive errors: ${e.message}`)}}disable(e){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.disabled=!0,this.emit("watcherError",e)}debouncedEmit(e,...n){const a=e+JSON.stringify(n),i=this.debounceTimers.get(a);i&&clearTimeout(i);const r=setTimeout(()=>{this.debounceTimers.delete(a),this.emit(e,...n)},this.debounceDelay);this.debounceTimers.set(a,r)}async syncTaskDir(e){if(!this.tasksDirHandle)return;let n;try{n=this.tasksDirHandle.values()}catch(a){throw a}for await(const a of n){if(a.kind!=="file"||!a.name.endsWith(".md"))continue;const i=a.name.replace(".md","");if(!this.knownTaskIds.has(i))try{this.knownTaskIds.add(i);const r=await YL(this.tasksDirHandle,i);r!==null&&(this.taskHashes.set(i,await this.hash(r)),e&&this.debouncedEmit("newTaskDetected",i))}catch(r){console.warn(`[Watcher] syncTaskDir: failed to read ${i}:`,r)}}}async hash(e){const a=new TextEncoder().encode(e),i=await crypto.subtle.digest("SHA-256",a);return Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("")}emit(e,...n){this.listeners.get(e)?.forEach(i=>{if(e==="configChanged"){i();return}if(e==="taskChanged"){const[s]=n;i(s);return}if(e==="newTaskDetected"){const[s]=n;i(s);return}const[r]=n;i(r)})}}async function KL(t){try{return await(await(await t.getFileHandle("kandown.json")).getFile()).text()}catch{return null}}async function YL(t,e){try{return await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}const jo=new $pe,Epe={soft:[{frequency:520,durationMs:90,delayMs:0,type:"sine"},{frequency:720,durationMs:120,delayMs:95,type:"sine"}],chime:[{frequency:660,durationMs:120,delayMs:0,type:"triangle"},{frequency:880,durationMs:160,delayMs:125,type:"triangle"}],ping:[{frequency:920,durationMs:110,delayMs:0,type:"sine"}],pop:[{frequency:260,durationMs:55,delayMs:0,type:"square"},{frequency:520,durationMs:80,delayMs:60,type:"square"}]};let XL=null;function EH(){return"Notification"in window?Notification.permission:"unsupported"}async function Tpe(){return"Notification"in window?await Notification.requestPermission():"unsupported"}function W2({title:t,body:e,config:n}){if(n.notifications.webhookUrl&&fetch(n.notifications.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"kandown_notification",title:t,body:e,timestamp:new Date().toISOString()})}).catch(()=>{}),n.notifications.sound&&Ppe(n.notifications.soundId),!(!n.notifications.browser||EH()!=="granted"))try{new Notification(t,{body:e})}catch{}}function Ppe(t){const e=Epe[t],n=window.AudioContext??window.webkitAudioContext;if(!(!n||e.length===0))try{XL??=new n;const a=XL;a.state==="suspended"&&a.resume();const i=a.currentTime+.01;e.forEach(r=>{const s=a.createOscillator(),o=a.createGain(),c=i+r.delayMs/1e3,p=c+r.durationMs/1e3;s.type=r.type??"sine",s.frequency.setValueAtTime(r.frequency,c),o.gain.setValueAtTime(1e-4,c),o.gain.exponentialRampToValueAtTime(.08,c+.01),o.gain.exponentialRampToValueAtTime(1e-4,p),s.connect(o),o.connect(a.destination),s.start(c),s.stop(p+.02)})}catch{}}async function rl(t,e={}){const{maxAttempts:n=3,baseDelayMs:a=500,retryableCheck:i=ape}=e;let r;for(let s=1;s<=n;s++)try{return await t()}catch(o){if(r=o,!i(o))throw o;if(s<n){const c=a*Math.pow(2,s-1);await new Promise(p=>setTimeout(p,c))}}throw r}function Mpe(t){const e=t.toLowerCase(),n=new Date;if(e==="today")return n.toISOString().split("T")[0];if(e==="tomorrow"){const i=new Date(n);return i.setDate(i.getDate()+1),i.toISOString().split("T")[0]}const a=["sunday","monday","tuesday","wednesday","thursday","friday","saturday"];if(a.includes(e)){const i=a.indexOf(e),r=new Date(n);let s=i-r.getDay();return s<=0&&(s+=7),r.setDate(r.getDate()+s),r.toISOString().split("T")[0]}return t}function Lpe(t){let e=t.trim(),n;const a=[];let i,r;const s=[];return e=e.replace(/(?:^|\s)p([1-4])(?:\s|$)/i,(c,p)=>(n=`P${p}`," ")),e=e.replace(/(?:^|\s)#([a-zA-Z0-9_-]+)/g,(c,p)=>(a.push(p.toLowerCase())," ")),e=e.replace(/(?:^|\s)@([a-zA-Z0-9_-]+)/g,(c,p)=>(i=p," ")),e=e.replace(/(?:^|\s)due:([^\s]+)/i,(c,p)=>(r=Mpe(p)," ")),e=e.replace(/(?:^|\s)\+([a-zA-Z0-9_-]+)/g,(c,p)=>(s.push(p)," ")),{title:e.replace(/\s+/g," ").trim()||t,...n?{priority:n}:{},...a.length>0?{tags:a}:{},...i?{assignee:i}:{},...r?{due:r}:{},...s.length>0?{depends_on:s}:{}}}const jpe=/^[A-Za-z0-9_-]+$/;function K2(t){if(!t)return null;const e=t.trim().replace(/^\/+|\/+$/g,"").replace(/^#/,"");return!e||e.includes("/")||e.includes(".")||!jpe.test(e)?null:/^\d+$/.test(e)?`t${e}`:e}function Dpe(t){const e=new URLSearchParams(t.search).get("p");if(!e)return null;const[n]=e.split("/").filter(Boolean);return n||null}function qy(t){const e=new URLSearchParams(t.search),n=K2(e.get("task"));if(n)return n;const a=e.get("p");if(a){const[,...r]=a.split("/").filter(Boolean),s=K2(r.join("/"));if(s)return s}return K2(decodeURIComponent(t.pathname))}function I3(t){return t?`/?p=${encodeURIComponent(t)}`:"/"}function xS(t,e){const n=t.replace(/^t(?=\d+$)/,""),a=`/${encodeURIComponent(n)}`;return e?`${a}?p=${encodeURIComponent(e)}`:a}function Vy(t,e=!1){typeof window>"u"||`${window.location.pathname}${window.location.search}`===t||(e?window.history.replaceState({},"",t):window.history.pushState({},"",t),window.dispatchEvent(new Event("kandown:urlchange")))}function zv(t){typeof window<"u"&&qy(window.location)||Vy(I3(t))}function Ipe(t,e=[]){let n=-1;for(const a of[...t.flatMap(i=>i.tasks),...e]){const i=a.id.match(/^t(\d+)$/);if(i){const r=parseInt(i[1],10);r>n&&(n=r)}}return"t"+(n+1)}async function Rpe(){const t=await _S();return await Promise.all(t.map(async n=>{const{frontmatter:a,body:i}=await AH(n),r={...a,id:a.id||n,status:a.status||"Backlog"},{subtasks:s,bodyWithoutSubtasks:o}=Os(i);return{id:n,frontmatter:r,body:o,subtasks:s}}))}async function Ope(t){const e=await ype(t),n=await Promise.all(e.map(async r=>{const s=await SH(t,r);return{id:r,result:s}})),a=[],i=[];for(const{id:r,result:s}of n)if(s.ok){const o={...s.task.frontmatter,id:s.task.frontmatter.id||r,status:s.task.frontmatter.status||"Backlog"},{subtasks:c,bodyWithoutSubtasks:p}=Os(s.task.body);a.push({id:r,frontmatter:o,body:p,subtasks:c})}else{if(s.reason==="not-found")continue;i.push(r)}return{tasks:a,failedIds:i}}async function QL(t,e,n){const a=[];for(const s of e){const o=s.name;s.tasks.forEach((c,p)=>{const d=(async()=>{const{frontmatter:u,body:f}=await Ms(t,c.id);await mu(t,c.id,{...u,id:c.id,status:o,order:p},f)})();a.push({id:c.id,promise:d})})}const i=await Promise.allSettled(a.map(s=>s.promise)),r=[];return i.forEach((s,o)=>{s.status==="rejected"&&r.push(a[o].id)}),{failedIds:r}}function ul(t){kH(t.ui.theme,t.ui.skin,t.ui.font,t.ui.background)}function R3(t){return{title:t.frontmatter.title||t.id,status:t.frontmatter.status||"Backlog",body:t.body,subtasks:t.subtasks}}function Y2(t){xu.clear(),t.forEach(e=>{xu.set(e.id,R3(e))})}function Fpe(t){const e=t.split(/[\\/]+/).filter(Boolean),n=e[e.length-1];return n===".kandown"?e[e.length-2]??"Project":n??"Project"}function zpe(t,e){return e.reduce((n,a,i)=>{const r=t[i]?.done??!1;return n+(a.done&&!r?1:0)},0)}function Hpe(t,e){const n=t.subtasks.map(i=>({text:i.text,description:i.description??"",report:i.report??""})),a=e.subtasks.map(i=>({text:i.text,description:i.description??"",report:i.report??""}));return t.title!==e.title||t.body!==e.body||JSON.stringify(n)!==JSON.stringify(a)}let Bpe=0;const xu=new Map,Ff=new Map;let X2=null,Qd=!1;function JL(t){return[...new Set(t.filter(e=>typeof e=="string"&&e.trim().length>0))]}const re=qce((t,e)=>({isOpen:!1,loading:!1,dirHandle:null,projectName:null,tasksDirHandle:null,boardTitle:"Project Kanban",columns:[],archivedTasks:[],showArchives:!1,showMetadata:!0,taskContents:new Map,searchMatches:new Map,viewMode:localStorage.getItem("kandown:view")||"board",density:localStorage.getItem("kandown:density")||"comfortable",filters:{search:"",priority:null,tag:null,assignee:null,ownerType:null},commandOpen:!1,cheatsheetOpen:!1,drawerTaskId:null,drawerData:null,currentPage:"board",config:Ti,recentProjects:[],toasts:[],agentHook:null,isReloading:!1,lastReloadError:null,failedTaskIds:[],watcherError:null,hasUnsavedDrawerEdits:!1,lastSaveError:null,drawerRecoveryData:new Map,selectedTaskIds:[],toggleTaskSelection:n=>{t(a=>({selectedTaskIds:a.selectedTaskIds.includes(n)?a.selectedTaskIds.filter(s=>s!==n):[...a.selectedTaskIds,n]}))},clearTaskSelection:()=>t({selectedTaskIds:[]}),bulkMoveTasks:async n=>{const{selectedTaskIds:a,columns:i,moveTask:r}=e();for(const s of a){let o="Backlog";for(const c of i)if(c.tasks.some(p=>p.id===s)){o=c.name;break}await r(s,o,n)}t({selectedTaskIds:[]})},bulkDeleteTasks:async n=>{const{selectedTaskIds:a,tasksDirHandle:i,drawerTaskId:r}=e(),s=JL(n??a);if(!(s.length===0||!i&&!Mt())){if(Qd){e().toast("Another bulk action is already running","warning");return}Qd=!0;try{const o=await Promise.allSettled(s.map(d=>rl(()=>Z2(i||null,d),{maxAttempts:3}))),c=s.filter((d,u)=>o[u]?.status==="fulfilled"),p=s.filter((d,u)=>o[u]?.status==="rejected");r&&c.includes(r)&&e().closeDrawer(),t(d=>({selectedTaskIds:d.selectedTaskIds.filter(u=>!c.includes(u))})),await e().reloadBoard(),p.length>0?e().toast(`${c.length} deleted, ${p.length} could not be deleted`,"warning",8e3):e().toast(`Deleted ${c.length} task${c.length===1?"":"s"}`)}finally{Qd=!1}}},bulkArchiveTasks:async n=>{const{tasksDirHandle:a,drawerTaskId:i}=e(),r=JL(n);if(!(r.length===0||!a&&!Mt())){if(Qd){e().toast("Another bulk action is already running","warning");return}Qd=!0;try{const s=await Promise.allSettled(r.map(async p=>{const d=await SH(a||null,p);if(!d.ok)throw new Error(`Task ${p} could not be read (${d.reason})`);await rl(()=>GL(a||null,p,{...d.task.frontmatter,id:p,archived:!0},d.task.body),{maxAttempts:3})})),o=r.filter((p,d)=>s[d]?.status==="fulfilled"),c=r.filter((p,d)=>s[d]?.status==="rejected");i&&o.includes(i)&&e().closeDrawer(),t(p=>({selectedTaskIds:p.selectedTaskIds.filter(d=>!o.includes(d))})),await e().reloadBoard(),c.length>0?e().toast(`${o.length} archived, ${c.length} could not be archived`,"warning",8e3):e().toast(`Archived ${o.length} task${o.length===1?"":"s"}`)}finally{Qd=!1}}},drawerBaseVersion:null,conflictState:null,showConflictModal:!1,openFolder:async()=>{if(!wH()){const c=navigator.userAgent||"this browser";e().toast(new npe(c).message,"error",8e3);return}let n;try{n=await mpe()}catch(c){c instanceof yS?e().toast("Permission denied — please grant access to the project folder","error"):e().toast("Failed to open folder: "+c.message,"error");return}if(!n)return;const{projectHandle:a,kandownHandle:i,tasksHandle:r}=n,s=a.name;t({dirHandle:i,tasksDirHandle:r,projectName:s}),zv(s);const o=Mt()?V2():null;try{await G2({id:a.name,name:a.name,handle:a,lastOpened:Date.now(),...o?{kandownDir:o}:{}})}catch(c){console.warn("[Store] Failed to save recent project:",c)}await e().loadConfig(),await e().reloadBoard();try{const c=await Uy();t({recentProjects:c})}catch(c){console.warn("[Store] Failed to load recent projects:",c)}e().setupWatcher()},openRecentProject:async n=>{const a={dirHandle:e().dirHandle,tasksDirHandle:e().tasksDirHandle,projectName:e().projectName};if(!await WL(n.handle,!0)){let r=!1;try{await By(n.handle),r=!0}catch{r=!1}if(!r){e().toast(`"${n.name}" is no longer accessible. Removed from recent projects.`,"warning",8e3);try{await Cpe(n.id);const s=await Uy();t({recentProjects:s})}catch{}return}e().toast("Permission denied — please grant access to the folder","error");return}try{const r=await By(n.handle),s=await D3(n.handle),o=n.handle.name;t({dirHandle:r,tasksDirHandle:s,projectName:o}),zv(o);try{await G2({...n,lastOpened:Date.now()})}catch(c){console.warn("[Store] Failed to update recent project:",c)}await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()}catch(r){t(a),e().toast(`Failed to open project: ${r.message}`,"error")}},openServerProject:async()=>{t({loading:!0});try{const n=V2();if(!n)throw new Error("No server root");await VL();const a=Fpe(n),i=await xH();ul(i);const r=await _S(),s=await Promise.all(r.map(async f=>{const{frontmatter:h,body:v}=await AH(f),k={...h,id:h.id||f,status:h.status||"Backlog"},{subtasks:w,bodyWithoutSubtasks:x}=Os(v);return{id:f,frontmatter:k,body:x,subtasks:w}}));Y2(s);const o=s.map(f=>({frontmatter:f.frontmatter,body:Xd(f.body,f.subtasks)})),c=B2(o,i.board.columns),p=U2(o),d=c.reduce((f,h)=>f+h.tasks.length,0),u=new Map;if(d<=10)for(const f of s)u.set(f.frontmatter.id,{frontmatter:f.frontmatter,subtasks:f.subtasks,body:f.body});t({loading:!1,isOpen:!0,config:i,columns:c,archivedTasks:p,boardTitle:"Project Kanban",projectName:a,taskContents:u,searchMatches:new Map}),zv(a),e().setupWatcher(),e().refreshAgentHook()}catch{t({loading:!1,isOpen:!1}),e().toast("Impossible de charger le projet. Relancez `kandown`.","error")}},tryAutoOpenServerProject:async()=>{if(!Mt())return;const n=V2();if(!n)return;await VL();const a=await Uy(),i=a.find(p=>p.kandownDir===n);if(!i){await e().openServerProject();return}if(!await WL(i.handle,!0)){await e().openServerProject();return}const s=await By(i.handle),o=await D3(i.handle),c=i.handle.name;t({dirHandle:s,tasksDirHandle:o,projectName:c,recentProjects:a,isOpen:!0}),zv(c),await G2({...i,lastOpened:Date.now()}),await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()},loadConfig:async()=>{const{dirHandle:n}=e();if(!(!n&&!Mt()))try{const a=await fpe(n);if(a.ok){t({config:a.config}),ul(a.config);return}if(a.reason==="corrupted"){if(a.rawContent&&n)try{const r=await(await n.getFileHandle("kandown.json.backup",{create:!0})).createWritable();try{await r.write(a.rawContent)}finally{await r.close()}}catch{}e().toast("kandown.json is corrupted — using default settings. A backup was saved as kandown.json.backup.","warning",1e4)}t({config:Ti}),ul(Ti)}catch{t({config:Ti}),ul(Ti)}},updateConfig:async n=>{const{dirHandle:a,config:i}=e();if(!a&&!Mt())return;const r=n(i);t({config:r}),ul(r);try{await gpe(a,r)}catch(s){const o=s;o instanceof Po?e().toast("Disk is full — settings were not saved.","error",8e3):e().toast("Failed to save config: "+o.message,"error")}},reloadBoard:async()=>{const{tasksDirHandle:n,config:a}=e();t({isReloading:!0,lastReloadError:null});try{if(Mt()){const i=await Rpe();Y2(i);const r=i.map(d=>({frontmatter:d.frontmatter,body:Xd(d.body,d.subtasks)})),s=B2(r,a.board.columns),o=U2(r);t({boardTitle:"Project Kanban",columns:s,archivedTasks:o});const c=s.reduce((d,u)=>d+u.tasks.length,0),p=new Map;if(c<=10)for(const d of i)p.set(d.frontmatter.id,{frontmatter:d.frontmatter,subtasks:d.subtasks,body:d.body});t({taskContents:p,searchMatches:new Map,failedTaskIds:[],isReloading:!1})}else if(n){const{tasks:i,failedIds:r}=await Ope(n);Y2(i);const s=i.map(u=>({frontmatter:u.frontmatter,body:Xd(u.body,u.subtasks)})),o=B2(s,a.board.columns),c=U2(s);t({boardTitle:"Project Kanban",columns:o,archivedTasks:c});const p=o.reduce((u,f)=>u+f.tasks.length,0),d=new Map;if(p<=10)for(const u of i)d.set(u.frontmatter.id,{frontmatter:u.frontmatter,subtasks:u.subtasks,body:u.body});if(r.length>0){const u=r.length===1?`Task ${r[0]} could not be loaded`:`${r.length} tasks could not be loaded`;e().toast(u,"warning",8e3)}t({taskContents:d,searchMatches:new Map,failedTaskIds:r,isReloading:!1})}else t({isReloading:!1})}catch(i){const r=i.message||String(i);t({isReloading:!1,lastReloadError:`Failed to reload board: ${r}`}),e().toast(`Board reload failed — showing last loaded state (${r})`,"warning",8e3)}},moveTask:async(n,a,i,r)=>{const{columns:s,config:o,taskContents:c,searchMatches:p}=e(),d=Mt();if(!d&&!e().tasksDirHandle)return;const u=s.find(E=>E.name===a),f=s.find(E=>E.name===i);if(!u||!f)return;const h=u.tasks.findIndex(E=>E.id===n);if(h===-1)return;const v=u.tasks[h];if(!v)return;if(Spe(i,o)){const E=new Map,P=g0(o).toLowerCase();for(const M of s)for(const D of M.tasks){const z=D.frontmatter&&(D.frontmatter.archived===!0||D.frontmatter.archived==="true");E.set(D.id,{exists:!0,resolved:z||D.id===n||M.name.toLowerCase()===P})}const L=[];for(const M of v.dependsOn){if(typeof M!="string"||!M.trim()||M===n)continue;const D=E.get(M);(!D||!D.resolved)&&L.push(M)}if(L.length>0){const M=L.length===1?L[0]:`${L.slice(0,-1).join(", ")} and ${L[L.length-1]}`;e().toast(`Cannot move ${n} to ${i}: blocked by ${M}`,"error");return}}const k=s.map(E=>({...E,tasks:[...E.tasks]})),w=k.find(E=>E.name===a),x=k.find(E=>E.name===i),[$]=w.tasks.splice(h,1);/done|termin|closed|complet/i.test(i)?$.checked=!0:$.checked=!1,r!==void 0?x.tasks.splice(r,0,$):x.tasks.push($),t({columns:k});try{const{tasksDirHandle:E}=e();if(!E&&!d)return;const P=a===i?k.filter(M=>M.name===i):k.filter(M=>M.name===a||M.name===i),{failedIds:L}=await rl(()=>QL(E??null,P,o.board.columns),{maxAttempts:3});if(L.length>0){const M=L.length===1?`Could not save move for ${L[0]}`:`${L.length} tasks could not be moved`;e().toast(M,"warning",8e3),await e().reloadBoard()}}catch(E){const P=E;P instanceof Po?e().toast("Disk is full — move was not saved. Free up space and try again.","error",8e3):e().toast("Failed to save: "+P.message,"error"),t({columns:s,taskContents:c,searchMatches:p})}},reorderInColumn:async(n,a,i)=>{const{columns:r,tasksDirHandle:s,config:o,taskContents:c,searchMatches:p}=e();if(!s&&!Mt())return;const d=r.map(h=>({...h,tasks:[...h.tasks]})),u=d.find(h=>h.name===n);if(!u)return;const[f]=u.tasks.splice(a,1);u.tasks.splice(i,0,f),t({columns:d});try{const{tasksDirHandle:h}=e(),v=Mt();if(!h&&!v)return;const{failedIds:k}=await rl(()=>QL(h??null,[u],o.board.columns),{maxAttempts:3});k.length>0&&(e().toast(`Could not save reorder for ${k.length} task(s)`,"warning",8e3),await e().reloadBoard())}catch(h){const v=h;v instanceof Po?e().toast("Disk is full — reorder was not saved.","error",8e3):e().toast("Failed to save: "+v.message,"error"),t({columns:r,taskContents:c,searchMatches:p})}},addColumn:async n=>{const a=n.trim();if(!a)return;const{config:i}=e();i.board.columns.some(r=>r.toLowerCase()===a.toLowerCase())||(await e().updateConfig(r=>({...r,board:{...r.board,columns:[...r.board.columns,a]}})),await e().reloadBoard())},renameColumn:async(n,a)=>{const i=a.trim(),{columns:r,tasksDirHandle:s,config:o}=e();if(!s||!i||i.toLowerCase()===n.toLowerCase())return;if(r.some(d=>d.name.toLowerCase()===i.toLowerCase())){e().toast("Column already exists","error");return}const c=r,p=r.map(d=>d.name===n?{...d,name:i}:d);t({columns:p});try{const d=c.find(u=>u.name===n);if(d){const f=(await Promise.allSettled(d.tasks.map(async(h,v)=>{const{frontmatter:k,body:w}=await Ms(s,h.id);await mu(s,h.id,{...k,id:h.id,status:i,order:v},w)}))).filter(h=>h.status==="rejected").length;f>0&&e().toast(`${f} task(s) could not be renamed`,"warning",8e3)}await e().updateConfig(u=>{const f={...u.board.columnColors??{}},h=f[n.toLowerCase()];h&&(f[i.toLowerCase()]=h,delete f[n.toLowerCase()]);const v=u.board.columns.some(k=>k.toLowerCase()===n.toLowerCase())?u.board.columns:[...u.board.columns,n];return{...u,board:{...u.board,columns:v.map(k=>k.toLowerCase()===n.toLowerCase()?i:k),columnColors:f}}}),await e().reloadBoard()}catch(d){e().toast("Failed to rename column: "+d.message,"error"),t({columns:c})}},reorderColumns:async(n,a)=>{const{config:i,columns:r,tasksDirHandle:s}=e();if(n<0||a<0||n>=r.length||a>=r.length||n===a||!s&&!Mt())return;const o=Array.from(r),[c]=o.splice(n,1);o.splice(a,0,c),t({columns:o});const p=o.map(d=>d.name);try{await e().updateConfig(d=>({...d,board:{...d.board,columns:p}})),await e().reloadBoard()}catch(d){e().toast("Failed to reorder columns: "+d.message,"error"),t({columns:r})}},deleteColumn:async n=>{const{columns:a,tasksDirHandle:i}=e();if(!i&&!Mt())return;const r=a.find(o=>o.name===n);if(!r)return;const s=a;t({columns:a.filter(o=>o.name!==n)});try{const c=(await Promise.allSettled(r.tasks.map(p=>Z2(i,p.id)))).filter(p=>p.status==="rejected").length;c>0&&e().toast(`${c} task(s) could not be deleted`,"warning",8e3),await e().updateConfig(p=>{const d={...p.board.columnColors??{}};return delete d[n.toLowerCase()],{...p,board:{...p.board,columns:p.board.columns.filter(u=>u.toLowerCase()!==n.toLowerCase()),columnColors:d}}}),await e().reloadBoard(),e().toast("Column deleted")}catch(o){e().toast("Failed to delete column: "+o.message,"error"),t({columns:s})}},createTask:async(n,a)=>{const{columns:i,tasksDirHandle:r,config:s,taskContents:o,searchMatches:c,archivedTasks:p}=e();if(!r&&!Mt()||!i.length)return null;const d=n||s.board.columns[0]||i[0].name,u=Ipe(i,p),f=i.find(E=>E.name===d)?.tasks.length??0,h=a?Lpe(a):null,v={id:u,title:h?.title||"",checked:!1,dependsOn:h?.depends_on||[],tags:h?.tags||[],assignee:h?.assignee||null,priority:h?.priority||(s.fields.priority?s.board.defaultPriority:null),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",progress:null,frontmatter:{}},k=i.map(E=>E.name===d?{...E,tasks:[...E.tasks,v]}:E),w=new Map(o),x={id:u,title:h?.title||"",status:d,order:f,priority:h?.priority||(s.fields.priority?s.board.defaultPriority:""),tags:h?.tags||[],assignee:h?.assignee||"",due:h?.due||"",depends_on:h?.depends_on||[],created:new Date().toISOString().slice(0,10),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",tools:""},$="";w.set(u,{frontmatter:x,subtasks:[],body:$}),t({columns:k,taskContents:w});try{const E=r||null;return await rl(()=>mu(E,u,x,$),{maxAttempts:3}),e().toast(`Created ${u.replace(/^t/,"")}`),await e().openDrawer(u),u}catch(E){const P=E;return P instanceof Po?e().toast("Disk is full — task was not created.","error",8e3):e().toast("Failed to create: "+P.message,"error"),t({columns:i,taskContents:o,searchMatches:c}),null}},deleteTask:async n=>{const{columns:a,tasksDirHandle:i,taskContents:r,searchMatches:s}=e();if(!i&&!Mt())return;const o=a.map(d=>({...d,tasks:d.tasks.filter(u=>u.id!==n)}));t({columns:o});const c=new Map(r);c.delete(n);const p=new Map(s);p.delete(n),t({taskContents:c,searchMatches:p});try{await Z2(i||null,n),e().toast("Deleted")}catch(d){const u=d;e().toast("Failed to delete: "+u.message,"error"),t({columns:a,taskContents:r,searchMatches:s})}},archiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Mt()))try{const{frontmatter:i,body:r}=await Ms(a||null,n);await GL(a||null,n,{...i,archived:!0},r),e().drawerTaskId===n&&e().closeDrawer(),await e().reloadBoard(),e().toast("Archived")}catch(i){const r=i;r instanceof Po?e().toast("Disk is full — task was not archived.","error",8e3):e().toast("Failed to archive: "+r.message,"error")}},unarchiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Mt()))try{const{frontmatter:i,body:r}=await Ms(a||null,n),s={...i};delete s.archived,await wpe(a||null,n,s,r),await e().reloadBoard(),e().toast("Restored")}catch(i){const r=i;r instanceof Po?e().toast("Disk is full — task was not restored.","error",8e3):e().toast("Failed to restore: "+r.message,"error")}},setShowArchives:n=>t({showArchives:n}),setShowMetadata:n=>t({showMetadata:n}),openDrawer:async(n,a={})=>{const{tasksDirHandle:i,projectName:r}=e();if(!(!i&&!Mt()))try{const{frontmatter:s,body:o}=await Ms(i,n),{subtasks:c,bodyWithoutSubtasks:p}=Os(o),d={frontmatter:s,subtasks:c,body:p,savedAt:Date.now()},u=e().drawerRecoveryData.get(n),f=u?{frontmatter:u.frontmatter,subtasks:u.subtasks,body:u.body}:{frontmatter:s,subtasks:c,body:p},h=new Map(e().drawerRecoveryData);h.delete(n),a.syncUrl!==!1&&Vy(xS(n,r),a.replace),t({drawerTaskId:n,drawerData:f,drawerBaseVersion:d,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!!u,lastSaveError:null,drawerRecoveryData:h}),u&&e().toast("Restored your unsaved edits for this task","info")}catch(s){e().toast("Failed to open: "+s.message,"error")}},closeDrawer:(n={})=>{n.syncUrl!==!1&&Vy(I3(e().projectName),n.replace),t({drawerTaskId:null,drawerData:null,drawerBaseVersion:null,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!1,lastSaveError:null})},markDrawerDirty:()=>t({hasUnsavedDrawerEdits:!0}),forceCloseDrawer:()=>{const{drawerTaskId:n,drawerData:a}=e();if(n&&a){const i=new Map(e().drawerRecoveryData);i.set(n,{frontmatter:a.frontmatter,subtasks:a.subtasks,body:a.body}),t({drawerRecoveryData:i})}e().closeDrawer()},updateDrawerData:n=>{const{drawerData:a}=e();a&&t({drawerData:n(a)})},saveDrawer:async()=>{const{drawerTaskId:n,drawerData:a,tasksDirHandle:i,taskContents:r}=e();if(!n||!a)return;const s=Xd(a.body,a.subtasks),o={...a.frontmatter,id:n};try{await rl(()=>mu(i||null,n,o,s),{maxAttempts:3}),e().toast("Saved");const c=new Map(e().drawerRecoveryData);c.delete(n),Vy(I3(e().projectName)),t({drawerTaskId:null,drawerData:null,hasUnsavedDrawerEdits:!1,lastSaveError:null,drawerRecoveryData:c});const p=new Map(r);p.set(n,{frontmatter:o,subtasks:a.subtasks,body:a.body}),t({taskContents:p}),await e().reloadBoard()}catch(c){const p=c,d=p instanceof Po?"Disk is full — your edits are kept. Free up space and retry.":"Failed to save: "+p.message;e().toast(d,"error",8e3),t({lastSaveError:d})}},saveDrawerMetadata:async()=>{const{drawerTaskId:n,drawerData:a,tasksDirHandle:i,taskContents:r}=e();if(!(!n||!a))try{const s=Xd(a.body,a.subtasks),o={...a.frontmatter,id:n};await rl(()=>mu(i||null,n,o,s),{maxAttempts:3});const c=new Map(r);c.set(n,{frontmatter:o,subtasks:a.subtasks,body:a.body}),t({taskContents:c,hasUnsavedDrawerEdits:!1,lastSaveError:null}),await e().reloadBoard()}catch(s){const o=s,c=o instanceof Po?"Disk is full — your edits are kept.":"Failed to save: "+o.message;t({hasUnsavedDrawerEdits:!0,lastSaveError:c})}},setViewMode:n=>{localStorage.setItem("kandown:view",n),t({viewMode:n})},setDensity:n=>{localStorage.setItem("kandown:density",n),t({density:n})},setFilter:(n,a)=>{if(t(i=>({filters:{...i.filters,[n]:a}})),n==="search"){const{columns:i,tasksDirHandle:r,taskContents:s}=e(),o=a,c=i.flatMap(p=>p.tasks.map(d=>d.id));if(r){const p=c.filter(d=>!s.has(d));p.length>0?e().loadTaskContents(p).then(()=>{e().computeSearchMatches(o)}):e().computeSearchMatches(o)}}},clearFilters:()=>t({filters:{search:"",priority:null,tag:null,assignee:null,ownerType:null},searchMatches:new Map}),setCommandOpen:n=>t({commandOpen:n}),setCheatsheetOpen:n=>t({cheatsheetOpen:n}),refreshAgentHook:async()=>{if(!Mt()){t({agentHook:null});return}const n=await lpe();t({agentHook:n?.agentHook??null})},sendTaskToAgent:async n=>{const a=e().agentHook;if(!a){e().toast("Agent hook not configured","error");return}e().toast(`Sending to ${a.label}…`);const i=await dpe(n);if(i===null){e().toast("Could not reach the daemon","error");return}i.ok?e().toast(`Sent to ${a.label}`):e().toast(i.error||"Agent hook failed","error")},setCurrentPage:n=>t({currentPage:n}),loadTaskContents:async n=>{const{tasksDirHandle:a}=e();if(!a)return;const i=new Map(e().taskContents);await Promise.all(n.map(async r=>{if(!i.has(r))try{const{frontmatter:s,body:o}=await Ms(a,r),{subtasks:c,bodyWithoutSubtasks:p}=Os(o);i.set(r,{frontmatter:s,subtasks:c,body:p})}catch{}})),t({taskContents:i})},computeSearchMatches:n=>{if(!n.trim()){t({searchMatches:new Map});return}const{taskContents:a}=e(),i=new Map,r=n.toLowerCase();for(const[s,o]of a){const c=vH(o,r);c.length>0&&i.set(s,c)}t({searchMatches:i})},toast:(n,a="success",i)=>{const r=++Bpe,s=i??(a==="error"||a==="warning"?6e3:2500);t(o=>({toasts:[...o.toasts,{id:r,message:n,type:a}]})),setTimeout(()=>{t(o=>({toasts:o.toasts.filter(c=>c.id!==r)}))},s)},dismissToast:n=>t(a=>({toasts:a.toasts.filter(i=>i.id!==n)})),resolveConflict:async n=>{const{conflictState:a,drawerData:i,tasksDirHandle:r,drawerTaskId:s,drawerBaseVersion:o}=e();if(!(!a||!r||!s))if(n==="reload"){const{frontmatter:c,body:p}=await Ms(r,s),{subtasks:d,bodyWithoutSubtasks:u}=Os(p);t({drawerData:{frontmatter:c,subtasks:d,body:u},drawerBaseVersion:{frontmatter:c,subtasks:d,body:u,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Reloaded from disk")}else if(n==="overwrite"){if(i&&s&&o){const c=Xd(i.body,i.subtasks),p={...i.frontmatter,id:s};try{await mu(r,s,p,c),t({drawerBaseVersion:{...i,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Overwritten remote changes")}catch(d){e().toast("Failed to overwrite: "+d.message,"error")}}}else t({conflictState:null,showConflictModal:!1})},setupWatcher:()=>{if(Mt()){X2&&clearInterval(X2),X2=setInterval(()=>{e().reloadBoard()},2e3);return}const{dirHandle:n,tasksDirHandle:a}=e();if(!n||!a)return;jo.stop(),Ff.forEach(s=>clearTimeout(s)),Ff.clear(),jo.start(n,a);const i=(s,o)=>{const c=Ff.get(s);c&&clearTimeout(c);const p=Math.max(2e3,e().config.notifications.editDebounceMs),d=setTimeout(()=>{Ff.delete(s);const u=e().config;u.notifications.taskEdits&&W2({title:"Task edited",body:`${o} changed on disk.`,config:u})},p);Ff.set(s,d)},r=async s=>{const{tasksDirHandle:o,config:c}=e();if(!o)return;let p,d;try{({frontmatter:p,body:d}=await Ms(o,s))}catch(x){console.warn(`[Watcher] notifyTaskChange: failed to read ${s}:`,x);return}const{subtasks:u,bodyWithoutSubtasks:f}=Os(d),h={id:s,frontmatter:{...p,id:p.id||s,status:p.status||"Backlog"},body:f,subtasks:u},v=R3(h),k=xu.get(s);if(!k){xu.set(s,v);return}c.notifications.statusChanges&&k.status!==v.status&&W2({title:"Task status changed",body:`${v.title}: ${k.status} → ${v.status}`,config:c});const w=zpe(k.subtasks,v.subtasks);c.notifications.subtaskCompletions&&w>0&&W2({title:"Subtask completed",body:w===1?`${v.title}: 1 subtask completed.`:`${v.title}: ${w} subtasks completed.`,config:c}),Hpe(k,v)&&i(s,v.title),xu.set(s,v)};jo.on("configChanged",()=>{try{e().loadConfig(),e().toast("Settings updated externally","info")}catch(s){console.error("[Watcher] configChanged handler error:",s)}}),jo.on("taskChanged",async s=>{try{const{drawerTaskId:o,drawerBaseVersion:c,tasksDirHandle:p}=e();if(await r(s),o===s&&c&&p){let d,u;try{({frontmatter:d,body:u}=await Ms(p,s))}catch(E){console.warn(`[Watcher] taskChanged: failed to re-read ${s}:`,E);return}const{subtasks:f,bodyWithoutSubtasks:h}=Os(u),v=c,k=JSON.stringify(v.frontmatter)!==JSON.stringify(d),w=v.body!==h,x=JSON.stringify(v.subtasks)!==JSON.stringify(f);if(!k&&!w&&!x)return;let $="none";k&&(w||x)?$="full":k?$="metadata-only":(w||x)&&($="body-only"),t({conflictState:{taskId:s,type:$,local:v,remote:{frontmatter:d,body:h,subtasks:f}},showConflictModal:$==="full"})}else await e().reloadBoard()}catch(o){console.error(`[Watcher] taskChanged handler error for ${s}:`,o)}}),jo.on("newTaskDetected",async s=>{try{const{tasksDirHandle:o}=e();if(o){let c,p;try{({frontmatter:c,body:p}=await Ms(o,s))}catch(f){console.warn(`[Watcher] newTaskDetected: failed to read ${s}:`,f),e().toast(`New task ${s} detected but could not be loaded`,"warning");return}const{subtasks:d,bodyWithoutSubtasks:u}=Os(p);xu.set(s,R3({id:s,frontmatter:{...c,id:c.id||s,status:c.status||"Backlog"},body:u,subtasks:d}))}await e().reloadBoard()}catch(o){console.error(`[Watcher] newTaskDetected handler error for ${s}:`,o)}}),jo.on("watcherError",s=>{t({watcherError:s}),e().toast(s,"warning",1e4)})},restartWatcher:()=>{const{dirHandle:n,tasksDirHandle:a}=e();!n||!a||(t({watcherError:null}),e().setupWatcher(),e().toast("File watcher restarted"))}}));Uy().then(t=>{re.setState({recentProjects:t})}).catch(t=>{console.warn("[Store] Failed to hydrate recent projects:",t)});ul(Ti);window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{ul(re.getState().config)});const Upe=Object.freeze(Object.defineProperty({__proto__:null,useStore:re},Symbol.toStringTag,{value:"Module"}));function qpe({icon:t,value:e,label:n,isActive:a,onClick:i,layoutId:r}){return b.jsxs("button",{type:"button",className:j1("relative flex size-8 cursor-default items-center justify-center rounded-full transition-all [&_svg]:size-4",a?"text-zinc-950 dark:text-zinc-50":"text-zinc-400 hover:text-zinc-950 dark:text-zinc-500 dark:hover:text-zinc-50"),role:"radio","aria-checked":a,"aria-label":`Switch to ${n} theme`,onClick:()=>i(e),children:[t,a&&b.jsx(Lt.div,{layoutId:r,transition:{type:"spring",bounce:.3,duration:.6},className:"absolute inset-0 rounded-full border border-zinc-200 dark:border-zinc-700"})]})}const Vpe=[{icon:b.jsx(Tce,{}),value:"auto",label:"system"},{icon:b.jsx(Oce,{}),value:"light",label:"light"},{icon:b.jsx(Mce,{}),value:"dark",label:"dark"}];function Zpe({value:t,onChange:e,className:n}){const a=re(d=>d.config.ui.theme),i=re(d=>d.updateConfig),r=`theme-option-${S.useId()}`,[s,o]=S.useState(!1);S.useEffect(()=>{o(!0)},[]);const c=t??a,p=e??(d=>{i(u=>({...u,ui:{...u.ui,theme:d}}))});return s?b.jsx(Lt.div,{initial:{opacity:0},animate:{opacity:1},transition:{duration:.3},className:j1("inline-flex items-center overflow-hidden rounded-full bg-white ring-1 ring-zinc-200 ring-inset dark:bg-zinc-950 dark:ring-zinc-700",n),role:"radiogroup","aria-label":"Theme mode",children:Vpe.map(d=>b.jsx(qpe,{icon:d.icon,value:d.value,label:d.label,isActive:c===d.value,onClick:p,layoutId:r},d.value))},String(s)):b.jsx("div",{className:j1("flex h-8 w-24",n)})}function Gpe(t){const e=boe(t,{stiffness:180,damping:22,mass:.8});return S.useEffect(()=>{e.set(t)},[t,e]),Xz(e,a=>Math.round(a).toString())}const O3="0.35.1",Lc=[.16,1,.3,1],Ka={fade:{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18,ease:Lc}},toast:{initial:{opacity:0,y:12,scale:.97},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:6,scale:.97},transition:{duration:.22,ease:Lc}},progressBar:t=>({initial:!1,animate:{width:`${t}%`},transition:{duration:.32,ease:Lc}}),heroStagger:t=>({initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.32,ease:Lc,delay:.05+t*.05}}),headerCrossfade:{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18,ease:Lc}},panel:{initial:{height:0,opacity:0},animate:{height:"auto",opacity:1},exit:{height:0,opacity:0},transition:{duration:.18,ease:Lc}},rotate:t=>({animate:{rotate:t?90:0},transition:{duration:.15,ease:Lc}}),chip:{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.9},transition:{duration:.15,ease:Lc}}};function TH({className:t="w-6 h-6"}){return b.jsxs("svg",{viewBox:"0 0 150 150",className:t,version:"1.1",xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",style:{fillRule:"evenodd",clipRule:"evenodd",strokeLinejoin:"round",strokeMiterlimit:2},children:[b.jsx("path",{d:"M148,21.594L148,128.406C148,139.22 139.22,148 128.406,148L21.594,148C10.78,148 2,139.22 2,128.406L2,21.594C2,10.78 10.78,2 21.594,2C139.22,2 148,10.78 148,21.594Z",style:{fill:"url(#_KandownLinear1)"}}),b.jsxs("g",{transform:"matrix(0.823551,0,0,0.823551,12.830775,11.282318)",children:[b.jsx("g",{transform:"matrix(1.620982,0,0,1.566239,-41.718998,-41.628205)",children:b.jsx("path",{d:"M56.491,62.601C57.2,61.897 57.602,60.925 57.606,59.908C57.627,53.936 57.7,33.2 57.7,33.2C57.6,29.7 55,27.6 52,27.6L42.075,27.6C38.544,27.6 35.673,30.547 35.644,34.201C35.528,48.996 35.327,83.484 35.956,83.013C35.956,83.013 52.072,66.994 56.491,62.601Z",style:{fill:"rgb(252,255,239)",fillRule:"nonzero"}})}),b.jsx("g",{transform:"matrix(1.566239,0,0,1.566239,-39.774573,-41.628205)",children:b.jsx("path",{d:"M87.6,43.8C84.2,43.9 80.5,45.1 77.7,47.5L39.2,86.2C37.1,88.3 35.8,91 35.7,93.7L35.7,116.574C35.7,117.219 36.088,117.802 36.683,118.051C37.278,118.3 37.965,118.167 38.425,117.714C50.467,105.842 98.836,58.16 110.608,46.555C111.047,46.122 111.185,45.468 110.956,44.894C110.728,44.321 110.178,43.94 109.561,43.928C106.663,43.871 103.089,43.8 103.089,43.8L87.6,43.8Z",style:{fill:"rgb(241,255,184)",fillRule:"nonzero"}})}),b.jsx("g",{transform:"matrix(0.766318,0.766329,-1.302872,1.302853,170.442469,-47.541879)",children:b.jsx("path",{d:"M38.038,101.45C35.808,101.45 34,100.387 34,99.075C34,95.326 34,88.102 34,84.58C34,84.042 34.364,83.525 35.011,83.145C35.658,82.764 36.536,82.55 37.452,82.55C46.372,82.55 69.5,82.55 69.5,82.55C69.5,82.55 69.5,77.52 69.5,74.389C69.5,73.947 69.936,73.545 70.617,73.359C71.298,73.173 72.101,73.236 72.675,73.521C80.028,77.17 98.075,86.125 104.279,89.204C104.832,89.479 105.168,89.876 105.206,90.301C105.245,90.727 104.982,91.143 104.481,91.45C98.972,94.832 83.072,104.591 75.013,109.539C74.195,110.041 72.946,110.206 71.841,109.959C70.737,109.712 69.99,109.101 69.946,108.406C69.744,105.262 69.5,101.45 69.5,101.45L38.038,101.45Z",style:{fill:"rgb(136,225,56)"}})})]}),b.jsx("defs",{children:b.jsxs("linearGradient",{id:"_KandownLinear1",x1:"0",y1:"0",x2:"1",y2:"0",gradientUnits:"userSpaceOnUse",gradientTransform:"matrix(62,131,-131,62,9,8)",children:[b.jsx("stop",{offset:"0",style:{stopColor:"rgb(12,29,23)",stopOpacity:1}}),b.jsx("stop",{offset:"1",style:{stopColor:"rgb(24,41,35)",stopOpacity:1}})]})})]})}function Wpe(){const{t}=xn(),e=re(ee=>ee.dirHandle),n=re(ee=>ee.isOpen),a=re(ee=>ee.projectName),i=re(ee=>ee.closeDrawer),r=re(ee=>ee.drawerTaskId),s=re(ee=>ee.saveDrawer),o=re(ee=>ee.archivedTasks.length),c=re(ee=>ee.showArchives),p=re(ee=>ee.setShowArchives),d=re(ee=>ee.columns),u=re(ee=>ee.openFolder),f=re(ee=>ee.reloadBoard),h=re(ee=>ee.createTask),v=re(ee=>ee.setCommandOpen),k=re(ee=>ee.viewMode),w=re(ee=>ee.setViewMode),x=re(ee=>ee.density),$=re(ee=>ee.setDensity),E=re(ee=>ee.setCurrentPage),P=re(ee=>ee.recentProjects),L=re(ee=>ee.openRecentProject),M=re(ee=>ee.filters),D=re(ee=>ee.setFilter),z=re(ee=>ee.clearFilters),I=re(ee=>ee.config.fields),j=re(ee=>ee.lastReloadError),G=re(ee=>ee.watcherError),J=re(ee=>ee.restartWatcher),[ne,U]=S.useState(!1),[F,B]=S.useState(!0),Y=S.useRef(null),X=S.useRef(null),oe=d.reduce((ee,K)=>ee+K.tasks.length,0),O=Gpe(oe),Z=[];I.priority&&M.priority&&Z.push({type:"priority",label:M.priority,value:M.priority}),I.tags&&M.tag&&Z.push({type:"tag",label:"#"+M.tag,value:M.tag}),I.assignee&&M.assignee&&Z.push({type:"assignee",label:"@"+M.assignee,value:M.assignee});const q=[{label:t("filterBar.ownerAll"),value:""},{label:t("filterBar.ownerHuman"),value:"human"},{label:t("filterBar.ownerAI"),value:"ai"}],R=Z.length>0||M.search||I.ownerType&&M.ownerType;return S.useEffect(()=>{if(!ne)return;const ee=K=>{Y.current&&!Y.current.contains(K.target)&&U(!1)};return document.addEventListener("mousedown",ee),()=>document.removeEventListener("mousedown",ee)},[ne]),S.useEffect(()=>{const ee=setTimeout(()=>B(!1),5e3);return()=>clearTimeout(ee)},[]),S.useEffect(()=>{document.title=a?`${a} · Kandown`:"Kandown"},[a]),b.jsxs(b.Fragment,{children:[(j||G)&&b.jsxs("div",{className:"flex items-center gap-2 px-5 py-1.5 bg-amber-500/10 border-b border-amber-500/30 text-[12px] text-amber-700 dark:text-amber-300",children:[b.jsx("span",{className:"flex-1 truncate",children:G?`⚠ ${G}`:`⚠ ${j}`}),G&&b.jsx("button",{type:"button",onClick:J,className:"px-2 py-0.5 rounded bg-amber-500/20 hover:bg-amber-500/30 text-[11.5px] font-medium",children:"Restart watcher"}),b.jsx("button",{type:"button",onClick:f,className:"px-2 py-0.5 rounded bg-amber-500/20 hover:bg-amber-500/30 text-[11.5px] font-medium",children:"Reload"})]}),b.jsxs("header",{className:"flex items-center justify-between px-5 h-[64px] border-b border-border bg-card/80 backdrop-blur-xl relative z-10",children:[b.jsxs("div",{className:"flex items-center gap-4 min-w-0",children:[b.jsxs("div",{className:"flex items-center gap-2.5 flex-shrink-0",children:[b.jsxs("button",{onClick:()=>{r?s():i({replace:!0})},className:"flex items-center gap-2 cursor-pointer",children:[b.jsx(TH,{className:"w-[34px] h-[34px] dark:text-white text-black"}),b.jsx(ya,{mode:"wait",initial:!1,children:F?b.jsxs(Lt.span,{...Ka.headerCrossfade,className:"flex items-center gap-2",children:[b.jsx("span",{className:"text-[15px] font-semibold tracking-tight text-fg",children:"kandown"}),b.jsxs("span",{className:"inline-flex items-center h-5 px-1.5 text-[10.5px] font-semibold text-red-600 bg-red-50 dark:text-red-400 dark:bg-red-500/15 rounded-md",children:["v",O3]})]},"boot"):a?b.jsx(Lt.span,{...Ka.headerCrossfade,className:"text-[15px] font-semibold tracking-tight text-fg truncate max-w-[240px]",children:a},"project"):null})]}),r&&b.jsxs("button",{type:"button",onClick:()=>{s()},className:"hidden md:inline-flex items-center gap-2 rounded-xl border border-border bg-bg px-3 py-2 text-[13px] font-semibold text-fg shadow-sm transition-colors hover:border-border-strong hover:bg-bg-2",title:t("taskWorkspace.backToCards"),children:[b.jsx(nn.ArrowLeft,{size:15}),b.jsx("span",{children:t("common.back")})]})]}),e&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"w-px h-[20px] bg-black/[0.08] dark:bg-white/[0.08] flex-shrink-0"}),b.jsxs("div",{className:"flex items-center gap-2 px-3 h-9 bg-secondary/60 border border-border rounded-xl min-w-[200px] max-w-[280px] focus-within:border-border-focus focus-within:bg-secondary transition-all",children:[b.jsx(nn.Search,{size:14,className:"text-fg-muted/60 flex-shrink-0"}),b.jsx("input",{ref:X,type:"text",placeholder:t("filterBar.searchPlaceholder"),value:M.search,onChange:ee=>D("search",ee.target.value),className:"bg-transparent border-none outline-none text-fg text-[13px] w-full placeholder:text-fg-muted/60"}),M.search?b.jsx("button",{onClick:()=>D("search",""),className:"text-fg-muted/60 hover:text-fg flex-shrink-0",children:b.jsx(nn.X,{size:14})}):b.jsx("kbd",{className:"inline-flex items-center h-5 px-1.5 text-[10px] font-medium text-fg-muted/50 bg-black/[0.04] dark:bg-white/[0.08] rounded border border-black/[0.06] dark:border-white/[0.1]",children:"⌘K"})]}),b.jsxs("div",{className:"flex items-center gap-1.5 flex-wrap overflow-hidden",children:[b.jsx(ya,{children:Z.map(ee=>b.jsxs(Lt.button,{...Ka.chip,onClick:()=>D(ee.type,null),className:"inline-flex items-center gap-1 h-6 px-2.5 text-[12px] text-fg bg-black/[0.05] dark:bg-white/[0.1] border border-black/[0.08] dark:border-white/[0.12] rounded-lg hover:bg-black/[0.08] dark:hover:bg-white/[0.15] transition-colors",children:[ee.label,b.jsx(nn.X,{size:10,className:"text-fg-muted/60"})]},ee.type+ee.value))}),I.ownerType&&b.jsx("div",{className:"flex items-center h-6 border border-black/[0.06] dark:border-white/[0.1] rounded-lg overflow-hidden",children:q.map(ee=>b.jsx("button",{onClick:()=>D("ownerType",ee.value),className:`h-full px-2.5 text-[12px] transition-colors ${M.ownerType===ee.value?"bg-black/[0.06] dark:bg-white/[0.12] text-fg":"text-fg-muted/70 hover:text-fg"}`,children:ee.label},ee.value))}),R&&b.jsx("button",{onClick:z,className:"text-[12px] text-fg-muted/60 hover:text-fg transition-colors",children:t("filterBar.clearAll")})]})]}),e&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"w-px h-[20px] bg-black/[0.08] dark:bg-white/[0.08] flex-shrink-0"}),b.jsxs("div",{className:"relative flex-shrink-0",ref:Y,children:[b.jsxs("button",{onClick:()=>U(ee=>!ee),className:"flex items-center gap-1.5 px-2.5 py-1.5 text-[13px] text-fg-muted hover:text-fg hover:bg-black/[0.04] dark:hover:bg-white/[0.06] rounded-lg transition-colors border border-transparent hover:border-black/[0.06] dark:hover:border-white/[0.1]",children:[b.jsx(nn.Folder,{size:13,className:"text-fg-muted/70"}),b.jsxs("span",{className:"font-medium",children:[".",e.name]}),b.jsx(nn.ChevronDown,{size:11,className:"opacity-50"})]}),b.jsx(ya,{children:ne&&b.jsx(Lt.div,{...Ka.fade,initial:{opacity:0,y:-4},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:-4},transition:{duration:.12,ease:Ka.fade.transition.ease},className:"absolute top-full left-0 mt-2 min-w-[240px] glass rounded-xl shadow-[0_16px_48px_rgba(0,0,0,0.5)] overflow-hidden z-50",children:b.jsxs("div",{className:"py-1.5",children:[P.length>0&&b.jsxs(b.Fragment,{children:[b.jsx("div",{className:"px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-fg-muted/60",children:t("header.recentProjects")}),P.map(ee=>b.jsxs("button",{onClick:()=>{U(!1),L(ee)},className:"w-full flex items-center gap-2 px-3 py-2 text-[13.5px] text-left hover:bg-black/[0.04] dark:hover:bg-white/[0.06] transition-colors",children:[b.jsx(nn.Folder,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{className:"truncate",children:ee.name}),ee.id===e.name&&b.jsx(nn.Check,{size:12,className:"ml-auto text-emerald-500"})]},ee.id)),b.jsx("div",{className:"h-px bg-black/[0.06] dark:bg-white/[0.08] my-1.5 mx-2"})]}),b.jsxs("button",{onClick:()=>{U(!1),u()},className:"w-full flex items-center gap-2 px-3 py-2 text-[13.5px] text-left hover:bg-black/[0.04] dark:hover:bg-white/[0.06] transition-colors",children:[b.jsx(nn.Plus,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{children:t("header.openFolder...")})]})]})})})]})]})]}),b.jsx("div",{className:"flex items-center gap-2 flex-shrink-0",children:n||e?b.jsxs(b.Fragment,{children:[b.jsxs("div",{className:"flex items-center gap-2 mr-2 text-[12.5px] text-fg-muted/70",children:[b.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full bg-emerald-500"}),b.jsx(Lt.span,{className:"tabular-nums font-medium transition-colors duration-200",children:O}),b.jsx("span",{children:t("header.tasks")})]}),b.jsxs("div",{className:"flex items-center bg-black/[0.04] dark:bg-white/[0.06] border border-black/[0.06] dark:border-white/[0.1] rounded-xl p-0.5 h-10",children:[b.jsx("button",{onClick:()=>w("board"),className:`w-9 h-9 inline-flex items-center justify-center rounded-lg transition-all ${k==="board"?"bg-card text-fg shadow-sm":"text-fg-muted/70 hover:text-fg"}`,title:t("common.board"),children:b.jsx(nn.LayoutBoard,{size:18})}),b.jsx("button",{onClick:()=>w("list"),className:`w-9 h-9 inline-flex items-center justify-center rounded-lg transition-all ${k==="list"?"bg-card text-fg shadow-sm":"text-fg-muted/70 hover:text-fg"}`,title:t("common.list"),children:b.jsx(nn.LayoutList,{size:18})})]}),b.jsx(an,{variant:"icon",icon:"Archive",onClick:()=>p(!c),title:c?t("header.backToBoard"):`${t("header.archives")} (${o})`,className:c?"text-accent":""}),b.jsx(an,{variant:"icon",icon:"Density",onClick:()=>$(x==="compact"?"comfortable":"compact"),title:`Density: ${x}`}),b.jsx(an,{variant:"icon",icon:"Settings",onClick:()=>E("settings"),title:t("common.settings")}),b.jsx(Zpe,{}),b.jsx("div",{className:"w-px h-5 bg-black/[0.08] dark:bg-white/[0.08] mx-1"}),b.jsx(an,{variant:"secondary",icon:"Search",label:t("common.search"),shortcut:"⌘K",onClick:()=>v(!0),title:"Command palette (⌘K)"}),b.jsx(an,{variant:"icon",icon:"Refresh",onClick:f,title:`${t("common.reload")} (R)`}),b.jsx(an,{variant:"primary",icon:"Plus",label:t("common.newTask"),shortcut:"N",onClick:()=>h()})]}):b.jsx(an,{variant:"primary",label:t("common.openFolder"),onClick:u})})]})]})}/**
|
|
219
219
|
* @license @tabler/icons-react v3.41.1 - MIT
|
|
220
220
|
*
|
|
221
221
|
* This source code is licensed under the MIT license.
|