kandown 0.33.0 → 0.33.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 +5 -0
- package/bin/kandown.js +24 -10
- package/dist/index.html +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.33.1 — 2026-07-21 — "Instant TUI & Browser Launcher Fix"
|
|
4
|
+
|
|
5
|
+
- **Fixed**: **CLI Default Command Execution (`kandown`)** — fixed `bin/tui.js` path resolution in global installation so running `kandown` with no arguments instantly opens both the browser AND the interactive terminal board UI (TUI), eliminating the fallback message `Open kandown.html in browser`.
|
|
6
|
+
- **Fixed**: **Automatic Browser Launch** — `kandown` now automatically invokes `open` (macOS), `xdg-open` (Linux), or `start` (Windows) on launch unless `--no-open` is specified.
|
|
7
|
+
|
|
3
8
|
## 0.33.0 — 2026-07-21 — "Universal Auto-Updater & Web UI Prompt Engine"
|
|
4
9
|
|
|
5
10
|
- **Added**: **Daemon HTTP Server Module (`src/cli/lib/server.ts`)** — re-introduced and modernized full REST API server & SSE live-reload for daemon mode (`/api/daemon`, `/api/board`, `/api/config`, `/api/tasks`, `/api/update/check`, `/api/update/apply`).
|
package/bin/kandown.js
CHANGED
|
@@ -12,9 +12,10 @@ import { spawn, execSync } from "child_process";
|
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
|
|
14
14
|
// src/lib/version.ts
|
|
15
|
-
var KANDOWN_VERSION = "0.33.
|
|
15
|
+
var KANDOWN_VERSION = "0.33.1";
|
|
16
16
|
|
|
17
17
|
// src/cli/lib/updater.ts
|
|
18
|
+
var PKG_ROOT = resolve(import.meta.url ? new URL("../../..", import.meta.url).pathname : process.cwd());
|
|
18
19
|
var CACHE_DIR = join(homedir(), ".kandown");
|
|
19
20
|
var UPDATE_CHECK_CACHE = join(CACHE_DIR, ".update-check.json");
|
|
20
21
|
var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
@@ -547,11 +548,11 @@ function readTask(kandownDir, taskId) {
|
|
|
547
548
|
}
|
|
548
549
|
};
|
|
549
550
|
}
|
|
550
|
-
var
|
|
551
|
+
var PKG_ROOT2 = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
551
552
|
function readAgentDoc(kandownDir) {
|
|
552
553
|
const sections = [];
|
|
553
554
|
try {
|
|
554
|
-
sections.push(readFileSync3(join3(
|
|
555
|
+
sections.push(readFileSync3(join3(PKG_ROOT2, "templates", "AGENT_KANDOWN.md"), "utf8").trim());
|
|
555
556
|
} catch (e) {
|
|
556
557
|
console.warn("[kandown] Could not read base agent rules:", e.message);
|
|
557
558
|
}
|
|
@@ -1089,6 +1090,13 @@ function success(msg) {
|
|
|
1089
1090
|
function err(msg) {
|
|
1090
1091
|
console.error(`${c.red}\u2717${c.reset} ${msg}`);
|
|
1091
1092
|
}
|
|
1093
|
+
function openBrowser(target) {
|
|
1094
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1095
|
+
try {
|
|
1096
|
+
spawn4(cmd, [target], { detached: true, stdio: "ignore" }).unref();
|
|
1097
|
+
} catch {
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1092
1100
|
function parseArgs(args) {
|
|
1093
1101
|
const flags = {};
|
|
1094
1102
|
const positional = [];
|
|
@@ -1137,7 +1145,7 @@ ${c.bold}USAGE:${c.reset}
|
|
|
1137
1145
|
kandown [command] [options]
|
|
1138
1146
|
|
|
1139
1147
|
${c.bold}COMMANDS:${c.reset}
|
|
1140
|
-
(none) Start web server & launch TUI
|
|
1148
|
+
(none) Start web server, open browser & launch TUI
|
|
1141
1149
|
work Output agent rules + live board digest
|
|
1142
1150
|
list List tasks (alias: ls)
|
|
1143
1151
|
show <id> Display task details
|
|
@@ -1200,7 +1208,7 @@ async function cmdUpdate(rawArgs) {
|
|
|
1200
1208
|
const kandownDir = resolve3(cwd, args.path);
|
|
1201
1209
|
const htmlDest = join6(kandownDir, "kandown.html");
|
|
1202
1210
|
if (existsSync6(htmlDest)) {
|
|
1203
|
-
const htmlSrc = resolve3(
|
|
1211
|
+
const htmlSrc = resolve3(PKG_ROOT, "dist", "index.html");
|
|
1204
1212
|
if (existsSync6(htmlSrc)) {
|
|
1205
1213
|
copyFileSync2(htmlSrc, htmlDest);
|
|
1206
1214
|
success(`Refreshed ${args.path}/kandown.html`);
|
|
@@ -1373,17 +1381,23 @@ async function main() {
|
|
|
1373
1381
|
break;
|
|
1374
1382
|
}
|
|
1375
1383
|
case void 0: {
|
|
1384
|
+
const parsed = parseArgs(rest);
|
|
1376
1385
|
const { kandownDir } = ensureKandownDir(rest);
|
|
1377
|
-
|
|
1386
|
+
let status = await getDaemonStatus(kandownDir);
|
|
1378
1387
|
if (!status.running) {
|
|
1379
|
-
await startProjectDaemon(kandownDir);
|
|
1388
|
+
status = await startProjectDaemon(kandownDir);
|
|
1389
|
+
}
|
|
1390
|
+
if (!parsed.flags["no-open"]) {
|
|
1391
|
+
const urlToOpen = status.metadata?.url || join6(kandownDir, "kandown.html");
|
|
1392
|
+
openBrowser(urlToOpen);
|
|
1380
1393
|
}
|
|
1381
|
-
const tuiPath =
|
|
1394
|
+
const tuiPath = join6(PKG_ROOT, "bin", "tui.js");
|
|
1382
1395
|
if (existsSync6(tuiPath)) {
|
|
1383
|
-
const child = spawn4(
|
|
1396
|
+
const child = spawn4(process.execPath, [tuiPath, ...rest], { stdio: "inherit" });
|
|
1384
1397
|
child.on("close", (code) => process.exit(code || 0));
|
|
1385
1398
|
} else {
|
|
1386
|
-
|
|
1399
|
+
err(`TUI binary not found at ${tuiPath}`);
|
|
1400
|
+
process.exit(1);
|
|
1387
1401
|
}
|
|
1388
1402
|
break;
|
|
1389
1403
|
}
|
package/dist/index.html
CHANGED
|
@@ -201,7 +201,7 @@ Error generating stack: `+_.message+`
|
|
|
201
201
|
|
|
202
202
|
## Subtasks
|
|
203
203
|
|
|
204
|
-
`}}async function bH(t,e){try{return await(await(await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}async function ope(t,e){try{return await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`),!0}catch{return!1}}async function vH(t,e){try{return await t.getDirectoryHandle("archive",{create:e})}catch{return null}}async function cpe(t){if(Lt())return fS();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 Ps(t,e){if(Lt())try{const i=await gS(e);return Fg(i)}catch{return FL(e)}const a=await(async i=>{try{return await(await(await i.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}})(t)??await bH(t,e);return a!==null?Fg(a):FL(e)}async function ppe(t,e){if(Lt())try{const a=await gS(e);return{ok:!0,task:Fg(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 bH(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:Fg(n)}}catch(a){return{ok:!1,reason:"corrupted",error:a}}}async function pu(t,e,n,a){const i=dS(n,a);if(Lt())return Xce(e,i);try{const o=await(await(await ope(t,e)?await vH(t,!0):t).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}}catch(r){throw Lh(r,`${e}.md`)}}async function zL(t,e){if(Lt())return Qce(e);try{await t.removeEntry(`${e}.md`)}catch{}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}async function lpe(t,e){await gi(`/api/tasks/${encodeURIComponent(t)}/archive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function dpe(t,e){await gi(`/api/tasks/${encodeURIComponent(t)}/unarchive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function upe(t,e,n,a){const i=dS(n,a);if(Lt())return lpe(e,i);try{const o=await(await(await vH(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 Lh(r,`archive/${e}.md`)}}async function mpe(t,e,n,a){const i=dS(n,a);if(Lt())return dpe(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 Lh(r,`${e}.md`)}}const fpe="kanban-md",gpe=1,sp="recentProjects";function hS(){return new Promise((t,e)=>{const n=indexedDB.open(fpe,gpe);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result),n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains(sp)||a.createObjectStore(sp,{keyPath:"id"})}})}async function H2(t){const e=await hS();return new Promise((n,a)=>{const i=e.transaction(sp,"readwrite");i.objectStore(sp).put(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function Fy(){const t=await hS();return new Promise((e,n)=>{const i=t.transaction(sp,"readonly").objectStore(sp).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 hpe(t){const e=await hS();return new Promise((n,a)=>{const i=e.transaction(sp,"readwrite");i.objectStore(sp).delete(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function HL(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 bpe(){try{return await(await gi("/api/update/check")).json()}catch{return null}}async function yH(){try{return await(await gi("/api/update/apply",{method:"POST"})).json()}catch{return null}}function _H(t=Ei){const e=t.board.columns;return e[e.length-1]??"Done"}function vpe(t,e=Ei){return t===_H(e)||t.toLowerCase()==="archived"}class ype{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,Lt()&&this.startServerSse(),e&&n&&(this.initHashes(),this.intervalId=setInterval(()=>void this.tick(),300))}startServerSse(){if(typeof window>"u"||!Lt()||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 BL(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 BL(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 UL(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 UL(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 BL(t){try{return await(await(await t.getFileHandle("kandown.json")).getFile()).text()}catch{return null}}async function UL(t,e){try{return await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}const Lo=new ype,_pe={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 qL=null;function kH(){return"Notification"in window?Notification.permission:"unsupported"}async function kpe(){return"Notification"in window?await Notification.requestPermission():"unsupported"}function B2({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&&wpe(n.notifications.soundId),!(!n.notifications.browser||kH()!=="granted"))try{new Notification(t,{body:e})}catch{}}function wpe(t){const e=_pe[t],n=window.AudioContext??window.webkitAudioContext;if(!(!n||e.length===0))try{qL??=new n;const a=qL;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 jf(t,e={}){const{maxAttempts:n=3,baseDelayMs:a=500,retryableCheck:i=Zce}=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 xpe(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 Ape(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=xpe(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 Cpe=/^[A-Za-z0-9_-]+$/;function U2(t){if(!t)return null;const e=t.trim().replace(/^\/+|\/+$/g,"").replace(/^#/,"");return!e||e.includes("/")||e.includes(".")||!Cpe.test(e)?null:/^\d+$/.test(e)?`t${e}`:e}function Npe(t){const e=new URLSearchParams(t.search).get("p");if(!e)return null;const[n]=e.split("/").filter(Boolean);return n||null}function zy(t){const e=new URLSearchParams(t.search),n=U2(e.get("task"));if(n)return n;const a=e.get("p");if(a){const[,...r]=a.split("/").filter(Boolean),s=U2(r.join("/"));if(s)return s}return U2(decodeURIComponent(t.pathname))}function T3(t){return t?`/?p=${encodeURIComponent(t)}`:"/"}function bS(t,e){const n=t.replace(/^t(?=\d+$)/,""),a=`/${encodeURIComponent(n)}`;return e?`${a}?p=${encodeURIComponent(e)}`:a}function Hy(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 Iv(t){typeof window<"u"&&zy(window.location)||Hy(T3(t))}function Spe(t){let e=-1;for(const n of t)for(const a of n.tasks){const i=a.id.match(/^t(\d+)$/);if(i){const r=parseInt(i[1],10);r>e&&(e=r)}}return"t"+(e+1)}async function $pe(){const t=await fS();return await Promise.all(t.map(async n=>{const{frontmatter:a,body:i}=await hH(n),r={...a,id:a.id||n,status:a.status||"Backlog"},{subtasks:s,bodyWithoutSubtasks:o}=Rs(i);return{id:n,frontmatter:r,body:o,subtasks:s}}))}async function Epe(t){const e=await cpe(t),n=await Promise.all(e.map(async r=>{const s=await ppe(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}=Rs(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 VL(t,e,n){const a=[];for(const s of e){const o=s.name;s.tasks.forEach((c,p)=>{const d=(async()=>{const{frontmatter:m,body:f}=await Ps(t,c.id);await pu(t,c.id,{...m,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 pl(t){mH(t.ui.theme,t.ui.skin,t.ui.font,t.ui.background)}function P3(t){return{title:t.frontmatter.title||t.id,status:t.frontmatter.status||"Backlog",body:t.body,subtasks:t.subtasks}}function q2(t){yu.clear(),t.forEach(e=>{yu.set(e.id,P3(e))})}function Tpe(t){const e=t.split(/[\\/]+/).filter(Boolean),n=e[e.length-1];return n===".kandown"?e[e.length-2]??"Project":n??"Project"}function Ppe(t,e){return e.reduce((n,a,i)=>{const r=t[i]?.done??!1;return n+(a.done&&!r?1:0)},0)}function Mpe(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 Lpe=0;const yu=new Map,Df=new Map;let V2=null;const se=Lce((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:Ei,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()=>{const{selectedTaskIds:n,deleteTask:a}=e();for(const i of n)await a(i);t({selectedTaskIds:[]})},drawerBaseVersion:null,conflictState:null,showConflictModal:!1,openFolder:async()=>{if(!fH()){const c=navigator.userAgent||"this browser";e().toast(new Vce(c).message,"error",8e3);return}let n;try{n=await npe()}catch(c){c instanceof mS?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}),Iv(s);const o=Lt()?z2():null;try{await H2({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 Fy();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 HL(n.handle,!0)){let r=!1;try{await Oy(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 hpe(n.id);const s=await Fy();t({recentProjects:s})}catch{}return}e().toast("Permission denied — please grant access to the folder","error");return}try{const r=await Oy(n.handle),s=await E3(n.handle),o=n.handle.name;t({dirHandle:r,tasksDirHandle:s,projectName:o}),Iv(o);try{await H2({...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=z2();if(!n)throw new Error("No server root");await OL();const a=Tpe(n),i=await gH();pl(i);const r=await fS(),s=await Promise.all(r.map(async f=>{const{frontmatter:h,body:v}=await hH(f),k={...h,id:h.id||f,status:h.status||"Backlog"},{subtasks:w,bodyWithoutSubtasks:A}=Rs(v);return{id:f,frontmatter:k,body:A,subtasks:w}}));q2(s);const o=s.map(f=>({frontmatter:f.frontmatter,body:Wd(f.body,f.subtasks)})),c=R2(o,i.board.columns),p=O2(o),d=c.reduce((f,h)=>f+h.tasks.length,0),m=new Map;if(d<=10)for(const f of s)m.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:m,searchMatches:new Map}),Iv(a),e().setupWatcher(),e().refreshAgentHook()}catch{t({loading:!1,isOpen:!1}),e().toast("Impossible de charger le projet. Relancez `kandown`.","error")}},tryAutoOpenServerProject:async()=>{if(!Lt())return;const n=z2();if(!n)return;await OL();const a=await Fy(),i=a.find(p=>p.kandownDir===n);if(!i){await e().openServerProject();return}if(!await HL(i.handle,!0)){await e().openServerProject();return}const s=await Oy(i.handle),o=await E3(i.handle),c=i.handle.name;t({dirHandle:s,tasksDirHandle:o,projectName:c,recentProjects:a,isOpen:!0}),Iv(c),await H2({...i,lastOpened:Date.now()}),await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()},loadConfig:async()=>{const{dirHandle:n}=e();if(!(!n&&!Lt()))try{const a=await ape(n);if(a.ok){t({config:a.config}),pl(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:Ei}),pl(Ei)}catch{t({config:Ei}),pl(Ei)}},updateConfig:async n=>{const{dirHandle:a,config:i}=e();if(!a&&!Lt())return;const r=n(i);t({config:r}),pl(r);try{await ipe(a,r)}catch(s){const o=s;o instanceof To?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(Lt()){const i=await $pe();q2(i);const r=i.map(d=>({frontmatter:d.frontmatter,body:Wd(d.body,d.subtasks)})),s=R2(r,a.board.columns),o=O2(r);t({boardTitle:"Project Kanban",columns:s,archivedTasks:o});const c=s.reduce((d,m)=>d+m.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 Epe(n);q2(i);const s=i.map(m=>({frontmatter:m.frontmatter,body:Wd(m.body,m.subtasks)})),o=R2(s,a.board.columns),c=O2(s);t({boardTitle:"Project Kanban",columns:o,archivedTasks:c});const p=o.reduce((m,f)=>m+f.tasks.length,0),d=new Map;if(p<=10)for(const m of i)d.set(m.frontmatter.id,{frontmatter:m.frontmatter,subtasks:m.subtasks,body:m.body});if(r.length>0){const m=r.length===1?`Task ${r[0]} could not be loaded`:`${r.length} tasks could not be loaded`;e().toast(m,"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=Lt();if(!d&&!e().tasksDirHandle)return;const m=s.find(T=>T.name===a),f=s.find(T=>T.name===i);if(!m||!f)return;const h=m.tasks.findIndex(T=>T.id===n);if(h===-1)return;const v=m.tasks[h];if(!v)return;if(vpe(i,o)){const T=new Map,M=_H(o).toLowerCase();for(const D of s)for(const I of D.tasks){const H=I.frontmatter&&(I.frontmatter.archived===!0||I.frontmatter.archived==="true");T.set(I.id,{exists:!0,resolved:H||I.id===n||D.name.toLowerCase()===M})}const j=[];for(const D of v.dependsOn){if(typeof D!="string"||!D.trim()||D===n)continue;const I=T.get(D);(!I||!I.resolved)&&j.push(D)}if(j.length>0){const D=j.length===1?j[0]:`${j.slice(0,-1).join(", ")} and ${j[j.length-1]}`;e().toast(`Cannot move ${n} to ${i}: blocked by ${D}`,"error");return}}const k=s.map(T=>({...T,tasks:[...T.tasks]})),w=k.find(T=>T.name===a),A=k.find(T=>T.name===i),[$]=w.tasks.splice(h,1);/done|termin|closed|complet/i.test(i)?$.checked=!0:$.checked=!1,r!==void 0?A.tasks.splice(r,0,$):A.tasks.push($),t({columns:k});try{const{tasksDirHandle:T}=e();if(!T&&!d)return;const M=a===i?k.filter(D=>D.name===i):k.filter(D=>D.name===a||D.name===i),{failedIds:j}=await jf(()=>VL(T??null,M,o.board.columns),{maxAttempts:3});if(j.length>0){const D=j.length===1?`Could not save move for ${j[0]}`:`${j.length} tasks could not be moved`;e().toast(D,"warning",8e3),await e().reloadBoard()}}catch(T){const M=T;M instanceof To?e().toast("Disk is full — move was not saved. Free up space and try again.","error",8e3):e().toast("Failed to save: "+M.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&&!Lt())return;const d=r.map(h=>({...h,tasks:[...h.tasks]})),m=d.find(h=>h.name===n);if(!m)return;const[f]=m.tasks.splice(a,1);m.tasks.splice(i,0,f),t({columns:d});try{const{tasksDirHandle:h}=e(),v=Lt();if(!h&&!v)return;const{failedIds:k}=await jf(()=>VL(h??null,[m],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 To?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(m=>m.name===n);if(d){const f=(await Promise.allSettled(d.tasks.map(async(h,v)=>{const{frontmatter:k,body:w}=await Ps(s,h.id);await pu(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(m=>{const f={...m.board.columnColors??{}},h=f[n.toLowerCase()];h&&(f[i.toLowerCase()]=h,delete f[n.toLowerCase()]);const v=m.board.columns.some(k=>k.toLowerCase()===n.toLowerCase())?m.board.columns:[...m.board.columns,n];return{...m,board:{...m.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&&!Lt())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&&!Lt())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=>zL(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(m=>m.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}=e();if(!r&&!Lt()||!i.length)return null;const p=n||s.board.columns[0]||i[0].name,d=Spe(i),m=i.find($=>$.name===p)?.tasks.length??0,f=a?Ape(a):null,h={id:d,title:f?.title||"",checked:!1,dependsOn:f?.depends_on||[],tags:f?.tags||[],assignee:f?.assignee||null,priority:f?.priority||(s.fields.priority?s.board.defaultPriority:null),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",progress:null,frontmatter:{}},v=i.map($=>$.name===p?{...$,tasks:[...$.tasks,h]}:$),k=new Map(o),w={id:d,title:f?.title||"",status:p,order:m,priority:f?.priority||(s.fields.priority?s.board.defaultPriority:""),tags:f?.tags||[],assignee:f?.assignee||"",due:f?.due||"",depends_on:f?.depends_on||[],created:new Date().toISOString().slice(0,10),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",tools:""},A="";k.set(d,{frontmatter:w,subtasks:[],body:A}),t({columns:v,taskContents:k});try{const $=r||null;return await jf(()=>pu($,d,w,A),{maxAttempts:3}),e().toast(`Created ${d.replace(/^t/,"")}`),await e().openDrawer(d),d}catch($){const T=$;return T instanceof To?e().toast("Disk is full — task was not created.","error",8e3):e().toast("Failed to create: "+T.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&&!Lt())return;const o=a.map(d=>({...d,tasks:d.tasks.filter(m=>m.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 zL(i||null,n),e().toast("Deleted")}catch(d){const m=d;e().toast("Failed to delete: "+m.message,"error"),t({columns:a,taskContents:r,searchMatches:s})}},archiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Lt()))try{const{frontmatter:i,body:r}=await Ps(a||null,n);await upe(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 To?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&&!Lt()))try{const{frontmatter:i,body:r}=await Ps(a||null,n),s={...i};delete s.archived,await mpe(a||null,n,s,r),await e().reloadBoard(),e().toast("Restored")}catch(i){const r=i;r instanceof To?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&&!Lt()))try{const{frontmatter:s,body:o}=await Ps(i,n),{subtasks:c,bodyWithoutSubtasks:p}=Rs(o),d={frontmatter:s,subtasks:c,body:p,savedAt:Date.now()},m=e().drawerRecoveryData.get(n),f=m?{frontmatter:m.frontmatter,subtasks:m.subtasks,body:m.body}:{frontmatter:s,subtasks:c,body:p},h=new Map(e().drawerRecoveryData);h.delete(n),a.syncUrl!==!1&&Hy(bS(n,r),a.replace),t({drawerTaskId:n,drawerData:f,drawerBaseVersion:d,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!!m,lastSaveError:null,drawerRecoveryData:h}),m&&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&&Hy(T3(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=Wd(a.body,a.subtasks),o={...a.frontmatter,id:n};try{await jf(()=>pu(i||null,n,o,s),{maxAttempts:3}),e().toast("Saved");const c=new Map(e().drawerRecoveryData);c.delete(n),Hy(T3(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 To?"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=Wd(a.body,a.subtasks),o={...a.frontmatter,id:n};await jf(()=>pu(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 To?"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(!Lt()){t({agentHook:null});return}const n=await Jce();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 epe(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 Ps(a,r),{subtasks:c,bodyWithoutSubtasks:p}=Rs(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=lH(o,r);c.length>0&&i.set(s,c)}t({searchMatches:i})},toast:(n,a="success",i)=>{const r=++Lpe,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 Ps(r,s),{subtasks:d,bodyWithoutSubtasks:m}=Rs(p);t({drawerData:{frontmatter:c,subtasks:d,body:m},drawerBaseVersion:{frontmatter:c,subtasks:d,body:m,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Reloaded from disk")}else if(n==="overwrite"){if(i&&s&&o){const c=Wd(i.body,i.subtasks),p={...i.frontmatter,id:s};try{await pu(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(Lt()){V2&&clearInterval(V2),V2=setInterval(()=>{e().reloadBoard()},2e3);return}const{dirHandle:n,tasksDirHandle:a}=e();if(!n||!a)return;Lo.stop(),Df.forEach(s=>clearTimeout(s)),Df.clear(),Lo.start(n,a);const i=(s,o)=>{const c=Df.get(s);c&&clearTimeout(c);const p=Math.max(2e3,e().config.notifications.editDebounceMs),d=setTimeout(()=>{Df.delete(s);const m=e().config;m.notifications.taskEdits&&B2({title:"Task edited",body:`${o} changed on disk.`,config:m})},p);Df.set(s,d)},r=async s=>{const{tasksDirHandle:o,config:c}=e();if(!o)return;let p,d;try{({frontmatter:p,body:d}=await Ps(o,s))}catch(A){console.warn(`[Watcher] notifyTaskChange: failed to read ${s}:`,A);return}const{subtasks:m,bodyWithoutSubtasks:f}=Rs(d),h={id:s,frontmatter:{...p,id:p.id||s,status:p.status||"Backlog"},body:f,subtasks:m},v=P3(h),k=yu.get(s);if(!k){yu.set(s,v);return}c.notifications.statusChanges&&k.status!==v.status&&B2({title:"Task status changed",body:`${v.title}: ${k.status} → ${v.status}`,config:c});const w=Ppe(k.subtasks,v.subtasks);c.notifications.subtaskCompletions&&w>0&&B2({title:"Subtask completed",body:w===1?`${v.title}: 1 subtask completed.`:`${v.title}: ${w} subtasks completed.`,config:c}),Mpe(k,v)&&i(s,v.title),yu.set(s,v)};Lo.on("configChanged",()=>{try{e().loadConfig(),e().toast("Settings updated externally","info")}catch(s){console.error("[Watcher] configChanged handler error:",s)}}),Lo.on("taskChanged",async s=>{try{const{drawerTaskId:o,drawerBaseVersion:c,tasksDirHandle:p}=e();if(await r(s),o===s&&c&&p){let d,m;try{({frontmatter:d,body:m}=await Ps(p,s))}catch(T){console.warn(`[Watcher] taskChanged: failed to re-read ${s}:`,T);return}const{subtasks:f,bodyWithoutSubtasks:h}=Rs(m),v=c,k=JSON.stringify(v.frontmatter)!==JSON.stringify(d),w=v.body!==h,A=JSON.stringify(v.subtasks)!==JSON.stringify(f);if(!k&&!w&&!A)return;let $="none";k&&(w||A)?$="full":k?$="metadata-only":(w||A)&&($="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)}}),Lo.on("newTaskDetected",async s=>{try{const{tasksDirHandle:o}=e();if(o){let c,p;try{({frontmatter:c,body:p}=await Ps(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:m}=Rs(p);yu.set(s,P3({id:s,frontmatter:{...c,id:c.id||s,status:c.status||"Backlog"},body:m,subtasks:d}))}await e().reloadBoard()}catch(o){console.error(`[Watcher] newTaskDetected handler error for ${s}:`,o)}}),Lo.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"))}}));Fy().then(t=>{se.setState({recentProjects:t})}).catch(t=>{console.warn("[Store] Failed to hydrate recent projects:",t)});pl(Ei);window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{pl(se.getState().config)});const jpe=Object.freeze(Object.defineProperty({__proto__:null,useStore:se},Symbol.toStringTag,{value:"Module"}));function Dpe({icon:t,value:e,label:n,isActive:a,onClick:i,layoutId:r}){return b.jsxs("button",{type:"button",className:T1("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(nt.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 Ipe=[{icon:b.jsx(yce,{}),value:"auto",label:"system"},{icon:b.jsx(Sce,{}),value:"light",label:"light"},{icon:b.jsx(kce,{}),value:"dark",label:"dark"}];function Rpe({value:t,onChange:e,className:n}){const a=se(d=>d.config.ui.theme),i=se(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(m=>({...m,ui:{...m.ui,theme:d}}))});return s?b.jsx(nt.div,{initial:{opacity:0},animate:{opacity:1},transition:{duration:.3},className:T1("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:Ipe.map(d=>b.jsx(Dpe,{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:T1("flex h-8 w-24",n)})}function Ope(t){const e=soe(t,{stiffness:180,damping:22,mass:.8});return S.useEffect(()=>{e.set(t)},[t,e]),Uz(e,a=>Math.round(a).toString())}const M3="0.33.0";function wH({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 Fpe(){const{t}=Tn(),e=se(B=>B.dirHandle),n=se(B=>B.isOpen),a=se(B=>B.projectName),i=se(B=>B.closeDrawer),r=se(B=>B.drawerTaskId),s=se(B=>B.saveDrawer),o=se(B=>B.archivedTasks.length),c=se(B=>B.showArchives),p=se(B=>B.setShowArchives),d=se(B=>B.columns),m=se(B=>B.openFolder),f=se(B=>B.reloadBoard),h=se(B=>B.createTask),v=se(B=>B.setCommandOpen),k=se(B=>B.viewMode),w=se(B=>B.setViewMode),A=se(B=>B.density),$=se(B=>B.setDensity),T=se(B=>B.setCurrentPage),M=se(B=>B.recentProjects),j=se(B=>B.openRecentProject),D=se(B=>B.filters),I=se(B=>B.setFilter),H=se(B=>B.clearFilters),R=se(B=>B.config.fields),L=se(B=>B.lastReloadError),G=se(B=>B.watcherError),Y=se(B=>B.restartWatcher),[ne,U]=S.useState(!1),[F,V]=S.useState(!0),Q=S.useRef(null),J=S.useRef(null),oe=d.reduce((B,ae)=>B+ae.tasks.length,0),O=Ope(oe),Z=[];R.priority&&D.priority&&Z.push({type:"priority",label:D.priority,value:D.priority}),R.tags&&D.tag&&Z.push({type:"tag",label:"#"+D.tag,value:D.tag}),R.assignee&&D.assignee&&Z.push({type:"assignee",label:"@"+D.assignee,value:D.assignee});const K=[{label:t("filterBar.ownerAll"),value:""},{label:t("filterBar.ownerHuman"),value:"human"},{label:t("filterBar.ownerAI"),value:"ai"}],E=Z.length>0||D.search||R.ownerType&&D.ownerType;return S.useEffect(()=>{if(!ne)return;const B=ae=>{Q.current&&!Q.current.contains(ae.target)&&U(!1)};return document.addEventListener("mousedown",B),()=>document.removeEventListener("mousedown",B)},[ne]),S.useEffect(()=>{const B=setTimeout(()=>V(!1),5e3);return()=>clearTimeout(B)},[]),S.useEffect(()=>{document.title=a?`${a} · Kandown`:"Kandown"},[a]),b.jsxs(b.Fragment,{children:[(L||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}`:`⚠ ${L}`}),G&&b.jsx("button",{type:"button",onClick:Y,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(wH,{className:"w-[34px] h-[34px] dark:text-white text-black"}),b.jsx(Wa,{mode:"wait",initial:!1,children:F?b.jsxs(nt.span,{className:"flex items-center gap-2",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.45},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",M3]})]},"boot"):a?b.jsx(nt.span,{className:"text-[15px] font-semibold tracking-tight text-fg truncate max-w-[240px]",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.45},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(Wn.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(Wn.Search,{size:14,className:"text-fg-muted/60 flex-shrink-0"}),b.jsx("input",{ref:J,type:"text",placeholder:t("filterBar.searchPlaceholder"),value:D.search,onChange:B=>I("search",B.target.value),className:"bg-transparent border-none outline-none text-fg text-[13px] w-full placeholder:text-fg-muted/60"}),D.search?b.jsx("button",{onClick:()=>I("search",""),className:"text-fg-muted/60 hover:text-fg flex-shrink-0",children:b.jsx(Wn.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(Wa,{children:Z.map(B=>b.jsxs(nt.button,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.9},transition:{duration:.15},onClick:()=>I(B.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:[B.label,b.jsx(Wn.X,{size:10,className:"text-fg-muted/60"})]},B.type+B.value))}),R.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:K.map(B=>b.jsx("button",{onClick:()=>I("ownerType",B.value),className:`h-full px-2.5 text-[12px] transition-colors ${D.ownerType===B.value?"bg-black/[0.06] dark:bg-white/[0.12] text-fg":"text-fg-muted/70 hover:text-fg"}`,children:B.label},B.value))}),E&&b.jsx("button",{onClick:H,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:Q,children:[b.jsxs("button",{onClick:()=>U(B=>!B),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(Wn.Folder,{size:13,className:"text-fg-muted/70"}),b.jsxs("span",{className:"font-medium",children:[".",e.name]}),b.jsx(Wn.ChevronDown,{size:11,className:"opacity-50"})]}),b.jsx(Wa,{children:ne&&b.jsx(nt.div,{initial:{opacity:0,y:-4,scale:.98},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:-4,scale:.98},transition:{duration:.12},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:[M.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")}),M.map(B=>b.jsxs("button",{onClick:()=>{U(!1),j(B)},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(Wn.Folder,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{className:"truncate",children:B.name}),B.id===e.name&&b.jsx(Wn.Check,{size:12,className:"ml-auto text-emerald-500"})]},B.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),m()},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(Wn.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(nt.span,{className:"tabular-nums font-medium",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(Wn.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(Wn.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:()=>$(A==="compact"?"comfortable":"compact"),title:`Density: ${A}`}),b.jsx(an,{variant:"icon",icon:"Settings",onClick:()=>T("settings"),title:t("common.settings")}),b.jsx(Rpe,{}),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:m})})]})]})}/**
|
|
204
|
+
`}}async function bH(t,e){try{return await(await(await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}async function ope(t,e){try{return await(await t.getDirectoryHandle("archive",{create:!1})).getFileHandle(`${e}.md`),!0}catch{return!1}}async function vH(t,e){try{return await t.getDirectoryHandle("archive",{create:e})}catch{return null}}async function cpe(t){if(Lt())return fS();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 Ps(t,e){if(Lt())try{const i=await gS(e);return Fg(i)}catch{return FL(e)}const a=await(async i=>{try{return await(await(await i.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}})(t)??await bH(t,e);return a!==null?Fg(a):FL(e)}async function ppe(t,e){if(Lt())try{const a=await gS(e);return{ok:!0,task:Fg(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 bH(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:Fg(n)}}catch(a){return{ok:!1,reason:"corrupted",error:a}}}async function pu(t,e,n,a){const i=dS(n,a);if(Lt())return Xce(e,i);try{const o=await(await(await ope(t,e)?await vH(t,!0):t).getFileHandle(`${e}.md`,{create:!0})).createWritable();try{await o.write(i)}finally{await o.close()}}catch(r){throw Lh(r,`${e}.md`)}}async function zL(t,e){if(Lt())return Qce(e);try{await t.removeEntry(`${e}.md`)}catch{}try{await(await t.getDirectoryHandle("archive",{create:!1})).removeEntry(`${e}.md`)}catch{}}async function lpe(t,e){await gi(`/api/tasks/${encodeURIComponent(t)}/archive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function dpe(t,e){await gi(`/api/tasks/${encodeURIComponent(t)}/unarchive`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}})}async function upe(t,e,n,a){const i=dS(n,a);if(Lt())return lpe(e,i);try{const o=await(await(await vH(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 Lh(r,`archive/${e}.md`)}}async function mpe(t,e,n,a){const i=dS(n,a);if(Lt())return dpe(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 Lh(r,`${e}.md`)}}const fpe="kanban-md",gpe=1,sp="recentProjects";function hS(){return new Promise((t,e)=>{const n=indexedDB.open(fpe,gpe);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result),n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains(sp)||a.createObjectStore(sp,{keyPath:"id"})}})}async function H2(t){const e=await hS();return new Promise((n,a)=>{const i=e.transaction(sp,"readwrite");i.objectStore(sp).put(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function Fy(){const t=await hS();return new Promise((e,n)=>{const i=t.transaction(sp,"readonly").objectStore(sp).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 hpe(t){const e=await hS();return new Promise((n,a)=>{const i=e.transaction(sp,"readwrite");i.objectStore(sp).delete(t),i.oncomplete=()=>n(),i.onerror=()=>a(i.error)})}async function HL(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 bpe(){try{return await(await gi("/api/update/check")).json()}catch{return null}}async function yH(){try{return await(await gi("/api/update/apply",{method:"POST"})).json()}catch{return null}}function _H(t=Ei){const e=t.board.columns;return e[e.length-1]??"Done"}function vpe(t,e=Ei){return t===_H(e)||t.toLowerCase()==="archived"}class ype{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,Lt()&&this.startServerSse(),e&&n&&(this.initHashes(),this.intervalId=setInterval(()=>void this.tick(),300))}startServerSse(){if(typeof window>"u"||!Lt()||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 BL(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 BL(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 UL(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 UL(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 BL(t){try{return await(await(await t.getFileHandle("kandown.json")).getFile()).text()}catch{return null}}async function UL(t,e){try{return await(await(await t.getFileHandle(`${e}.md`)).getFile()).text()}catch{return null}}const Lo=new ype,_pe={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 qL=null;function kH(){return"Notification"in window?Notification.permission:"unsupported"}async function kpe(){return"Notification"in window?await Notification.requestPermission():"unsupported"}function B2({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&&wpe(n.notifications.soundId),!(!n.notifications.browser||kH()!=="granted"))try{new Notification(t,{body:e})}catch{}}function wpe(t){const e=_pe[t],n=window.AudioContext??window.webkitAudioContext;if(!(!n||e.length===0))try{qL??=new n;const a=qL;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 jf(t,e={}){const{maxAttempts:n=3,baseDelayMs:a=500,retryableCheck:i=Zce}=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 xpe(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 Ape(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=xpe(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 Cpe=/^[A-Za-z0-9_-]+$/;function U2(t){if(!t)return null;const e=t.trim().replace(/^\/+|\/+$/g,"").replace(/^#/,"");return!e||e.includes("/")||e.includes(".")||!Cpe.test(e)?null:/^\d+$/.test(e)?`t${e}`:e}function Npe(t){const e=new URLSearchParams(t.search).get("p");if(!e)return null;const[n]=e.split("/").filter(Boolean);return n||null}function zy(t){const e=new URLSearchParams(t.search),n=U2(e.get("task"));if(n)return n;const a=e.get("p");if(a){const[,...r]=a.split("/").filter(Boolean),s=U2(r.join("/"));if(s)return s}return U2(decodeURIComponent(t.pathname))}function T3(t){return t?`/?p=${encodeURIComponent(t)}`:"/"}function bS(t,e){const n=t.replace(/^t(?=\d+$)/,""),a=`/${encodeURIComponent(n)}`;return e?`${a}?p=${encodeURIComponent(e)}`:a}function Hy(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 Iv(t){typeof window<"u"&&zy(window.location)||Hy(T3(t))}function Spe(t){let e=-1;for(const n of t)for(const a of n.tasks){const i=a.id.match(/^t(\d+)$/);if(i){const r=parseInt(i[1],10);r>e&&(e=r)}}return"t"+(e+1)}async function $pe(){const t=await fS();return await Promise.all(t.map(async n=>{const{frontmatter:a,body:i}=await hH(n),r={...a,id:a.id||n,status:a.status||"Backlog"},{subtasks:s,bodyWithoutSubtasks:o}=Rs(i);return{id:n,frontmatter:r,body:o,subtasks:s}}))}async function Epe(t){const e=await cpe(t),n=await Promise.all(e.map(async r=>{const s=await ppe(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}=Rs(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 VL(t,e,n){const a=[];for(const s of e){const o=s.name;s.tasks.forEach((c,p)=>{const d=(async()=>{const{frontmatter:m,body:f}=await Ps(t,c.id);await pu(t,c.id,{...m,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 pl(t){mH(t.ui.theme,t.ui.skin,t.ui.font,t.ui.background)}function P3(t){return{title:t.frontmatter.title||t.id,status:t.frontmatter.status||"Backlog",body:t.body,subtasks:t.subtasks}}function q2(t){yu.clear(),t.forEach(e=>{yu.set(e.id,P3(e))})}function Tpe(t){const e=t.split(/[\\/]+/).filter(Boolean),n=e[e.length-1];return n===".kandown"?e[e.length-2]??"Project":n??"Project"}function Ppe(t,e){return e.reduce((n,a,i)=>{const r=t[i]?.done??!1;return n+(a.done&&!r?1:0)},0)}function Mpe(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 Lpe=0;const yu=new Map,Df=new Map;let V2=null;const se=Lce((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:Ei,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()=>{const{selectedTaskIds:n,deleteTask:a}=e();for(const i of n)await a(i);t({selectedTaskIds:[]})},drawerBaseVersion:null,conflictState:null,showConflictModal:!1,openFolder:async()=>{if(!fH()){const c=navigator.userAgent||"this browser";e().toast(new Vce(c).message,"error",8e3);return}let n;try{n=await npe()}catch(c){c instanceof mS?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}),Iv(s);const o=Lt()?z2():null;try{await H2({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 Fy();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 HL(n.handle,!0)){let r=!1;try{await Oy(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 hpe(n.id);const s=await Fy();t({recentProjects:s})}catch{}return}e().toast("Permission denied — please grant access to the folder","error");return}try{const r=await Oy(n.handle),s=await E3(n.handle),o=n.handle.name;t({dirHandle:r,tasksDirHandle:s,projectName:o}),Iv(o);try{await H2({...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=z2();if(!n)throw new Error("No server root");await OL();const a=Tpe(n),i=await gH();pl(i);const r=await fS(),s=await Promise.all(r.map(async f=>{const{frontmatter:h,body:v}=await hH(f),k={...h,id:h.id||f,status:h.status||"Backlog"},{subtasks:w,bodyWithoutSubtasks:A}=Rs(v);return{id:f,frontmatter:k,body:A,subtasks:w}}));q2(s);const o=s.map(f=>({frontmatter:f.frontmatter,body:Wd(f.body,f.subtasks)})),c=R2(o,i.board.columns),p=O2(o),d=c.reduce((f,h)=>f+h.tasks.length,0),m=new Map;if(d<=10)for(const f of s)m.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:m,searchMatches:new Map}),Iv(a),e().setupWatcher(),e().refreshAgentHook()}catch{t({loading:!1,isOpen:!1}),e().toast("Impossible de charger le projet. Relancez `kandown`.","error")}},tryAutoOpenServerProject:async()=>{if(!Lt())return;const n=z2();if(!n)return;await OL();const a=await Fy(),i=a.find(p=>p.kandownDir===n);if(!i){await e().openServerProject();return}if(!await HL(i.handle,!0)){await e().openServerProject();return}const s=await Oy(i.handle),o=await E3(i.handle),c=i.handle.name;t({dirHandle:s,tasksDirHandle:o,projectName:c,recentProjects:a,isOpen:!0}),Iv(c),await H2({...i,lastOpened:Date.now()}),await e().loadConfig(),await e().reloadBoard(),e().setupWatcher()},loadConfig:async()=>{const{dirHandle:n}=e();if(!(!n&&!Lt()))try{const a=await ape(n);if(a.ok){t({config:a.config}),pl(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:Ei}),pl(Ei)}catch{t({config:Ei}),pl(Ei)}},updateConfig:async n=>{const{dirHandle:a,config:i}=e();if(!a&&!Lt())return;const r=n(i);t({config:r}),pl(r);try{await ipe(a,r)}catch(s){const o=s;o instanceof To?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(Lt()){const i=await $pe();q2(i);const r=i.map(d=>({frontmatter:d.frontmatter,body:Wd(d.body,d.subtasks)})),s=R2(r,a.board.columns),o=O2(r);t({boardTitle:"Project Kanban",columns:s,archivedTasks:o});const c=s.reduce((d,m)=>d+m.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 Epe(n);q2(i);const s=i.map(m=>({frontmatter:m.frontmatter,body:Wd(m.body,m.subtasks)})),o=R2(s,a.board.columns),c=O2(s);t({boardTitle:"Project Kanban",columns:o,archivedTasks:c});const p=o.reduce((m,f)=>m+f.tasks.length,0),d=new Map;if(p<=10)for(const m of i)d.set(m.frontmatter.id,{frontmatter:m.frontmatter,subtasks:m.subtasks,body:m.body});if(r.length>0){const m=r.length===1?`Task ${r[0]} could not be loaded`:`${r.length} tasks could not be loaded`;e().toast(m,"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=Lt();if(!d&&!e().tasksDirHandle)return;const m=s.find(T=>T.name===a),f=s.find(T=>T.name===i);if(!m||!f)return;const h=m.tasks.findIndex(T=>T.id===n);if(h===-1)return;const v=m.tasks[h];if(!v)return;if(vpe(i,o)){const T=new Map,M=_H(o).toLowerCase();for(const D of s)for(const I of D.tasks){const H=I.frontmatter&&(I.frontmatter.archived===!0||I.frontmatter.archived==="true");T.set(I.id,{exists:!0,resolved:H||I.id===n||D.name.toLowerCase()===M})}const j=[];for(const D of v.dependsOn){if(typeof D!="string"||!D.trim()||D===n)continue;const I=T.get(D);(!I||!I.resolved)&&j.push(D)}if(j.length>0){const D=j.length===1?j[0]:`${j.slice(0,-1).join(", ")} and ${j[j.length-1]}`;e().toast(`Cannot move ${n} to ${i}: blocked by ${D}`,"error");return}}const k=s.map(T=>({...T,tasks:[...T.tasks]})),w=k.find(T=>T.name===a),A=k.find(T=>T.name===i),[$]=w.tasks.splice(h,1);/done|termin|closed|complet/i.test(i)?$.checked=!0:$.checked=!1,r!==void 0?A.tasks.splice(r,0,$):A.tasks.push($),t({columns:k});try{const{tasksDirHandle:T}=e();if(!T&&!d)return;const M=a===i?k.filter(D=>D.name===i):k.filter(D=>D.name===a||D.name===i),{failedIds:j}=await jf(()=>VL(T??null,M,o.board.columns),{maxAttempts:3});if(j.length>0){const D=j.length===1?`Could not save move for ${j[0]}`:`${j.length} tasks could not be moved`;e().toast(D,"warning",8e3),await e().reloadBoard()}}catch(T){const M=T;M instanceof To?e().toast("Disk is full — move was not saved. Free up space and try again.","error",8e3):e().toast("Failed to save: "+M.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&&!Lt())return;const d=r.map(h=>({...h,tasks:[...h.tasks]})),m=d.find(h=>h.name===n);if(!m)return;const[f]=m.tasks.splice(a,1);m.tasks.splice(i,0,f),t({columns:d});try{const{tasksDirHandle:h}=e(),v=Lt();if(!h&&!v)return;const{failedIds:k}=await jf(()=>VL(h??null,[m],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 To?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(m=>m.name===n);if(d){const f=(await Promise.allSettled(d.tasks.map(async(h,v)=>{const{frontmatter:k,body:w}=await Ps(s,h.id);await pu(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(m=>{const f={...m.board.columnColors??{}},h=f[n.toLowerCase()];h&&(f[i.toLowerCase()]=h,delete f[n.toLowerCase()]);const v=m.board.columns.some(k=>k.toLowerCase()===n.toLowerCase())?m.board.columns:[...m.board.columns,n];return{...m,board:{...m.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&&!Lt())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&&!Lt())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=>zL(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(m=>m.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}=e();if(!r&&!Lt()||!i.length)return null;const p=n||s.board.columns[0]||i[0].name,d=Spe(i),m=i.find($=>$.name===p)?.tasks.length??0,f=a?Ape(a):null,h={id:d,title:f?.title||"",checked:!1,dependsOn:f?.depends_on||[],tags:f?.tags||[],assignee:f?.assignee||null,priority:f?.priority||(s.fields.priority?s.board.defaultPriority:null),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",progress:null,frontmatter:{}},v=i.map($=>$.name===p?{...$,tasks:[...$.tasks,h]}:$),k=new Map(o),w={id:d,title:f?.title||"",status:p,order:m,priority:f?.priority||(s.fields.priority?s.board.defaultPriority:""),tags:f?.tags||[],assignee:f?.assignee||"",due:f?.due||"",depends_on:f?.depends_on||[],created:new Date().toISOString().slice(0,10),ownerType:s.fields.ownerType?s.board.defaultOwnerType:"",tools:""},A="";k.set(d,{frontmatter:w,subtasks:[],body:A}),t({columns:v,taskContents:k});try{const $=r||null;return await jf(()=>pu($,d,w,A),{maxAttempts:3}),e().toast(`Created ${d.replace(/^t/,"")}`),await e().openDrawer(d),d}catch($){const T=$;return T instanceof To?e().toast("Disk is full — task was not created.","error",8e3):e().toast("Failed to create: "+T.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&&!Lt())return;const o=a.map(d=>({...d,tasks:d.tasks.filter(m=>m.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 zL(i||null,n),e().toast("Deleted")}catch(d){const m=d;e().toast("Failed to delete: "+m.message,"error"),t({columns:a,taskContents:r,searchMatches:s})}},archiveTask:async n=>{const{tasksDirHandle:a}=e();if(!(!a&&!Lt()))try{const{frontmatter:i,body:r}=await Ps(a||null,n);await upe(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 To?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&&!Lt()))try{const{frontmatter:i,body:r}=await Ps(a||null,n),s={...i};delete s.archived,await mpe(a||null,n,s,r),await e().reloadBoard(),e().toast("Restored")}catch(i){const r=i;r instanceof To?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&&!Lt()))try{const{frontmatter:s,body:o}=await Ps(i,n),{subtasks:c,bodyWithoutSubtasks:p}=Rs(o),d={frontmatter:s,subtasks:c,body:p,savedAt:Date.now()},m=e().drawerRecoveryData.get(n),f=m?{frontmatter:m.frontmatter,subtasks:m.subtasks,body:m.body}:{frontmatter:s,subtasks:c,body:p},h=new Map(e().drawerRecoveryData);h.delete(n),a.syncUrl!==!1&&Hy(bS(n,r),a.replace),t({drawerTaskId:n,drawerData:f,drawerBaseVersion:d,conflictState:null,showConflictModal:!1,hasUnsavedDrawerEdits:!!m,lastSaveError:null,drawerRecoveryData:h}),m&&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&&Hy(T3(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=Wd(a.body,a.subtasks),o={...a.frontmatter,id:n};try{await jf(()=>pu(i||null,n,o,s),{maxAttempts:3}),e().toast("Saved");const c=new Map(e().drawerRecoveryData);c.delete(n),Hy(T3(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 To?"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=Wd(a.body,a.subtasks),o={...a.frontmatter,id:n};await jf(()=>pu(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 To?"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(!Lt()){t({agentHook:null});return}const n=await Jce();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 epe(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 Ps(a,r),{subtasks:c,bodyWithoutSubtasks:p}=Rs(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=lH(o,r);c.length>0&&i.set(s,c)}t({searchMatches:i})},toast:(n,a="success",i)=>{const r=++Lpe,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 Ps(r,s),{subtasks:d,bodyWithoutSubtasks:m}=Rs(p);t({drawerData:{frontmatter:c,subtasks:d,body:m},drawerBaseVersion:{frontmatter:c,subtasks:d,body:m,savedAt:Date.now()},conflictState:null,showConflictModal:!1}),e().toast("Reloaded from disk")}else if(n==="overwrite"){if(i&&s&&o){const c=Wd(i.body,i.subtasks),p={...i.frontmatter,id:s};try{await pu(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(Lt()){V2&&clearInterval(V2),V2=setInterval(()=>{e().reloadBoard()},2e3);return}const{dirHandle:n,tasksDirHandle:a}=e();if(!n||!a)return;Lo.stop(),Df.forEach(s=>clearTimeout(s)),Df.clear(),Lo.start(n,a);const i=(s,o)=>{const c=Df.get(s);c&&clearTimeout(c);const p=Math.max(2e3,e().config.notifications.editDebounceMs),d=setTimeout(()=>{Df.delete(s);const m=e().config;m.notifications.taskEdits&&B2({title:"Task edited",body:`${o} changed on disk.`,config:m})},p);Df.set(s,d)},r=async s=>{const{tasksDirHandle:o,config:c}=e();if(!o)return;let p,d;try{({frontmatter:p,body:d}=await Ps(o,s))}catch(A){console.warn(`[Watcher] notifyTaskChange: failed to read ${s}:`,A);return}const{subtasks:m,bodyWithoutSubtasks:f}=Rs(d),h={id:s,frontmatter:{...p,id:p.id||s,status:p.status||"Backlog"},body:f,subtasks:m},v=P3(h),k=yu.get(s);if(!k){yu.set(s,v);return}c.notifications.statusChanges&&k.status!==v.status&&B2({title:"Task status changed",body:`${v.title}: ${k.status} → ${v.status}`,config:c});const w=Ppe(k.subtasks,v.subtasks);c.notifications.subtaskCompletions&&w>0&&B2({title:"Subtask completed",body:w===1?`${v.title}: 1 subtask completed.`:`${v.title}: ${w} subtasks completed.`,config:c}),Mpe(k,v)&&i(s,v.title),yu.set(s,v)};Lo.on("configChanged",()=>{try{e().loadConfig(),e().toast("Settings updated externally","info")}catch(s){console.error("[Watcher] configChanged handler error:",s)}}),Lo.on("taskChanged",async s=>{try{const{drawerTaskId:o,drawerBaseVersion:c,tasksDirHandle:p}=e();if(await r(s),o===s&&c&&p){let d,m;try{({frontmatter:d,body:m}=await Ps(p,s))}catch(T){console.warn(`[Watcher] taskChanged: failed to re-read ${s}:`,T);return}const{subtasks:f,bodyWithoutSubtasks:h}=Rs(m),v=c,k=JSON.stringify(v.frontmatter)!==JSON.stringify(d),w=v.body!==h,A=JSON.stringify(v.subtasks)!==JSON.stringify(f);if(!k&&!w&&!A)return;let $="none";k&&(w||A)?$="full":k?$="metadata-only":(w||A)&&($="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)}}),Lo.on("newTaskDetected",async s=>{try{const{tasksDirHandle:o}=e();if(o){let c,p;try{({frontmatter:c,body:p}=await Ps(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:m}=Rs(p);yu.set(s,P3({id:s,frontmatter:{...c,id:c.id||s,status:c.status||"Backlog"},body:m,subtasks:d}))}await e().reloadBoard()}catch(o){console.error(`[Watcher] newTaskDetected handler error for ${s}:`,o)}}),Lo.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"))}}));Fy().then(t=>{se.setState({recentProjects:t})}).catch(t=>{console.warn("[Store] Failed to hydrate recent projects:",t)});pl(Ei);window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{pl(se.getState().config)});const jpe=Object.freeze(Object.defineProperty({__proto__:null,useStore:se},Symbol.toStringTag,{value:"Module"}));function Dpe({icon:t,value:e,label:n,isActive:a,onClick:i,layoutId:r}){return b.jsxs("button",{type:"button",className:T1("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(nt.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 Ipe=[{icon:b.jsx(yce,{}),value:"auto",label:"system"},{icon:b.jsx(Sce,{}),value:"light",label:"light"},{icon:b.jsx(kce,{}),value:"dark",label:"dark"}];function Rpe({value:t,onChange:e,className:n}){const a=se(d=>d.config.ui.theme),i=se(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(m=>({...m,ui:{...m.ui,theme:d}}))});return s?b.jsx(nt.div,{initial:{opacity:0},animate:{opacity:1},transition:{duration:.3},className:T1("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:Ipe.map(d=>b.jsx(Dpe,{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:T1("flex h-8 w-24",n)})}function Ope(t){const e=soe(t,{stiffness:180,damping:22,mass:.8});return S.useEffect(()=>{e.set(t)},[t,e]),Uz(e,a=>Math.round(a).toString())}const M3="0.33.1";function wH({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 Fpe(){const{t}=Tn(),e=se(B=>B.dirHandle),n=se(B=>B.isOpen),a=se(B=>B.projectName),i=se(B=>B.closeDrawer),r=se(B=>B.drawerTaskId),s=se(B=>B.saveDrawer),o=se(B=>B.archivedTasks.length),c=se(B=>B.showArchives),p=se(B=>B.setShowArchives),d=se(B=>B.columns),m=se(B=>B.openFolder),f=se(B=>B.reloadBoard),h=se(B=>B.createTask),v=se(B=>B.setCommandOpen),k=se(B=>B.viewMode),w=se(B=>B.setViewMode),A=se(B=>B.density),$=se(B=>B.setDensity),T=se(B=>B.setCurrentPage),M=se(B=>B.recentProjects),j=se(B=>B.openRecentProject),D=se(B=>B.filters),I=se(B=>B.setFilter),H=se(B=>B.clearFilters),R=se(B=>B.config.fields),L=se(B=>B.lastReloadError),G=se(B=>B.watcherError),Y=se(B=>B.restartWatcher),[ne,U]=S.useState(!1),[F,V]=S.useState(!0),Q=S.useRef(null),J=S.useRef(null),oe=d.reduce((B,ae)=>B+ae.tasks.length,0),O=Ope(oe),Z=[];R.priority&&D.priority&&Z.push({type:"priority",label:D.priority,value:D.priority}),R.tags&&D.tag&&Z.push({type:"tag",label:"#"+D.tag,value:D.tag}),R.assignee&&D.assignee&&Z.push({type:"assignee",label:"@"+D.assignee,value:D.assignee});const K=[{label:t("filterBar.ownerAll"),value:""},{label:t("filterBar.ownerHuman"),value:"human"},{label:t("filterBar.ownerAI"),value:"ai"}],E=Z.length>0||D.search||R.ownerType&&D.ownerType;return S.useEffect(()=>{if(!ne)return;const B=ae=>{Q.current&&!Q.current.contains(ae.target)&&U(!1)};return document.addEventListener("mousedown",B),()=>document.removeEventListener("mousedown",B)},[ne]),S.useEffect(()=>{const B=setTimeout(()=>V(!1),5e3);return()=>clearTimeout(B)},[]),S.useEffect(()=>{document.title=a?`${a} · Kandown`:"Kandown"},[a]),b.jsxs(b.Fragment,{children:[(L||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}`:`⚠ ${L}`}),G&&b.jsx("button",{type:"button",onClick:Y,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(wH,{className:"w-[34px] h-[34px] dark:text-white text-black"}),b.jsx(Wa,{mode:"wait",initial:!1,children:F?b.jsxs(nt.span,{className:"flex items-center gap-2",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.45},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",M3]})]},"boot"):a?b.jsx(nt.span,{className:"text-[15px] font-semibold tracking-tight text-fg truncate max-w-[240px]",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.45},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(Wn.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(Wn.Search,{size:14,className:"text-fg-muted/60 flex-shrink-0"}),b.jsx("input",{ref:J,type:"text",placeholder:t("filterBar.searchPlaceholder"),value:D.search,onChange:B=>I("search",B.target.value),className:"bg-transparent border-none outline-none text-fg text-[13px] w-full placeholder:text-fg-muted/60"}),D.search?b.jsx("button",{onClick:()=>I("search",""),className:"text-fg-muted/60 hover:text-fg flex-shrink-0",children:b.jsx(Wn.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(Wa,{children:Z.map(B=>b.jsxs(nt.button,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.9},transition:{duration:.15},onClick:()=>I(B.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:[B.label,b.jsx(Wn.X,{size:10,className:"text-fg-muted/60"})]},B.type+B.value))}),R.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:K.map(B=>b.jsx("button",{onClick:()=>I("ownerType",B.value),className:`h-full px-2.5 text-[12px] transition-colors ${D.ownerType===B.value?"bg-black/[0.06] dark:bg-white/[0.12] text-fg":"text-fg-muted/70 hover:text-fg"}`,children:B.label},B.value))}),E&&b.jsx("button",{onClick:H,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:Q,children:[b.jsxs("button",{onClick:()=>U(B=>!B),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(Wn.Folder,{size:13,className:"text-fg-muted/70"}),b.jsxs("span",{className:"font-medium",children:[".",e.name]}),b.jsx(Wn.ChevronDown,{size:11,className:"opacity-50"})]}),b.jsx(Wa,{children:ne&&b.jsx(nt.div,{initial:{opacity:0,y:-4,scale:.98},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:-4,scale:.98},transition:{duration:.12},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:[M.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")}),M.map(B=>b.jsxs("button",{onClick:()=>{U(!1),j(B)},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(Wn.Folder,{size:12,className:"text-fg-muted/60"}),b.jsx("span",{className:"truncate",children:B.name}),B.id===e.name&&b.jsx(Wn.Check,{size:12,className:"ml-auto text-emerald-500"})]},B.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),m()},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(Wn.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(nt.span,{className:"tabular-nums font-medium",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(Wn.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(Wn.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:()=>$(A==="compact"?"comfortable":"compact"),title:`Density: ${A}`}),b.jsx(an,{variant:"icon",icon:"Settings",onClick:()=>T("settings"),title:t("common.settings")}),b.jsx(Rpe,{}),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:m})})]})]})}/**
|
|
205
205
|
* @license @tabler/icons-react v3.41.1 - MIT
|
|
206
206
|
*
|
|
207
207
|
* This source code is licensed under the MIT license.
|