@dendelion/paper-camp 0.23.1 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/app/assets/{index-CKO_a_mt.js → index-B5TCF8_a.js} +2 -2
  2. package/dist/app/assets/{index-CKO_a_mt.js.map → index-B5TCF8_a.js.map} +1 -1
  3. package/dist/app/assets/{index-DC_F8eQU.js → index-BY8Yo_l0.js} +2 -2
  4. package/dist/app/assets/{index-DC_F8eQU.js.map → index-BY8Yo_l0.js.map} +1 -1
  5. package/dist/app/assets/{index-DoH_Ktpt.js → index-BxRIu8zx.js} +2 -2
  6. package/dist/app/assets/{index-DoH_Ktpt.js.map → index-BxRIu8zx.js.map} +1 -1
  7. package/dist/app/assets/{index-CFMhKXQf.js → index-C1ORGbU3.js} +2 -2
  8. package/dist/app/assets/{index-CFMhKXQf.js.map → index-C1ORGbU3.js.map} +1 -1
  9. package/dist/app/assets/{index-CeEpQji6.js → index-C3R9IAt7.js} +2 -2
  10. package/dist/app/assets/{index-CeEpQji6.js.map → index-C3R9IAt7.js.map} +1 -1
  11. package/dist/app/assets/{index-Twqzhu_o.js → index-CR8PI9q6.js} +2 -2
  12. package/dist/app/assets/{index-Twqzhu_o.js.map → index-CR8PI9q6.js.map} +1 -1
  13. package/dist/app/assets/{index-CTHTRX-O.js → index-Ddz2TPW1.js} +2 -2
  14. package/dist/app/assets/{index-CTHTRX-O.js.map → index-Ddz2TPW1.js.map} +1 -1
  15. package/dist/app/assets/{index-B0T4zOOc.js → index-rxWn42R9.js} +2 -2
  16. package/dist/app/assets/{index-B0T4zOOc.js.map → index-rxWn42R9.js.map} +1 -1
  17. package/dist/app/assets/{main-CDkrPxrg.js → main-DkQCGPBX.js} +120 -120
  18. package/dist/app/assets/main-DkQCGPBX.js.map +1 -0
  19. package/dist/app/assets/main-o2BbWpF4.css +1 -0
  20. package/dist/app/assets/{sidebar-section-7T-4hlR4.js → sidebar-section-Cqk2bPNP.js} +2 -2
  21. package/dist/app/assets/{sidebar-section-7T-4hlR4.js.map → sidebar-section-Cqk2bPNP.js.map} +1 -1
  22. package/dist/app/index.html +2 -2
  23. package/dist/app/toolbar.js +3030 -2968
  24. package/dist/app/toolbar.js.map +1 -1
  25. package/dist/cli/index.js +2526 -2522
  26. package/dist/cli/index.js.map +1 -1
  27. package/package.json +1 -1
  28. package/dist/app/assets/main-BAlJ6w7u.css +0 -1
  29. package/dist/app/assets/main-CDkrPxrg.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index-Twqzhu_o.js","sources":["../../../src/core/notifications.ts","../../../src/app/features/inbox/helpers.ts","../../../src/app/features/inbox/hooks/use-inbox-page.ts","../../../src/app/features/inbox/notification-row.tsx","../../../src/app/features/inbox/question-row.tsx","../../../src/app/features/inbox/inbox-page.tsx"],"sourcesContent":["import type { Notification, ParkedQuestion, StoredNotification } from '../types/index';\n\nfunction ageInDays(date: string): number {\n return Math.floor((Date.now() - Date.parse(date)) / 86_400_000);\n}\n\nexport function notificationAgeDays(notification: Notification): number {\n return notification.kind === 'question' ? notification.ageDays : ageInDays(notification.date);\n}\n\n/** Every parked question alongside completed/reply notifications, oldest-first — the\n * unified feed (IDEA-153) replacing the questions-only Inbox. */\nexport function mergeNotifications(\n parkedQuestions: ParkedQuestion[],\n stored: StoredNotification[],\n): Notification[] {\n const entries: Notification[] = [\n ...parkedQuestions.map((q): Notification => ({ ...q, kind: 'question' })),\n ...stored,\n ];\n return entries.sort((a, b) => notificationAgeDays(b) - notificationAgeDays(a));\n}\n","export const formatAge = (ageDays: number): string => {\n if (!Number.isFinite(ageDays)) return 'age unknown';\n if (ageDays <= 0) return 'today';\n return ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;\n};\n","import { useOpenEntity } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useEffect, useState } from 'react';\n\nexport const useInboxPage = () => {\n const [expandedKey, setExpandedKey] = useState<string | null>(null);\n const notifications = useAppStore((s) => s.notifications);\n const loadFailed = useAppStore((s) => s.notificationsError !== null);\n const plans = useAppStore((s) => s.plans);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadNotifications = useAppStore((s) => s.loadNotifications);\n const markRead = useAppStore((s) => s.markRead);\n const openEntity = useOpenEntity();\n\n useEffect(() => {\n loadNotifications();\n }, [loadNotifications]);\n\n useEffect(() => {\n if (!notifications) return;\n for (const n of notifications) {\n if (n.kind !== 'question' && !n.read) markRead(n.id);\n }\n }, [notifications, markRead]);\n\n const reload = async () => {\n await Promise.all([loadPlans(), loadNotifications()]);\n };\n\n return {\n notifications,\n loadFailed,\n plans,\n expandedKey,\n setExpandedKey,\n openEntity,\n reload,\n };\n};\n","import { PlanIdStamp } from '@/app/features/plans/components';\nimport type { StoredNotification } from '@/types/index';\nimport { formatAge } from './helpers';\n\nconst KIND_LABELS: Record<StoredNotification['kind'], string> = {\n completed: 'Completed',\n reply: 'Reply',\n};\n\ninterface NotificationRowProps {\n notification: StoredNotification;\n ageDays: number;\n onOpen: () => void;\n}\n\nexport const NotificationRow = ({ notification, ageDays, onOpen }: NotificationRowProps) => (\n <div className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${notification.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={notification.entityId} />\n </button>\n <span className=\"text-xs uppercase tracking-wide opacity-40 whitespace-nowrap\">\n {KIND_LABELS[notification.kind]}\n </span>\n <span className=\"flex-1 min-w-0 truncate\">{notification.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(ageDays)}</span>\n </div>\n);\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport { useSendFeedbackMessage } from '@/app/features/plans/hooks';\nimport { readLocalDraft, removeLocalDraft, writeLocalDraft } from '@/app/utils/local-draft-store';\nimport type { ParkedQuestion, PlanEntry } from '@/types/index';\nimport { Button, Spinner, Textarea, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { formatAge } from './helpers';\n\ninterface QuestionRowProps {\n question: ParkedQuestion;\n plan: PlanEntry;\n expanded: boolean;\n onToggle: () => void;\n onOpen: () => void;\n reload: () => Promise<void>;\n}\n\nexport const QuestionRow = ({\n question,\n plan,\n expanded,\n onToggle,\n onOpen,\n reload,\n}: QuestionRowProps) => {\n const { toast } = useToast();\n const [input, setInput] = useState('');\n const { sending, send, undo, undoing, undoEdit } = useSendFeedbackMessage(plan, {\n reload,\n notify: toast,\n });\n\n const draftKey = `question-reply:${question.entityId}`;\n\n useEffect(() => {\n const draft = readLocalDraft<string>(draftKey);\n if (draft) setInput(draft);\n }, [draftKey]);\n\n useEffect(() => {\n if (!input) return;\n writeLocalDraft(draftKey, input);\n }, [draftKey, input]);\n\n const handleSend = async () => {\n if (!input.trim()) return;\n if (await send(input.trim())) {\n setInput('');\n removeLocalDraft(draftKey);\n }\n };\n\n return (\n <div className=\"border-b border-black/10 last:border-b-0\">\n <div className=\"flex items-center gap-3 py-2.5\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${question.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={question.entityId} />\n </button>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"flex-1 min-w-0 truncate text-left bg-transparent border-none p-0 cursor-pointer\"\n >\n {question.text}\n </button>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(question.ageDays)}</span>\n </div>\n {expanded && (\n <div className=\"flex flex-col gap-3 pb-4\">\n <FeedbackThread\n messages={plan.thread ?? []}\n undo={undo}\n undoing={undoing}\n onUndo={undoEdit}\n />\n <Textarea\n value={input}\n onChange={(e) => setInput(e.target.value)}\n aria-label={`Reply to ${question.entityTitle}`}\n placeholder=\"Reply to resolve and resume…\"\n rows={2}\n disabled={sending}\n />\n <div className=\"flex justify-end items-center gap-3\">\n <span className={sending ? 'visible' : 'invisible'}>\n <Spinner size=\"small\" label=\"Agent replying…\" />\n </span>\n <Button size=\"small\" onClick={handleSend} disabled={sending || !input.trim()}>\n Reply\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { PlanIdStamp } from '@/app/features/plans/components';\nimport { notificationAgeDays } from '@/core/notifications';\nimport { formatAge } from './helpers';\nimport { useInboxPage } from './hooks';\nimport { NotificationRow } from './notification-row';\nimport { QuestionRow } from './question-row';\n\nexport const InboxPage = () => {\n const { notifications, loadFailed, plans, expandedKey, setExpandedKey, openEntity, reload } =\n useInboxPage();\n\n return (\n <div>\n <PageTitle>Inbox</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every parked question, completed run, and agent reply, oldest first.\n </p>\n {loadFailed && <p className=\"opacity-50\">Couldn't load notifications.</p>}\n {!loadFailed && !notifications && <p className=\"opacity-50\">Loading…</p>}\n {notifications && notifications.length === 0 && (\n <p className=\"opacity-50\">Nothing here — no parked questions or recent activity.</p>\n )}\n {notifications && notifications.length > 0 && (\n <div className=\"flex flex-col\">\n {notifications.map((n, i) => {\n const key = `${n.entityId}-${n.kind}-${i}`;\n const onOpen = () => openEntity(n.entityId, n.entityTitle);\n\n if (n.kind !== 'question') {\n return (\n <NotificationRow\n key={key}\n notification={n}\n ageDays={notificationAgeDays(n)}\n onOpen={onOpen}\n />\n );\n }\n\n const plan = plans?.entries.find((p) => p.id === n.entityId);\n if (!plan) {\n return (\n <div\n key={key}\n className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\"\n >\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${n.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={n.entityId} />\n </button>\n <span className=\"flex-1 min-w-0 truncate\">{n.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatAge(n.ageDays)}\n </span>\n </div>\n );\n }\n return (\n <QuestionRow\n key={key}\n question={n}\n plan={plan}\n expanded={expandedKey === key}\n onToggle={() => setExpandedKey((cur) => (cur === key ? null : key))}\n onOpen={onOpen}\n reload={reload}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ageInDays","date","notificationAgeDays","notification","formatAge","ageDays","useInboxPage","expandedKey","setExpandedKey","useState","notifications","useAppStore","loadFailed","plans","loadPlans","loadNotifications","markRead","openEntity","useOpenEntity","useEffect","n","KIND_LABELS","NotificationRow","onOpen","jsxs","jsx","PlanIdStamp","QuestionRow","question","plan","expanded","onToggle","reload","toast","useToast","input","setInput","sending","send","undo","undoing","undoEdit","useSendFeedbackMessage","draftKey","draft","readLocalDraft","writeLocalDraft","handleSend","removeLocalDraft","FeedbackThread","Textarea","e","Spinner","Button","InboxPage","PageTitle","i","key","p","cur"],"mappings":"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"}
1
+ {"version":3,"file":"index-CR8PI9q6.js","sources":["../../../src/core/notifications.ts","../../../src/app/features/inbox/helpers.ts","../../../src/app/features/inbox/hooks/use-inbox-page.ts","../../../src/app/features/inbox/notification-row.tsx","../../../src/app/features/inbox/question-row.tsx","../../../src/app/features/inbox/inbox-page.tsx"],"sourcesContent":["import type { Notification, ParkedQuestion, StoredNotification } from '../types/index';\n\nfunction ageInDays(date: string): number {\n return Math.floor((Date.now() - Date.parse(date)) / 86_400_000);\n}\n\nexport function notificationAgeDays(notification: Notification): number {\n return notification.kind === 'question' ? notification.ageDays : ageInDays(notification.date);\n}\n\n/** Every parked question alongside completed/reply notifications, oldest-first — the\n * unified feed (IDEA-153) replacing the questions-only Inbox. */\nexport function mergeNotifications(\n parkedQuestions: ParkedQuestion[],\n stored: StoredNotification[],\n): Notification[] {\n const entries: Notification[] = [\n ...parkedQuestions.map((q): Notification => ({ ...q, kind: 'question' })),\n ...stored,\n ];\n return entries.sort((a, b) => notificationAgeDays(b) - notificationAgeDays(a));\n}\n","export const formatAge = (ageDays: number): string => {\n if (!Number.isFinite(ageDays)) return 'age unknown';\n if (ageDays <= 0) return 'today';\n return ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;\n};\n","import { useOpenEntity } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useEffect, useState } from 'react';\n\nexport const useInboxPage = () => {\n const [expandedKey, setExpandedKey] = useState<string | null>(null);\n const notifications = useAppStore((s) => s.notifications);\n const loadFailed = useAppStore((s) => s.notificationsError !== null);\n const plans = useAppStore((s) => s.plans);\n const loadPlans = useAppStore((s) => s.loadPlans);\n const loadNotifications = useAppStore((s) => s.loadNotifications);\n const markRead = useAppStore((s) => s.markRead);\n const openEntity = useOpenEntity();\n\n useEffect(() => {\n loadNotifications();\n }, [loadNotifications]);\n\n useEffect(() => {\n if (!notifications) return;\n for (const n of notifications) {\n if (n.kind !== 'question' && !n.read) markRead(n.id);\n }\n }, [notifications, markRead]);\n\n const reload = async () => {\n await Promise.all([loadPlans(), loadNotifications()]);\n };\n\n return {\n notifications,\n loadFailed,\n plans,\n expandedKey,\n setExpandedKey,\n openEntity,\n reload,\n };\n};\n","import { PlanIdStamp } from '@/app/features/plans/components';\nimport type { StoredNotification } from '@/types/index';\nimport { formatAge } from './helpers';\n\nconst KIND_LABELS: Record<StoredNotification['kind'], string> = {\n completed: 'Completed',\n reply: 'Reply',\n};\n\ninterface NotificationRowProps {\n notification: StoredNotification;\n ageDays: number;\n onOpen: () => void;\n}\n\nexport const NotificationRow = ({ notification, ageDays, onOpen }: NotificationRowProps) => (\n <div className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${notification.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={notification.entityId} />\n </button>\n <span className=\"text-xs uppercase tracking-wide opacity-40 whitespace-nowrap\">\n {KIND_LABELS[notification.kind]}\n </span>\n <span className=\"flex-1 min-w-0 truncate\">{notification.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(ageDays)}</span>\n </div>\n);\n","import { FeedbackThread, PlanIdStamp } from '@/app/features/plans/components';\nimport { useSendFeedbackMessage } from '@/app/features/plans/hooks';\nimport { readLocalDraft, removeLocalDraft, writeLocalDraft } from '@/app/utils/local-draft-store';\nimport type { ParkedQuestion, PlanEntry } from '@/types/index';\nimport { Button, Spinner, Textarea, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { formatAge } from './helpers';\n\ninterface QuestionRowProps {\n question: ParkedQuestion;\n plan: PlanEntry;\n expanded: boolean;\n onToggle: () => void;\n onOpen: () => void;\n reload: () => Promise<void>;\n}\n\nexport const QuestionRow = ({\n question,\n plan,\n expanded,\n onToggle,\n onOpen,\n reload,\n}: QuestionRowProps) => {\n const { toast } = useToast();\n const [input, setInput] = useState('');\n const { sending, send, undo, undoing, undoEdit } = useSendFeedbackMessage(plan, {\n reload,\n notify: toast,\n });\n\n const draftKey = `question-reply:${question.entityId}`;\n\n useEffect(() => {\n const draft = readLocalDraft<string>(draftKey);\n if (draft) setInput(draft);\n }, [draftKey]);\n\n useEffect(() => {\n if (!input) return;\n writeLocalDraft(draftKey, input);\n }, [draftKey, input]);\n\n const handleSend = async () => {\n if (!input.trim()) return;\n if (await send(input.trim())) {\n setInput('');\n removeLocalDraft(draftKey);\n }\n };\n\n return (\n <div className=\"border-b border-black/10 last:border-b-0\">\n <div className=\"flex items-center gap-3 py-2.5\">\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${question.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={question.entityId} />\n </button>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"flex-1 min-w-0 truncate text-left bg-transparent border-none p-0 cursor-pointer\"\n >\n {question.text}\n </button>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">{formatAge(question.ageDays)}</span>\n </div>\n {expanded && (\n <div className=\"flex flex-col gap-3 pb-4\">\n <FeedbackThread\n messages={plan.thread ?? []}\n undo={undo}\n undoing={undoing}\n onUndo={undoEdit}\n />\n <Textarea\n value={input}\n onChange={(e) => setInput(e.target.value)}\n aria-label={`Reply to ${question.entityTitle}`}\n placeholder=\"Reply to resolve and resume…\"\n rows={2}\n disabled={sending}\n />\n <div className=\"flex justify-end items-center gap-3\">\n <span className={sending ? 'visible' : 'invisible'}>\n <Spinner size=\"small\" label=\"Agent replying…\" />\n </span>\n <Button size=\"small\" onClick={handleSend} disabled={sending || !input.trim()}>\n Reply\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { PlanIdStamp } from '@/app/features/plans/components';\nimport { notificationAgeDays } from '@/core/notifications';\nimport { formatAge } from './helpers';\nimport { useInboxPage } from './hooks';\nimport { NotificationRow } from './notification-row';\nimport { QuestionRow } from './question-row';\n\nexport const InboxPage = () => {\n const { notifications, loadFailed, plans, expandedKey, setExpandedKey, openEntity, reload } =\n useInboxPage();\n\n return (\n <div>\n <PageTitle>Inbox</PageTitle>\n <p className=\"opacity-50 mb-6\">\n Every parked question, completed run, and agent reply, oldest first.\n </p>\n {loadFailed && <p className=\"opacity-50\">Couldn't load notifications.</p>}\n {!loadFailed && !notifications && <p className=\"opacity-50\">Loading…</p>}\n {notifications && notifications.length === 0 && (\n <p className=\"opacity-50\">Nothing here — no parked questions or recent activity.</p>\n )}\n {notifications && notifications.length > 0 && (\n <div className=\"flex flex-col\">\n {notifications.map((n, i) => {\n const key = `${n.entityId}-${n.kind}-${i}`;\n const onOpen = () => openEntity(n.entityId, n.entityTitle);\n\n if (n.kind !== 'question') {\n return (\n <NotificationRow\n key={key}\n notification={n}\n ageDays={notificationAgeDays(n)}\n onOpen={onOpen}\n />\n );\n }\n\n const plan = plans?.entries.find((p) => p.id === n.entityId);\n if (!plan) {\n return (\n <div\n key={key}\n className=\"flex items-center gap-3 py-2.5 border-b border-black/10 last:border-b-0\"\n >\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${n.entityTitle}`}\n className=\"bg-transparent border-none p-0 cursor-pointer\"\n >\n <PlanIdStamp id={n.entityId} />\n </button>\n <span className=\"flex-1 min-w-0 truncate\">{n.text}</span>\n <span className=\"opacity-50 text-xs whitespace-nowrap\">\n {formatAge(n.ageDays)}\n </span>\n </div>\n );\n }\n return (\n <QuestionRow\n key={key}\n question={n}\n plan={plan}\n expanded={expandedKey === key}\n onToggle={() => setExpandedKey((cur) => (cur === key ? null : key))}\n onOpen={onOpen}\n reload={reload}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ageInDays","date","notificationAgeDays","notification","formatAge","ageDays","useInboxPage","expandedKey","setExpandedKey","useState","notifications","useAppStore","loadFailed","plans","loadPlans","loadNotifications","markRead","openEntity","useOpenEntity","useEffect","n","KIND_LABELS","NotificationRow","onOpen","jsxs","jsx","PlanIdStamp","QuestionRow","question","plan","expanded","onToggle","reload","toast","useToast","input","setInput","sending","send","undo","undoing","undoEdit","useSendFeedbackMessage","draftKey","draft","readLocalDraft","writeLocalDraft","handleSend","removeLocalDraft","FeedbackThread","Textarea","e","Spinner","Button","InboxPage","PageTitle","i","key","p","cur"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import{u as h,a2 as y,r as x,a3 as D,j as s,J as C,$ as k,g as v,a4 as L,C as $,a5 as N,a6 as S,S as A,a7 as E,a8 as T,a9 as R,aa as I,ab as _,p as G,ac as M,ad as U,w as O,P as z,ae as B,af as H}from"./main-CDkrPxrg.js";const W=({state:e,filesEmpty:a})=>{const t=h(f=>f.status),{checks:i}=y(),{qualityStatus:l,testStatus:o,consistencyStatus:c}=x.useMemo(()=>D(t,i),[t,i]),n=[l==="fail"&&"Quality",o==="fail"&&"Tests",c==="fail"&&"Consistency"].filter(f=>f!==!1),m=s.jsx(C,{size:"small",disabled:a||!e.commitTitle.trim()||e.committing||e.commitInFlight,onClick:e.handleCommit,children:e.committing||e.commitInFlight?"Committing…":e.stagedCount>0?`Commit ${e.stagedCount} staged`:"Commit"});return n.length===0?m:s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(k,{content:`${n.join(", ")} failing`,children:s.jsx(v,{size:"small",variant:"warning",children:"!"})}),m]})},K="__git__",q=()=>!0,J=e=>L(e,{formKey:K,matchesSuggestionTask:q});function b(e){const a=e.lastIndexOf("/");return a===-1?{dir:"",base:e}:{dir:e.slice(0,a+1),base:e.slice(a+1)}}function Q(e){const a=new Map;for(const t of e){const{dir:i}=b(t.path),l=i||"./",o=a.get(l);o?o.push(t):a.set(l,[t])}return[...a].map(([t,i])=>({dir:t,entries:i}))}const V=()=>{const e=h(d=>d.diffFiles),a=h(d=>d.activeDiffPath),t=h(d=>d.loadDiffFiles),i=h(d=>d.expandDiffPath),[l,o]=x.useState(new Set),[c,n]=x.useState(!1),{toast:m}=$(),f=x.useMemo(()=>Q(e??[]),[e]),r=(e??[]).length>0&&(e??[]).every(d=>d.staged);return{files:e,activePath:a,expandDiffPath:i,groups:f,pending:l,bulkPending:c,allStaged:r,toggleAll:async()=>{const d=(e??[]).filter(j=>j.staged===r);n(!0);try{const p=(await Promise.allSettled(d.map(u=>r?S(u.path):N(u.path)))).filter(u=>u.status==="rejected").length;p>0&&m({title:r?"Unstage failed":"Stage failed",description:`${p} of ${d.length} file(s) could not be updated.`,variant:"error"})}finally{await t(),n(!1)}},toggleStaged:async(d,j)=>{o(p=>new Set(p).add(d.path));try{await(j?N(d.path):S(d.path)),await t()}catch(p){m({title:j?"Stage failed":"Unstage failed",description:A(p.message),variant:"error"})}finally{o(p=>{const u=new Set(p);return u.delete(d.path),u})}}}},X=()=>{const e=h(n=>n.diffFiles),a=h(n=>n.diffLoadFailed),t=h(n=>n.loadDiffFiles),i=h(n=>n.setActiveDiffPath),l=x.useRef(null),o=x.useMemo(()=>(e==null?void 0:e.map(n=>({path:n.path,staged:n.staged})))??[],[e]),c=J(o);return x.useEffect(()=>{t()},[t]),x.useEffect(()=>{let n;const m=E(r=>{r.message==="changed"&&(n&&clearTimeout(n),n=setTimeout(t,250))}),f=()=>t();return window.addEventListener("focus",f),()=>{n&&clearTimeout(n),window.removeEventListener("focus",f),m()}},[t]),x.useEffect(()=>{const n=l.current;if(!n)return;const m=Array.from(n.querySelectorAll("[data-diff-path]"));if(m.length===0)return;const f=new Set,r=new IntersectionObserver(g=>{for(const d of g)d.isIntersecting?f.add(d.target):f.delete(d.target);const w=m.find(d=>f.has(d));w&&i(w.dataset.diffPath??null)},{rootMargin:"0px 0px -70% 0px"});for(const g of m)r.observe(g);return()=>r.disconnect()},[e,i]),{files:e,loadFailed:a,loadDiffFiles:t,sectionsRef:l,commitForm:c}},F=({additions:e,deletions:a})=>s.jsxs("span",{className:"inline-flex shrink-0 gap-1.5 font-mono text-3xs",children:[s.jsxs("span",{className:"text-watercolor-green-dark",children:["+",e]}),s.jsxs("span",{className:"text-watercolor-rose-dark",children:["-",a]})]}),Y=({path:e,prefix:a,className:t=""})=>{const{dir:i,base:l}=b(e),o=`${a??""}${i}`;return s.jsxs("span",{className:`flex min-w-0 items-center font-mono ${t}`,children:[o&&s.jsx("span",{className:"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50",children:o}),s.jsx("span",{className:"shrink-0 whitespace-nowrap",children:l})]})},Z={success:"text-watercolor-green-dark",info:"text-watercolor-blue-dark",error:"text-watercolor-rose-dark",warning:"text-watercolor-amber-dark",neutral:"text-watercolor-slate-dark"},ee={A:{letter:"A",label:"Added",variant:"success"},M:{letter:"M",label:"Modified",variant:"info"},D:{letter:"D",label:"Deleted",variant:"error"},R:{letter:"R",label:"Renamed",variant:"info"},C:{letter:"C",label:"Copied",variant:"info"},U:{letter:"U",label:"Conflicted",variant:"warning"}},se=e=>{if(e==="??")return{letter:"??",label:"Untracked",variant:"neutral"};const[a,t]=e,i=a!==" "&&a!=="?"?a:t;return ee[i]??{letter:i??"?",label:i??"Unknown",variant:"neutral"}},P=({status:e,compact:a=!1})=>{const t=se(e);return a?s.jsx("span",{title:t.label,className:`w-4 shrink-0 text-center font-mono text-3xs font-semibold leading-none ${Z[t.variant]??""}`,children:t.letter}):s.jsx("span",{title:t.label,children:s.jsx(v,{size:"small",variant:t.variant,children:t.letter})})},te=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;function ae(e){if(!e)return[];const a=(e.endsWith(`
1
+ import{u as h,a2 as y,r as x,a3 as D,j as s,J as C,$ as k,g as v,a4 as L,C as $,a5 as N,a6 as S,S as A,a7 as E,a8 as T,a9 as R,aa as I,ab as _,p as G,ac as M,ad as U,w as O,P as z,ae as B,af as H}from"./main-DkQCGPBX.js";const W=({state:e,filesEmpty:a})=>{const t=h(f=>f.status),{checks:i}=y(),{qualityStatus:l,testStatus:o,consistencyStatus:c}=x.useMemo(()=>D(t,i),[t,i]),n=[l==="fail"&&"Quality",o==="fail"&&"Tests",c==="fail"&&"Consistency"].filter(f=>f!==!1),m=s.jsx(C,{size:"small",disabled:a||!e.commitTitle.trim()||e.committing||e.commitInFlight,onClick:e.handleCommit,children:e.committing||e.commitInFlight?"Committing…":e.stagedCount>0?`Commit ${e.stagedCount} staged`:"Commit"});return n.length===0?m:s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(k,{content:`${n.join(", ")} failing`,children:s.jsx(v,{size:"small",variant:"warning",children:"!"})}),m]})},K="__git__",q=()=>!0,J=e=>L(e,{formKey:K,matchesSuggestionTask:q});function b(e){const a=e.lastIndexOf("/");return a===-1?{dir:"",base:e}:{dir:e.slice(0,a+1),base:e.slice(a+1)}}function Q(e){const a=new Map;for(const t of e){const{dir:i}=b(t.path),l=i||"./",o=a.get(l);o?o.push(t):a.set(l,[t])}return[...a].map(([t,i])=>({dir:t,entries:i}))}const V=()=>{const e=h(d=>d.diffFiles),a=h(d=>d.activeDiffPath),t=h(d=>d.loadDiffFiles),i=h(d=>d.expandDiffPath),[l,o]=x.useState(new Set),[c,n]=x.useState(!1),{toast:m}=$(),f=x.useMemo(()=>Q(e??[]),[e]),r=(e??[]).length>0&&(e??[]).every(d=>d.staged);return{files:e,activePath:a,expandDiffPath:i,groups:f,pending:l,bulkPending:c,allStaged:r,toggleAll:async()=>{const d=(e??[]).filter(j=>j.staged===r);n(!0);try{const p=(await Promise.allSettled(d.map(u=>r?S(u.path):N(u.path)))).filter(u=>u.status==="rejected").length;p>0&&m({title:r?"Unstage failed":"Stage failed",description:`${p} of ${d.length} file(s) could not be updated.`,variant:"error"})}finally{await t(),n(!1)}},toggleStaged:async(d,j)=>{o(p=>new Set(p).add(d.path));try{await(j?N(d.path):S(d.path)),await t()}catch(p){m({title:j?"Stage failed":"Unstage failed",description:A(p.message),variant:"error"})}finally{o(p=>{const u=new Set(p);return u.delete(d.path),u})}}}},X=()=>{const e=h(n=>n.diffFiles),a=h(n=>n.diffLoadFailed),t=h(n=>n.loadDiffFiles),i=h(n=>n.setActiveDiffPath),l=x.useRef(null),o=x.useMemo(()=>(e==null?void 0:e.map(n=>({path:n.path,staged:n.staged})))??[],[e]),c=J(o);return x.useEffect(()=>{t()},[t]),x.useEffect(()=>{let n;const m=E(r=>{r.message==="changed"&&(n&&clearTimeout(n),n=setTimeout(t,250))}),f=()=>t();return window.addEventListener("focus",f),()=>{n&&clearTimeout(n),window.removeEventListener("focus",f),m()}},[t]),x.useEffect(()=>{const n=l.current;if(!n)return;const m=Array.from(n.querySelectorAll("[data-diff-path]"));if(m.length===0)return;const f=new Set,r=new IntersectionObserver(g=>{for(const d of g)d.isIntersecting?f.add(d.target):f.delete(d.target);const w=m.find(d=>f.has(d));w&&i(w.dataset.diffPath??null)},{rootMargin:"0px 0px -70% 0px"});for(const g of m)r.observe(g);return()=>r.disconnect()},[e,i]),{files:e,loadFailed:a,loadDiffFiles:t,sectionsRef:l,commitForm:c}},F=({additions:e,deletions:a})=>s.jsxs("span",{className:"inline-flex shrink-0 gap-1.5 font-mono text-3xs",children:[s.jsxs("span",{className:"text-watercolor-green-dark",children:["+",e]}),s.jsxs("span",{className:"text-watercolor-rose-dark",children:["-",a]})]}),Y=({path:e,prefix:a,className:t=""})=>{const{dir:i,base:l}=b(e),o=`${a??""}${i}`;return s.jsxs("span",{className:`flex min-w-0 items-center font-mono ${t}`,children:[o&&s.jsx("span",{className:"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50",children:o}),s.jsx("span",{className:"shrink-0 whitespace-nowrap",children:l})]})},Z={success:"text-watercolor-green-dark",info:"text-watercolor-blue-dark",error:"text-watercolor-rose-dark",warning:"text-watercolor-amber-dark",neutral:"text-watercolor-slate-dark"},ee={A:{letter:"A",label:"Added",variant:"success"},M:{letter:"M",label:"Modified",variant:"info"},D:{letter:"D",label:"Deleted",variant:"error"},R:{letter:"R",label:"Renamed",variant:"info"},C:{letter:"C",label:"Copied",variant:"info"},U:{letter:"U",label:"Conflicted",variant:"warning"}},se=e=>{if(e==="??")return{letter:"??",label:"Untracked",variant:"neutral"};const[a,t]=e,i=a!==" "&&a!=="?"?a:t;return ee[i]??{letter:i??"?",label:i??"Unknown",variant:"neutral"}},P=({status:e,compact:a=!1})=>{const t=se(e);return a?s.jsx("span",{title:t.label,className:`w-4 shrink-0 text-center font-mono text-3xs font-semibold leading-none ${Z[t.variant]??""}`,children:t.letter}):s.jsx("span",{title:t.label,children:s.jsx(v,{size:"small",variant:t.variant,children:t.letter})})},te=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;function ae(e){if(!e)return[];const a=(e.endsWith(`
2
2
  `)?e.slice(0,-1):e).split(`
3
3
  `),t=[];let i=null,l=0,o=0;for(const c of a){const n=c.match(te);if(n){i={header:c,lines:[]},t.push(i),l=Number(n[1]),o=Number(n[2]);continue}i&&(c.startsWith("\\")||(c.startsWith("+")?(i.lines.push({type:"add",text:c.slice(1),oldLine:null,newLine:o}),o++):c.startsWith("-")?(i.lines.push({type:"remove",text:c.slice(1),oldLine:l,newLine:null}),l++):(i.lines.push({type:"context",text:c.startsWith(" ")?c.slice(1):c,oldLine:l,newLine:o}),l++,o++)))}return t}function ie(e){return e?[{header:"",lines:(e.endsWith(`
4
4
  `)?e.slice(0,-1):e).split(`
5
5
  `).map((t,i)=>({type:"add",text:t,oldLine:null,newLine:i+1}))}]:[]}const ne=60,le={add:"bg-watercolor-green/[18%] text-watercolor-green-dark",remove:"bg-watercolor-rose/[18%] text-watercolor-rose-dark",context:""},oe={add:"+",remove:"-",context:" "},ce=({entry:e})=>s.jsxs("div",{className:"flex w-full min-w-0 items-center gap-3",children:[s.jsx(P,{status:e.status}),s.jsx(Y,{path:e.path,prefix:e.renameSource?`${e.renameSource} → `:void 0,className:"min-w-0 flex-1 text-xs"}),s.jsxs("span",{className:"flex shrink-0 items-center gap-2",children:[e.staged&&s.jsx(v,{size:"small",children:"staged"}),!e.binary&&s.jsx(F,{additions:e.additions,deletions:e.deletions})]})]}),re=({entry:e})=>{if(e.binary)return s.jsx("p",{className:"m-0 opacity-60",children:"Binary file not shown."});if(e.contentKind==="too-large")return s.jsx("p",{className:"m-0 opacity-60",children:"File too large to preview."});const a=e.contentKind==="raw"?ie(e.patch):ae(e.patch);return a.length===0?e.renameSource?s.jsx("p",{className:"m-0 opacity-60",children:e.additions===0&&e.deletions===0?"Renamed, no content changes.":"Renamed with unrelated content — diff omitted."}):s.jsx("p",{className:"m-0 opacity-60",children:"No changes to preview."}):s.jsx("div",{className:"flex min-w-0 max-w-full flex-col gap-3",children:a.map((t,i)=>s.jsxs("div",{className:"min-w-0 max-w-full",children:[t.header&&s.jsx("div",{className:"mb-1 font-mono text-2xs opacity-50",children:t.header}),s.jsx("pre",{className:"m-0 min-w-0 max-w-full overflow-x-auto font-mono text-2xs leading-normal",children:t.lines.map((l,o)=>s.jsxs("span",{className:`flex ${le[l.type]}`,children:[s.jsxs("span",{className:"inline-flex shrink-0 select-none gap-2 pr-2 opacity-40","aria-hidden":"true",children:[s.jsx("span",{className:"w-8 text-right",children:l.oldLine??""}),s.jsx("span",{className:"w-8 text-right",children:l.newLine??""})]}),s.jsxs("span",{children:[oe[l.type],l.text]})]},`${l.type}-${o}`))})]},`${t.header}-${i}`))})},de=({entry:e})=>{const a=h(c=>c.manuallyExpandedDiffPaths.has(e.path)),t=h(c=>c.manuallyCollapsedDiffPaths.has(e.path)),i=h(c=>c.setDiffCollapsed),l=t||!a&&e.additions+e.deletions>ne,o=e.renameSource?`${e.renameSource} → ${e.path}`:e.path;return s.jsxs("div",{"data-diff-path":e.path,className:"min-w-0 max-w-full scroll-mt-4",children:[s.jsx("h2",{className:"sr-only",children:o}),s.jsx(T,{title:s.jsx(ce,{entry:e}),expanded:!l,onToggle:()=>i(e.path,!l),children:s.jsx(re,{entry:e})})]})},fe="font-handwritten text-xs font-semibold leading-none opacity-[0.45]",me=(e,a)=>{a(e),requestAnimationFrame(()=>{var t;(t=document.querySelector(`[data-diff-path="${CSS.escape(e)}"]`))==null||t.scrollIntoView({behavior:"smooth",block:"start"})})},he=e=>{const[a,t]=e;return a!==" "&&a!=="?"&&t!==" "&&t!=="?"},pe=()=>{const{files:e,activePath:a,expandDiffPath:t,groups:i,pending:l,bulkPending:o,allStaged:c,toggleAll:n,toggleStaged:m}=V();return!e||e.length===0?null:s.jsxs("nav",{"aria-label":"Changed files",className:"flex flex-col",children:[s.jsxs("div",{className:`${fe} flex h-[32px] items-end justify-between pb-1`,children:[s.jsx("span",{children:"Changed files"}),s.jsx(k,{content:c?"Unstage every file":"Stage every file",children:s.jsx(R,{variant:"ghost",size:"tiny",className:"-mb-1",disabled:o,label:c?"Unstage all files":"Stage all files",onClick:n,icon:s.jsx(I,{})})})]}),s.jsx("ul",{className:"m-0 flex list-none flex-col p-0",children:i.map(f=>s.jsxs("li",{children:[s.jsx("div",{className:"flex h-[32px] items-end overflow-hidden text-ellipsis whitespace-nowrap pb-1 font-mono text-3xs leading-none opacity-50",title:f.dir,children:f.dir}),s.jsx("ul",{className:"m-0 flex list-none flex-col p-0",children:f.entries.map(r=>s.jsxs("li",{className:"pc-git-file-row flex h-[32px] min-w-0 items-end gap-1.5 pb-1",children:[s.jsx(_,{checked:r.staged,indeterminate:he(r.status),disabled:l.has(r.path),onChange:g=>m(r,g.target.checked),"aria-label":r.staged?`Unstage ${r.path}`:`Stage ${r.path}`}),s.jsx(P,{status:r.status,compact:!0}),s.jsx(G,{size:"small",active:r.path===a,onClick:()=>me(r.path,t),className:"min-w-0 flex-1 items-end py-0 text-3xs",action:!r.binary&&s.jsx(F,{additions:r.additions,deletions:r.deletions}),children:s.jsx("span",{className:"block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-mono text-3xs",title:r.path,children:b(r.path).base})})]},r.path))})]},f.dir))})]})},ue=()=>{const{files:e,loadFailed:a,loadDiffFiles:t,sectionsRef:i,commitForm:l}=X(),o="min-h-page",c=s.jsxs("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-x-4 gap-y-2",children:[s.jsx(z,{className:"!mb-0",children:"Git"}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(B,{}),s.jsx(H,{})]})]});return a?s.jsxs("div",{children:[c,s.jsxs("div",{className:`${o} flex flex-col items-start gap-3`,children:[s.jsx("p",{className:"opacity-50 m-0",children:"Couldn't load the working-tree diff."}),s.jsx(C,{variant:"secondary",size:"small",onClick:t,children:"Retry"})]})]}):e?s.jsxs("div",{children:[c,e.length===0?s.jsx("div",{className:o,children:s.jsx("p",{className:"opacity-50",children:"No changed files."})}):s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"sticky top-0 z-10 mb-4 flex items-center gap-2 py-2",children:[s.jsx("div",{className:"flex-1",children:s.jsx(U,{state:l,filesEmpty:!1})}),s.jsx(W,{state:l,filesEmpty:!1})]}),s.jsx("div",{ref:i,className:`flex min-w-0 flex-col gap-6 ${o}`,children:e.map((n,m)=>s.jsxs(x.Fragment,{children:[m>0&&s.jsx(O,{}),s.jsx(de,{entry:n})]},n.path))})]})]}):s.jsxs("div",{children:[c,s.jsx("div",{className:o,children:s.jsx(M,{label:"Loading the working-tree diff…"})})]})};export{pe as GitFileList,ue as GitPage};
6
- //# sourceMappingURL=index-CTHTRX-O.js.map
6
+ //# sourceMappingURL=index-Ddz2TPW1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-CTHTRX-O.js","sources":["../../../src/app/features/git/actions/git-commit-button.tsx","../../../src/app/features/git/hooks/use-git-commit-form.ts","../../../src/app/utils/path-display.ts","../../../src/app/features/git/hooks/use-git-file-list.ts","../../../src/app/features/git/hooks/use-git-page.ts","../../../src/app/features/git/components/count-badge.tsx","../../../src/app/features/git/components/file-path.tsx","../../../src/app/features/git/components/git-status-marker.tsx","../../../src/app/utils/parse-diff.ts","../../../src/app/features/git/views/file-diff-section.tsx","../../../src/app/features/git/views/git-file-list.tsx","../../../src/app/features/git/git-page.tsx"],"sourcesContent":["import type { GitCommitFormState } from '@/app/features/git/hooks';\nimport { useDeskChecks } from '@/app/hooks/use-desk-checks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { deriveCheckStatuses } from '@/app/utils/check-status';\nimport { Button, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useMemo } from 'react';\n\ninterface GitCommitButtonProps {\n state: GitCommitFormState;\n filesEmpty: boolean;\n}\n\n// Never Fix (plan-scoped, and the git page never has one) — a failing check is a warning instead.\nexport const GitCommitButton = ({ state, filesEmpty }: GitCommitButtonProps) => {\n const status = useAppStore((s) => s.status);\n const { checks: deskChecks } = useDeskChecks();\n const { qualityStatus, testStatus, consistencyStatus } = useMemo(\n () => deriveCheckStatuses(status, deskChecks),\n [status, deskChecks],\n );\n const failingChecks = [\n qualityStatus === 'fail' && 'Quality',\n testStatus === 'fail' && 'Tests',\n consistencyStatus === 'fail' && 'Consistency',\n ].filter((label): label is Exclude<typeof label, false> => label !== false);\n\n const commitButton = (\n <Button\n size=\"small\"\n disabled={filesEmpty || !state.commitTitle.trim() || state.committing || state.commitInFlight}\n onClick={state.handleCommit}\n >\n {state.committing || state.commitInFlight\n ? 'Committing…'\n : state.stagedCount > 0\n ? `Commit ${state.stagedCount} staged`\n : 'Commit'}\n </Button>\n );\n\n if (failingChecks.length === 0) return commitButton;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Tooltip content={`${failingChecks.join(', ')} failing`}>\n <Stamp size=\"small\" variant=\"warning\">\n !\n </Stamp>\n </Tooltip>\n {commitButton}\n </div>\n );\n};\n","import { type CommitFormFile, useCommitForm } from '@/app/hooks/use-commit-form';\n\n// Stable across renders — keeps drafts saved under the git page's key from being orphaned.\nconst GIT_PAGE_FORM_KEY = '__git__';\n\nconst matchAnySuggestionTask = () => true;\n\n// No plan on the git page, so this is bare commit mechanics — no phase recording, no Fix.\nexport const useGitCommitForm = (files: CommitFormFile[]) =>\n useCommitForm(files, {\n formKey: GIT_PAGE_FORM_KEY,\n matchesSuggestionTask: matchAnySuggestionTask,\n });\n\nexport type GitCommitFormState = ReturnType<typeof useGitCommitForm>;\n","export interface SplitPath {\n dir: string;\n base: string;\n}\n\nexport function splitPathForDisplay(path: string): SplitPath {\n const slash = path.lastIndexOf('/');\n return slash === -1\n ? { dir: '', base: path }\n : { dir: path.slice(0, slash + 1), base: path.slice(slash + 1) };\n}\n","import { stagePath, unstagePath } from '@/app/services/git-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport { splitPathForDisplay } from '@/app/utils/path-display';\nimport type { FileDiffEntry } from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useMemo, useState } from 'react';\n\nfunction groupByFolder(files: FileDiffEntry[]): { dir: string; entries: FileDiffEntry[] }[] {\n const groups = new Map<string, FileDiffEntry[]>();\n for (const entry of files) {\n const { dir } = splitPathForDisplay(entry.path);\n const key = dir || './';\n const bucket = groups.get(key);\n if (bucket) bucket.push(entry);\n else groups.set(key, [entry]);\n }\n return [...groups].map(([dir, entries]) => ({ dir, entries }));\n}\n\nexport const useGitFileList = () => {\n const files = useAppStore((s) => s.diffFiles);\n const activePath = useAppStore((s) => s.activeDiffPath);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const expandDiffPath = useAppStore((s) => s.expandDiffPath);\n const [pending, setPending] = useState<Set<string>>(new Set());\n const [bulkPending, setBulkPending] = useState(false);\n const { toast } = useToast();\n const groups = useMemo(() => groupByFolder(files ?? []), [files]);\n const allStaged = (files ?? []).length > 0 && (files ?? []).every((f) => f.staged);\n\n // No bulk endpoint: fans out over per-path calls and reloads once at the end, so a\n // partial failure still reports and whatever landed shows up in that single reload.\n const toggleAll = async () => {\n const targets = (files ?? []).filter((f) => f.staged === allStaged);\n setBulkPending(true);\n try {\n const results = await Promise.allSettled(\n targets.map((f) => (allStaged ? unstagePath(f.path) : stagePath(f.path))),\n );\n const failed = results.filter((r) => r.status === 'rejected').length;\n if (failed > 0) {\n toast({\n title: allStaged ? 'Unstage failed' : 'Stage failed',\n description: `${failed} of ${targets.length} file(s) could not be updated.`,\n variant: 'error',\n });\n }\n } finally {\n await loadDiffFiles();\n setBulkPending(false);\n }\n };\n\n const toggleStaged = async (entry: FileDiffEntry, next: boolean) => {\n setPending((prev) => new Set(prev).add(entry.path));\n try {\n await (next ? stagePath(entry.path) : unstagePath(entry.path));\n await loadDiffFiles();\n } catch (err) {\n toast({\n title: next ? 'Stage failed' : 'Unstage failed',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n } finally {\n setPending((prev) => {\n const updated = new Set(prev);\n updated.delete(entry.path);\n return updated;\n });\n }\n };\n\n return {\n files,\n activePath,\n expandDiffPath,\n groups,\n pending,\n bulkPending,\n allStaged,\n toggleAll,\n toggleStaged,\n };\n};\n","import { useGitCommitForm } from '@/app/features/git/hooks/use-git-commit-form';\nimport { subscribeToActivityStream } from '@/app/services/activity-stream';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useEffect, useMemo, useRef } from 'react';\n\nexport const useGitPage = () => {\n const files = useAppStore((s) => s.diffFiles);\n const loadFailed = useAppStore((s) => s.diffLoadFailed);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const setActiveDiffPath = useAppStore((s) => s.setActiveDiffPath);\n const sectionsRef = useRef<HTMLDivElement>(null);\n const commitFiles = useMemo(\n () => files?.map((entry) => ({ path: entry.path, staged: entry.staged })) ?? [],\n [files],\n );\n const commitForm = useGitCommitForm(commitFiles);\n\n useEffect(() => {\n loadDiffFiles();\n }, [loadDiffFiles]);\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const unsubscribe = subscribeToActivityStream((payload) => {\n if (payload.message !== 'changed') return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(loadDiffFiles, 250);\n });\n const onFocus = () => loadDiffFiles();\n window.addEventListener('focus', onFocus);\n return () => {\n if (timer) clearTimeout(timer);\n window.removeEventListener('focus', onFocus);\n unsubscribe();\n };\n }, [loadDiffFiles]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: files is the trigger to rebuild the observer, not a value read in the body.\n useEffect(() => {\n const root = sectionsRef.current;\n if (!root) return;\n const sections = Array.from(root.querySelectorAll<HTMLElement>('[data-diff-path]'));\n if (sections.length === 0) return;\n const visible = new Set<HTMLElement>();\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) visible.add(entry.target as HTMLElement);\n else visible.delete(entry.target as HTMLElement);\n }\n const topmost = sections.find((el) => visible.has(el));\n if (topmost) setActiveDiffPath(topmost.dataset.diffPath ?? null);\n },\n { rootMargin: '0px 0px -70% 0px' },\n );\n for (const el of sections) observer.observe(el);\n return () => observer.disconnect();\n }, [files, setActiveDiffPath]);\n\n return {\n files,\n loadFailed,\n loadDiffFiles,\n sectionsRef,\n commitForm,\n };\n};\n\nexport type GitPageState = ReturnType<typeof useGitPage>;\n","interface CountBadgeProps {\n additions: number;\n deletions: number;\n}\n\nexport const CountBadge = ({ additions, deletions }: CountBadgeProps) => (\n <span className=\"inline-flex shrink-0 gap-1.5 font-mono text-3xs\">\n <span className=\"text-watercolor-green-dark\">+{additions}</span>\n <span className=\"text-watercolor-rose-dark\">-{deletions}</span>\n </span>\n);\n","import { splitPathForDisplay } from '@/app/utils/path-display';\n\ninterface FilePathProps {\n path: string;\n prefix?: string;\n className?: string;\n}\n\nexport const FilePath = ({ path, prefix, className = '' }: FilePathProps) => {\n const { dir, base } = splitPathForDisplay(path);\n const dimmed = `${prefix ?? ''}${dir}`;\n return (\n <span className={`flex min-w-0 items-center font-mono ${className}`}>\n {dimmed && (\n <span className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50\">\n {dimmed}\n </span>\n )}\n <span className=\"shrink-0 whitespace-nowrap\">{base}</span>\n </span>\n );\n};\n","import { Stamp, type StampVariant } from '@dendelion/paper-ui';\n\ninterface StatusInfo {\n letter: string;\n label: string;\n variant: StampVariant;\n}\n\n// Compact rows can't spare the ~39px a Stamp's blob costs for one letter; the colour\n// alone carries the same meaning in a fraction of the width.\nconst COMPACT_COLOR: Record<StampVariant, string> = {\n success: 'text-watercolor-green-dark',\n info: 'text-watercolor-blue-dark',\n error: 'text-watercolor-rose-dark',\n warning: 'text-watercolor-amber-dark',\n neutral: 'text-watercolor-slate-dark',\n};\n\nconst STATUS_INFO: Record<string, StatusInfo> = {\n A: { letter: 'A', label: 'Added', variant: 'success' },\n M: { letter: 'M', label: 'Modified', variant: 'info' },\n D: { letter: 'D', label: 'Deleted', variant: 'error' },\n R: { letter: 'R', label: 'Renamed', variant: 'info' },\n C: { letter: 'C', label: 'Copied', variant: 'info' },\n U: { letter: 'U', label: 'Conflicted', variant: 'warning' },\n};\n\n// Git's porcelain code is two characters: index status then worktree status.\n// The index one wins when both are set — it's the state that would actually commit.\nexport const gitStatusInfo = (status: string): StatusInfo => {\n if (status === '??') return { letter: '??', label: 'Untracked', variant: 'neutral' };\n const [x, y] = status;\n const code = x !== ' ' && x !== '?' ? x : y;\n return STATUS_INFO[code] ?? { letter: code ?? '?', label: code ?? 'Unknown', variant: 'neutral' };\n};\n\ninterface GitStatusMarkerProps {\n status: string;\n compact?: boolean;\n}\n\nexport const GitStatusMarker = ({ status, compact = false }: GitStatusMarkerProps) => {\n const info = gitStatusInfo(status);\n if (compact) {\n return (\n <span\n title={info.label}\n className={`w-4 shrink-0 text-center font-mono text-3xs font-semibold leading-none ${COMPACT_COLOR[info.variant] ?? ''}`}\n >\n {info.letter}\n </span>\n );\n }\n return (\n <span title={info.label}>\n <Stamp size=\"small\" variant={info.variant}>\n {info.letter}\n </Stamp>\n </span>\n );\n};\n","export type DiffLineType = 'add' | 'remove' | 'context';\n\nexport interface DiffLine {\n type: DiffLineType;\n text: string;\n oldLine: number | null;\n newLine: number | null;\n}\n\nexport interface DiffHunk {\n header: string;\n lines: DiffLine[];\n}\n\nconst HUNK_HEADER = /^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/;\n\n// Parses a unified diff (git.ts getWorkingDiff, contentKind: 'diff'). A real diff\n// with no hunks (pure rename, mode-only change) is just the preamble, so it yields [].\nexport function parsePatch(patch: string): DiffHunk[] {\n if (!patch) return [];\n const lines = (patch.endsWith('\\n') ? patch.slice(0, -1) : patch).split('\\n');\n\n const hunks: DiffHunk[] = [];\n let current: DiffHunk | null = null;\n let oldLine = 0;\n let newLine = 0;\n for (const line of lines) {\n const header = line.match(HUNK_HEADER);\n if (header) {\n current = { header: line, lines: [] };\n hunks.push(current);\n oldLine = Number(header[1]);\n newLine = Number(header[2]);\n continue;\n }\n if (!current) continue; // preamble: diff --git / index / --- / +++\n if (line.startsWith('\\\\')) continue; // \"\\"\n if (line.startsWith('+')) {\n current.lines.push({ type: 'add', text: line.slice(1), oldLine: null, newLine });\n newLine++;\n } else if (line.startsWith('-')) {\n current.lines.push({ type: 'remove', text: line.slice(1), oldLine, newLine: null });\n oldLine++;\n } else {\n current.lines.push({\n type: 'context',\n text: line.startsWith(' ') ? line.slice(1) : line,\n oldLine,\n newLine,\n });\n oldLine++;\n newLine++;\n }\n }\n return hunks;\n}\n\n// Untracked files store raw content, not a diff (git.ts getWorkingDiff, contentKind:\n// 'raw') — synthesize a single all-added hunk so the renderer only has one shape to draw.\nexport function rawContentHunks(content: string): DiffHunk[] {\n if (!content) return [];\n const lines = (content.endsWith('\\n') ? content.slice(0, -1) : content).split('\\n');\n return [\n {\n header: '',\n lines: lines.map((text, i) => ({ type: 'add', text, oldLine: null, newLine: i + 1 })),\n },\n ];\n}\n","import { CountBadge, FilePath, GitStatusMarker } from '@/app/features/git/components';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { type DiffLineType, parsePatch, rawContentHunks } from '@/app/utils/parse-diff';\nimport type { FileDiffEntry } from '@/types/index';\nimport { Accordion, Stamp } from '@dendelion/paper-ui';\n\nconst COLLAPSE_LINE_THRESHOLD = 60;\n\nconst LINE_CLASS: Record<DiffLineType, string> = {\n add: 'bg-watercolor-green/[18%] text-watercolor-green-dark',\n remove: 'bg-watercolor-rose/[18%] text-watercolor-rose-dark',\n context: '',\n};\n\nconst LINE_PREFIX: Record<DiffLineType, string> = { add: '+', remove: '-', context: ' ' };\n\ninterface FileHeaderProps {\n entry: FileDiffEntry;\n}\n\nconst FileHeader = ({ entry }: FileHeaderProps) => (\n <div className=\"flex w-full min-w-0 items-center gap-3\">\n <GitStatusMarker status={entry.status} />\n <FilePath\n path={entry.path}\n prefix={entry.renameSource ? `${entry.renameSource} → ` : undefined}\n className=\"min-w-0 flex-1 text-xs\"\n />\n <span className=\"flex shrink-0 items-center gap-2\">\n {entry.staged && <Stamp size=\"small\">staged</Stamp>}\n {!entry.binary && <CountBadge additions={entry.additions} deletions={entry.deletions} />}\n </span>\n </div>\n);\n\ninterface DiffBodyProps {\n entry: FileDiffEntry;\n}\n\nconst DiffBody = ({ entry }: DiffBodyProps) => {\n if (entry.binary) {\n return <p className=\"m-0 opacity-60\">Binary file not shown.</p>;\n }\n if (entry.contentKind === 'too-large') {\n return <p className=\"m-0 opacity-60\">File too large to preview.</p>;\n }\n const hunks =\n entry.contentKind === 'raw' ? rawContentHunks(entry.patch) : parsePatch(entry.patch);\n if (hunks.length === 0) {\n if (entry.renameSource) {\n return (\n <p className=\"m-0 opacity-60\">\n {entry.additions === 0 && entry.deletions === 0\n ? 'Renamed, no content changes.'\n : 'Renamed with unrelated content — diff omitted.'}\n </p>\n );\n }\n return <p className=\"m-0 opacity-60\">No changes to preview.</p>;\n }\n return (\n <div className=\"flex min-w-0 max-w-full flex-col gap-3\">\n {hunks.map((hunk, i) => (\n <div key={`${hunk.header}-${i}`} className=\"min-w-0 max-w-full\">\n {hunk.header && <div className=\"mb-1 font-mono text-2xs opacity-50\">{hunk.header}</div>}\n {/* paper-ui's CodeBlock has no per-line add/remove styling. */}\n <pre className=\"m-0 min-w-0 max-w-full overflow-x-auto font-mono text-2xs leading-normal\">\n {hunk.lines.map((line, j) => (\n <span key={`${line.type}-${j}`} className={`flex ${LINE_CLASS[line.type]}`}>\n <span\n className=\"inline-flex shrink-0 select-none gap-2 pr-2 opacity-40\"\n aria-hidden=\"true\"\n >\n <span className=\"w-8 text-right\">{line.oldLine ?? ''}</span>\n <span className=\"w-8 text-right\">{line.newLine ?? ''}</span>\n </span>\n <span>\n {LINE_PREFIX[line.type]}\n {line.text}\n </span>\n </span>\n ))}\n </pre>\n </div>\n ))}\n </div>\n );\n};\n\ninterface FileDiffSectionProps {\n entry: FileDiffEntry;\n}\n\nexport const FileDiffSection = ({ entry }: FileDiffSectionProps) => {\n const manuallyExpanded = useAppStore((s) => s.manuallyExpandedDiffPaths.has(entry.path));\n const manuallyCollapsed = useAppStore((s) => s.manuallyCollapsedDiffPaths.has(entry.path));\n const setDiffCollapsed = useAppStore((s) => s.setDiffCollapsed);\n const collapsed =\n manuallyCollapsed ||\n (!manuallyExpanded && entry.additions + entry.deletions > COLLAPSE_LINE_THRESHOLD);\n\n const headingText = entry.renameSource ? `${entry.renameSource} → ${entry.path}` : entry.path;\n\n return (\n <div data-diff-path={entry.path} className=\"min-w-0 max-w-full scroll-mt-4\">\n <h2 className=\"sr-only\">{headingText}</h2>\n <Accordion\n title={<FileHeader entry={entry} />}\n expanded={!collapsed}\n onToggle={() => setDiffCollapsed(entry.path, !collapsed)}\n >\n <DiffBody entry={entry} />\n </Accordion>\n </div>\n );\n};\n","import { CheckAllIcon } from '@/app/components/icons';\nimport { CountBadge, GitStatusMarker } from '@/app/features/git/components';\nimport { useGitFileList } from '@/app/features/git/hooks';\nimport { splitPathForDisplay } from '@/app/utils/path-display';\nimport { Checkbox, IconButton, ListItem, Tooltip } from '@dendelion/paper-ui';\n\nconst sectionLabelClass = 'font-handwritten text-xs font-semibold leading-none opacity-[0.45]';\n\nconst scrollToFile = (path: string, expandDiffPath: (path: string) => void) => {\n expandDiffPath(path);\n requestAnimationFrame(() => {\n document\n .querySelector(`[data-diff-path=\"${CSS.escape(path)}\"]`)\n ?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n};\n\n// Both status characters set (and neither '?', which pairs up for untracked) means\n// part of the file is staged and part isn't — git can't be checked or unchecked.\nconst isPartiallyStaged = (status: string) => {\n const [x, y] = status;\n return x !== ' ' && x !== '?' && y !== ' ' && y !== '?';\n};\n\nexport const GitFileList = () => {\n const {\n files,\n activePath,\n expandDiffPath,\n groups,\n pending,\n bulkPending,\n allStaged,\n toggleAll,\n toggleStaged,\n } = useGitFileList();\n\n if (!files || files.length === 0) return null;\n\n return (\n <nav aria-label=\"Changed files\" className=\"flex flex-col\">\n <div className={`${sectionLabelClass} flex h-[32px] items-end justify-between pb-1`}>\n <span>Changed files</span>\n <Tooltip content={allStaged ? 'Unstage every file' : 'Stage every file'}>\n <IconButton\n variant=\"ghost\"\n size=\"tiny\"\n className=\"-mb-1\"\n disabled={bulkPending}\n label={allStaged ? 'Unstage all files' : 'Stage all files'}\n onClick={toggleAll}\n icon={<CheckAllIcon />}\n />\n </Tooltip>\n </div>\n {/* Every row is exactly one 32px cell so the list tracks the ruled background. */}\n <ul className=\"m-0 flex list-none flex-col p-0\">\n {groups.map((group) => (\n <li key={group.dir}>\n <div\n className=\"flex h-[32px] items-end overflow-hidden text-ellipsis whitespace-nowrap pb-1 font-mono text-3xs leading-none opacity-50\"\n title={group.dir}\n >\n {group.dir}\n </div>\n <ul className=\"m-0 flex list-none flex-col p-0\">\n {group.entries.map((entry) => (\n <li\n key={entry.path}\n className=\"pc-git-file-row flex h-[32px] min-w-0 items-end gap-1.5 pb-1\"\n >\n <Checkbox\n checked={entry.staged}\n indeterminate={isPartiallyStaged(entry.status)}\n disabled={pending.has(entry.path)}\n onChange={(e) => toggleStaged(entry, e.target.checked)}\n aria-label={entry.staged ? `Unstage ${entry.path}` : `Stage ${entry.path}`}\n />\n <GitStatusMarker status={entry.status} compact />\n <ListItem\n size=\"small\"\n active={entry.path === activePath}\n onClick={() => scrollToFile(entry.path, expandDiffPath)}\n className=\"min-w-0 flex-1 items-end py-0 text-3xs\"\n action={\n !entry.binary && (\n <CountBadge additions={entry.additions} deletions={entry.deletions} />\n )\n }\n >\n <span\n className=\"block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-mono text-3xs\"\n title={entry.path}\n >\n {splitPathForDisplay(entry.path).base}\n </span>\n </ListItem>\n </li>\n ))}\n </ul>\n </li>\n ))}\n </ul>\n </nav>\n );\n};\n","import { CommitMessageFields, GitStashSurface, GitSyncActions } from '@/app/components';\nimport { PageTitle } from '@/app/components/page-title';\nimport { GitCommitButton } from '@/app/features/git/actions';\nimport { useGitPage } from '@/app/features/git/hooks';\nimport { FileDiffSection } from '@/app/features/git/views';\nimport { Button, Divider, Spinner } from '@dendelion/paper-ui';\nimport { Fragment } from 'react';\n\nexport const GitPage = () => {\n const { files, loadFailed, loadDiffFiles, sectionsRef, commitForm } = useGitPage();\n\n const contentClass = 'min-h-page';\n\n const header = (\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-x-4 gap-y-2\">\n <PageTitle className=\"!mb-0\">Git</PageTitle>\n <div className=\"flex items-center gap-2\">\n <GitSyncActions />\n <GitStashSurface />\n </div>\n </div>\n );\n\n if (loadFailed) {\n return (\n <div>\n {header}\n <div className={`${contentClass} flex flex-col items-start gap-3`}>\n <p className=\"opacity-50 m-0\">Couldn't load the working-tree diff.</p>\n <Button variant=\"secondary\" size=\"small\" onClick={loadDiffFiles}>\n Retry\n </Button>\n </div>\n </div>\n );\n }\n\n if (!files) {\n return (\n <div>\n {header}\n <div className={contentClass}>\n <Spinner label=\"Loading the working-tree diff…\" />\n </div>\n </div>\n );\n }\n\n return (\n <div>\n {header}\n {files.length === 0 ? (\n <div className={contentClass}>\n <p className=\"opacity-50\">No changed files.</p>\n </div>\n ) : (\n <>\n <div className=\"sticky top-0 z-10 mb-4 flex items-center gap-2 py-2\">\n <div className=\"flex-1\">\n <CommitMessageFields state={commitForm} filesEmpty={false} />\n </div>\n <GitCommitButton state={commitForm} filesEmpty={false} />\n </div>\n <div ref={sectionsRef} className={`flex min-w-0 flex-col gap-6 ${contentClass}`}>\n {files.map((entry, idx) => (\n <Fragment key={entry.path}>\n {idx > 0 && <Divider />}\n <FileDiffSection entry={entry} />\n </Fragment>\n ))}\n </div>\n </>\n )}\n </div>\n );\n};\n"],"names":["GitCommitButton","state","filesEmpty","status","useAppStore","s","deskChecks","useDeskChecks","qualityStatus","testStatus","consistencyStatus","useMemo","deriveCheckStatuses","failingChecks","label","commitButton","jsx","Button","jsxs","Tooltip","Stamp","GIT_PAGE_FORM_KEY","matchAnySuggestionTask","useGitCommitForm","files","useCommitForm","splitPathForDisplay","path","slash","groupByFolder","groups","entry","dir","key","bucket","entries","useGitFileList","activePath","loadDiffFiles","expandDiffPath","pending","setPending","useState","bulkPending","setBulkPending","toast","useToast","allStaged","f","targets","failed","unstagePath","stagePath","r","next","prev","err","oneLineErrorSummary","updated","useGitPage","loadFailed","setActiveDiffPath","sectionsRef","useRef","commitFiles","commitForm","useEffect","timer","unsubscribe","subscribeToActivityStream","payload","onFocus","root","sections","visible","observer","topmost","el","CountBadge","additions","deletions","FilePath","prefix","className","base","dimmed","COMPACT_COLOR","STATUS_INFO","gitStatusInfo","x","y","code","GitStatusMarker","compact","info","HUNK_HEADER","parsePatch","patch","lines","hunks","current","oldLine","newLine","line","header","rawContentHunks","content","text","COLLAPSE_LINE_THRESHOLD","LINE_CLASS","LINE_PREFIX","FileHeader","DiffBody","hunk","j","FileDiffSection","manuallyExpanded","manuallyCollapsed","setDiffCollapsed","collapsed","headingText","Accordion","sectionLabelClass","scrollToFile","_a","isPartiallyStaged","GitFileList","toggleAll","toggleStaged","IconButton","CheckAllIcon","group","Checkbox","e","ListItem","GitPage","contentClass","PageTitle","GitSyncActions","GitStashSurface","Fragment","CommitMessageFields","idx","Divider","Spinner"],"mappings":"6NAaO,MAAMA,EAAkB,CAAC,CAAE,MAAAC,EAAO,WAAAC,KAAuC,CAC9E,MAAMC,EAASC,EAAaC,GAAMA,EAAE,MAAM,EACpC,CAAE,OAAQC,CAAA,EAAeC,EAAA,EACzB,CAAE,cAAAC,EAAe,WAAAC,EAAY,kBAAAC,CAAA,EAAsBC,EAAAA,QACvD,IAAMC,EAAoBT,EAAQG,CAAU,EAC5C,CAACH,EAAQG,CAAU,CAAA,EAEfO,EAAgB,CACpBL,IAAkB,QAAU,UAC5BC,IAAe,QAAU,QACzBC,IAAsB,QAAU,aAAA,EAChC,OAAQI,GAAiDA,IAAU,EAAK,EAEpEC,EACJC,EAAAA,IAACC,EAAA,CACC,KAAK,QACL,SAAUf,GAAc,CAACD,EAAM,YAAY,KAAA,GAAUA,EAAM,YAAcA,EAAM,eAC/E,QAASA,EAAM,aAEd,SAAAA,EAAM,YAAcA,EAAM,eACvB,cACAA,EAAM,YAAc,EAClB,UAAUA,EAAM,WAAW,UAC3B,QAAA,CAAA,EAIV,OAAIY,EAAc,SAAW,EAAUE,EAGrCG,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAF,MAACG,EAAA,CAAQ,QAAS,GAAGN,EAAc,KAAK,IAAI,CAAC,WAC3C,SAAAG,EAAAA,IAACI,GAAM,KAAK,QAAQ,QAAQ,UAAU,aAEtC,EACF,EACCL,CAAA,EACH,CAEJ,ECjDMM,EAAoB,UAEpBC,EAAyB,IAAM,GAGxBC,EAAoBC,GAC/BC,EAAcD,EAAO,CACnB,QAASH,EACT,sBAAuBC,CACzB,CAAC,ECPI,SAASI,EAAoBC,EAAyB,CAC3D,MAAMC,EAAQD,EAAK,YAAY,GAAG,EAClC,OAAOC,IAAU,GACb,CAAE,IAAK,GAAI,KAAMD,GACjB,CAAE,IAAKA,EAAK,MAAM,EAAGC,EAAQ,CAAC,EAAG,KAAMD,EAAK,MAAMC,EAAQ,CAAC,CAAA,CACjE,CCFA,SAASC,EAAcL,EAAqE,CAC1F,MAAMM,MAAa,IACnB,UAAWC,KAASP,EAAO,CACzB,KAAM,CAAE,IAAAQ,CAAA,EAAQN,EAAoBK,EAAM,IAAI,EACxCE,EAAMD,GAAO,KACbE,EAASJ,EAAO,IAAIG,CAAG,EACzBC,EAAQA,EAAO,KAAKH,CAAK,EACxBD,EAAO,IAAIG,EAAK,CAACF,CAAK,CAAC,CAC9B,CACA,MAAO,CAAC,GAAGD,CAAM,EAAE,IAAI,CAAC,CAACE,EAAKG,CAAO,KAAO,CAAE,IAAAH,EAAK,QAAAG,GAAU,CAC/D,CAEO,MAAMC,EAAiB,IAAM,CAClC,MAAMZ,EAAQpB,EAAaC,GAAMA,EAAE,SAAS,EACtCgC,EAAajC,EAAaC,GAAMA,EAAE,cAAc,EAChDiC,EAAgBlC,EAAaC,GAAMA,EAAE,aAAa,EAClDkC,EAAiBnC,EAAaC,GAAMA,EAAE,cAAc,EACpD,CAACmC,EAASC,CAAU,EAAIC,EAAAA,SAAsB,IAAI,GAAK,EACvD,CAACC,EAAaC,CAAc,EAAIF,EAAAA,SAAS,EAAK,EAC9C,CAAE,MAAAG,CAAA,EAAUC,EAAA,EACZhB,EAASnB,EAAAA,QAAQ,IAAMkB,EAAcL,GAAS,EAAE,EAAG,CAACA,CAAK,CAAC,EAC1DuB,GAAavB,GAAS,CAAA,GAAI,OAAS,IAAMA,GAAS,CAAA,GAAI,MAAOwB,GAAMA,EAAE,MAAM,EA6CjF,MAAO,CACL,MAAAxB,EACA,WAAAa,EACA,eAAAE,EACA,OAAAT,EACA,QAAAU,EACA,YAAAG,EACA,UAAAI,EACA,UAjDgB,SAAY,CAC5B,MAAME,GAAWzB,GAAS,IAAI,OAAQwB,GAAMA,EAAE,SAAWD,CAAS,EAClEH,EAAe,EAAI,EACnB,GAAI,CAIF,MAAMM,GAHU,MAAM,QAAQ,WAC5BD,EAAQ,IAAKD,GAAOD,EAAYI,EAAYH,EAAE,IAAI,EAAII,EAAUJ,EAAE,IAAI,CAAE,CAAA,GAEnD,OAAQK,GAAMA,EAAE,SAAW,UAAU,EAAE,OAC1DH,EAAS,GACXL,EAAM,CACJ,MAAOE,EAAY,iBAAmB,eACtC,YAAa,GAAGG,CAAM,OAAOD,EAAQ,MAAM,iCAC3C,QAAS,OAAA,CACV,CAEL,QAAA,CACE,MAAMX,EAAA,EACNM,EAAe,EAAK,CACtB,CACF,EA+BE,aA7BmB,MAAOb,EAAsBuB,IAAkB,CAClEb,EAAYc,GAAS,IAAI,IAAIA,CAAI,EAAE,IAAIxB,EAAM,IAAI,CAAC,EAClD,GAAI,CACF,MAAOuB,EAAOF,EAAUrB,EAAM,IAAI,EAAIoB,EAAYpB,EAAM,IAAI,GAC5D,MAAMO,EAAA,CACR,OAASkB,EAAK,CACZX,EAAM,CACJ,MAAOS,EAAO,eAAiB,iBAC/B,YAAaG,EAAqBD,EAAc,OAAO,EACvD,QAAS,OAAA,CACV,CACH,QAAA,CACEf,EAAYc,GAAS,CACnB,MAAMG,EAAU,IAAI,IAAIH,CAAI,EAC5B,OAAAG,EAAQ,OAAO3B,EAAM,IAAI,EAClB2B,CACT,CAAC,CACH,CACF,CAWE,CAEJ,EChFaC,EAAa,IAAM,CAC9B,MAAMnC,EAAQpB,EAAaC,GAAMA,EAAE,SAAS,EACtCuD,EAAaxD,EAAaC,GAAMA,EAAE,cAAc,EAChDiC,EAAgBlC,EAAaC,GAAMA,EAAE,aAAa,EAClDwD,EAAoBzD,EAAaC,GAAMA,EAAE,iBAAiB,EAC1DyD,EAAcC,EAAAA,OAAuB,IAAI,EACzCC,EAAcrD,EAAAA,QAClB,KAAMa,GAAA,YAAAA,EAAO,IAAKO,IAAW,CAAE,KAAMA,EAAM,KAAM,OAAQA,EAAM,MAAA,MAAc,CAAA,EAC7E,CAACP,CAAK,CAAA,EAEFyC,EAAa1C,EAAiByC,CAAW,EAE/CE,OAAAA,EAAAA,UAAU,IAAM,CACd5B,EAAA,CACF,EAAG,CAACA,CAAa,CAAC,EAElB4B,EAAAA,UAAU,IAAM,CACd,IAAIC,EACJ,MAAMC,EAAcC,EAA2BC,GAAY,CACrDA,EAAQ,UAAY,YACpBH,gBAAoBA,CAAK,EAC7BA,EAAQ,WAAW7B,EAAe,GAAG,EACvC,CAAC,EACKiC,EAAU,IAAMjC,EAAA,EACtB,cAAO,iBAAiB,QAASiC,CAAO,EACjC,IAAM,CACPJ,gBAAoBA,CAAK,EAC7B,OAAO,oBAAoB,QAASI,CAAO,EAC3CH,EAAA,CACF,CACF,EAAG,CAAC9B,CAAa,CAAC,EAGlB4B,EAAAA,UAAU,IAAM,CACd,MAAMM,EAAOV,EAAY,QACzB,GAAI,CAACU,EAAM,OACX,MAAMC,EAAW,MAAM,KAAKD,EAAK,iBAA8B,kBAAkB,CAAC,EAClF,GAAIC,EAAS,SAAW,EAAG,OAC3B,MAAMC,MAAc,IACdC,EAAW,IAAI,qBAClBxC,GAAY,CACX,UAAWJ,KAASI,EACdJ,EAAM,eAAgB2C,EAAQ,IAAI3C,EAAM,MAAqB,EAC5D2C,EAAQ,OAAO3C,EAAM,MAAqB,EAEjD,MAAM6C,EAAUH,EAAS,KAAMI,GAAOH,EAAQ,IAAIG,CAAE,CAAC,EACjDD,GAASf,EAAkBe,EAAQ,QAAQ,UAAY,IAAI,CACjE,EACA,CAAE,WAAY,kBAAA,CAAmB,EAEnC,UAAWC,KAAMJ,EAAUE,EAAS,QAAQE,CAAE,EAC9C,MAAO,IAAMF,EAAS,WAAA,CACxB,EAAG,CAACnD,EAAOqC,CAAiB,CAAC,EAEtB,CACL,MAAArC,EACA,WAAAoC,EACA,cAAAtB,EACA,YAAAwB,EACA,WAAAG,CAAA,CAEJ,EC7Daa,EAAa,CAAC,CAAE,UAAAC,EAAW,UAAAC,KACtC9D,OAAC,OAAA,CAAK,UAAU,kDACd,SAAA,CAAAA,EAAAA,KAAC,OAAA,CAAK,UAAU,6BAA6B,SAAA,CAAA,IAAE6D,CAAA,EAAU,EACzD7D,EAAAA,KAAC,OAAA,CAAK,UAAU,4BAA4B,SAAA,CAAA,IAAE8D,CAAA,CAAA,CAAU,CAAA,EAC1D,ECDWC,EAAW,CAAC,CAAE,KAAAtD,EAAM,OAAAuD,EAAQ,UAAAC,EAAY,MAAwB,CAC3E,KAAM,CAAE,IAAAnD,EAAK,KAAAoD,GAAS1D,EAAoBC,CAAI,EACxC0D,EAAS,GAAGH,GAAU,EAAE,GAAGlD,CAAG,GACpC,OACEd,EAAAA,KAAC,OAAA,CAAK,UAAW,uCAAuCiE,CAAS,GAC9D,SAAA,CAAAE,GACCrE,EAAAA,IAAC,OAAA,CAAK,UAAU,qEACb,SAAAqE,EACH,EAEFrE,EAAAA,IAAC,OAAA,CAAK,UAAU,6BAA8B,SAAAoE,CAAA,CAAK,CAAA,EACrD,CAEJ,ECXME,EAA8C,CAClD,QAAS,6BACT,KAAM,4BACN,MAAO,4BACP,QAAS,6BACT,QAAS,4BACX,EAEMC,GAA0C,CAC9C,EAAG,CAAE,OAAQ,IAAK,MAAO,QAAS,QAAS,SAAA,EAC3C,EAAG,CAAE,OAAQ,IAAK,MAAO,WAAY,QAAS,MAAA,EAC9C,EAAG,CAAE,OAAQ,IAAK,MAAO,UAAW,QAAS,OAAA,EAC7C,EAAG,CAAE,OAAQ,IAAK,MAAO,UAAW,QAAS,MAAA,EAC7C,EAAG,CAAE,OAAQ,IAAK,MAAO,SAAU,QAAS,MAAA,EAC5C,EAAG,CAAE,OAAQ,IAAK,MAAO,aAAc,QAAS,SAAA,CAClD,EAIaC,GAAiBrF,GAA+B,CAC3D,GAAIA,IAAW,KAAM,MAAO,CAAE,OAAQ,KAAM,MAAO,YAAa,QAAS,SAAA,EACzE,KAAM,CAACsF,EAAGC,CAAC,EAAIvF,EACTwF,EAAOF,IAAM,KAAOA,IAAM,IAAMA,EAAIC,EAC1C,OAAOH,GAAYI,CAAI,GAAK,CAAE,OAAQA,GAAQ,IAAK,MAAOA,GAAQ,UAAW,QAAS,SAAA,CACxF,EAOaC,EAAkB,CAAC,CAAE,OAAAzF,EAAQ,QAAA0F,EAAU,MAAkC,CACpF,MAAMC,EAAON,GAAcrF,CAAM,EACjC,OAAI0F,EAEA7E,EAAAA,IAAC,OAAA,CACC,MAAO8E,EAAK,MACZ,UAAW,0EAA0ER,EAAcQ,EAAK,OAAO,GAAK,EAAE,GAErH,SAAAA,EAAK,MAAA,CAAA,EAKV9E,EAAAA,IAAC,OAAA,CAAK,MAAO8E,EAAK,MAChB,SAAA9E,EAAAA,IAACI,EAAA,CAAM,KAAK,QAAQ,QAAS0E,EAAK,QAC/B,SAAAA,EAAK,OACR,EACF,CAEJ,EC9CMC,GAAc,0CAIb,SAASC,GAAWC,EAA2B,CACpD,GAAI,CAACA,EAAO,MAAO,CAAA,EACnB,MAAMC,GAASD,EAAM,SAAS;AAAA,CAAI,EAAIA,EAAM,MAAM,EAAG,EAAE,EAAIA,GAAO,MAAM;AAAA,CAAI,EAEtEE,EAAoB,CAAA,EAC1B,IAAIC,EAA2B,KAC3BC,EAAU,EACVC,EAAU,EACd,UAAWC,KAAQL,EAAO,CACxB,MAAMM,EAASD,EAAK,MAAMR,EAAW,EACrC,GAAIS,EAAQ,CACVJ,EAAU,CAAE,OAAQG,EAAM,MAAO,CAAA,CAAC,EAClCJ,EAAM,KAAKC,CAAO,EAClBC,EAAU,OAAOG,EAAO,CAAC,CAAC,EAC1BF,EAAU,OAAOE,EAAO,CAAC,CAAC,EAC1B,QACF,CACKJ,IACDG,EAAK,WAAW,IAAI,IACpBA,EAAK,WAAW,GAAG,GACrBH,EAAQ,MAAM,KAAK,CAAE,KAAM,MAAO,KAAMG,EAAK,MAAM,CAAC,EAAG,QAAS,KAAM,QAAAD,EAAS,EAC/EA,KACSC,EAAK,WAAW,GAAG,GAC5BH,EAAQ,MAAM,KAAK,CAAE,KAAM,SAAU,KAAMG,EAAK,MAAM,CAAC,EAAG,QAAAF,EAAS,QAAS,KAAM,EAClFA,MAEAD,EAAQ,MAAM,KAAK,CACjB,KAAM,UACN,KAAMG,EAAK,WAAW,GAAG,EAAIA,EAAK,MAAM,CAAC,EAAIA,EAC7C,QAAAF,EACA,QAAAC,CAAA,CACD,EACDD,IACAC,MAEJ,CACA,OAAOH,CACT,CAIO,SAASM,GAAgBC,EAA6B,CAC3D,OAAKA,EAEE,CACL,CACE,OAAQ,GACR,OAJWA,EAAQ,SAAS;AAAA,CAAI,EAAIA,EAAQ,MAAM,EAAG,EAAE,EAAIA,GAAS,MAAM;AAAA,CAAI,EAIjE,IAAI,CAACC,EAAM,KAAO,CAAE,KAAM,MAAO,KAAAA,EAAM,QAAS,KAAM,QAAS,EAAI,GAAI,CAAA,CACtF,EANmB,CAAA,CAQvB,CC9DA,MAAMC,GAA0B,GAE1BC,GAA2C,CAC/C,IAAK,uDACL,OAAQ,qDACR,QAAS,EACX,EAEMC,GAA4C,CAAE,IAAK,IAAK,OAAQ,IAAK,QAAS,GAAA,EAM9EC,GAAa,CAAC,CAAE,MAAAhF,KACpBb,EAAAA,KAAC,MAAA,CAAI,UAAU,yCACb,SAAA,CAAAF,EAAAA,IAAC4E,EAAA,CAAgB,OAAQ7D,EAAM,MAAA,CAAQ,EACvCf,EAAAA,IAACiE,EAAA,CACC,KAAMlD,EAAM,KACZ,OAAQA,EAAM,aAAe,GAAGA,EAAM,YAAY,MAAQ,OAC1D,UAAU,wBAAA,CAAA,EAEZb,EAAAA,KAAC,OAAA,CAAK,UAAU,mCACb,SAAA,CAAAa,EAAM,QAAUf,EAAAA,IAACI,EAAA,CAAM,KAAK,QAAQ,SAAA,SAAM,EAC1C,CAACW,EAAM,QAAUf,EAAAA,IAAC8D,EAAA,CAAW,UAAW/C,EAAM,UAAW,UAAWA,EAAM,SAAA,CAAW,CAAA,CAAA,CACxF,CAAA,EACF,EAOIiF,GAAW,CAAC,CAAE,MAAAjF,KAA2B,CAC7C,GAAIA,EAAM,OACR,OAAOf,EAAAA,IAAC,IAAA,CAAE,UAAU,iBAAiB,SAAA,yBAAsB,EAE7D,GAAIe,EAAM,cAAgB,YACxB,OAAOf,EAAAA,IAAC,IAAA,CAAE,UAAU,iBAAiB,SAAA,6BAA0B,EAEjE,MAAMmF,EACJpE,EAAM,cAAgB,MAAQ0E,GAAgB1E,EAAM,KAAK,EAAIiE,GAAWjE,EAAM,KAAK,EACrF,OAAIoE,EAAM,SAAW,EACfpE,EAAM,aAENf,EAAAA,IAAC,IAAA,CAAE,UAAU,iBACV,SAAAe,EAAM,YAAc,GAAKA,EAAM,YAAc,EAC1C,+BACA,gDAAA,CACN,EAGGf,EAAAA,IAAC,IAAA,CAAE,UAAU,iBAAiB,SAAA,yBAAsB,EAG3DA,EAAAA,IAAC,MAAA,CAAI,UAAU,yCACZ,SAAAmF,EAAM,IAAI,CAACc,EAAM,IAChB/F,OAAC,MAAA,CAAgC,UAAU,qBACxC,SAAA,CAAA+F,EAAK,QAAUjG,EAAAA,IAAC,MAAA,CAAI,UAAU,qCAAsC,WAAK,OAAO,QAEhF,MAAA,CAAI,UAAU,2EACZ,SAAAiG,EAAK,MAAM,IAAI,CAACV,EAAMW,IACrBhG,EAAAA,KAAC,QAA+B,UAAW,QAAQ2F,GAAWN,EAAK,IAAI,CAAC,GACtE,SAAA,CAAArF,EAAAA,KAAC,OAAA,CACC,UAAU,yDACV,cAAY,OAEZ,SAAA,CAAAF,MAAC,OAAA,CAAK,UAAU,iBAAkB,SAAAuF,EAAK,SAAW,GAAG,QACpD,OAAA,CAAK,UAAU,iBAAkB,SAAAA,EAAK,SAAW,EAAA,CAAG,CAAA,CAAA,CAAA,SAEtD,OAAA,CACE,SAAA,CAAAO,GAAYP,EAAK,IAAI,EACrBA,EAAK,IAAA,CAAA,CACR,CAAA,CAAA,EAXS,GAAGA,EAAK,IAAI,IAAIW,CAAC,EAY5B,CACD,CAAA,CACH,CAAA,GAnBQ,GAAGD,EAAK,MAAM,IAAI,CAAC,EAoB7B,CACD,EACH,CAEJ,EAMaE,GAAkB,CAAC,CAAE,MAAApF,KAAkC,CAClE,MAAMqF,EAAmBhH,EAAaC,GAAMA,EAAE,0BAA0B,IAAI0B,EAAM,IAAI,CAAC,EACjFsF,EAAoBjH,EAAaC,GAAMA,EAAE,2BAA2B,IAAI0B,EAAM,IAAI,CAAC,EACnFuF,EAAmBlH,EAAaC,GAAMA,EAAE,gBAAgB,EACxDkH,EACJF,GACC,CAACD,GAAoBrF,EAAM,UAAYA,EAAM,UAAY6E,GAEtDY,EAAczF,EAAM,aAAe,GAAGA,EAAM,YAAY,MAAMA,EAAM,IAAI,GAAKA,EAAM,KAEzF,cACG,MAAA,CAAI,iBAAgBA,EAAM,KAAM,UAAU,iCACzC,SAAA,CAAAf,EAAAA,IAAC,KAAA,CAAG,UAAU,UAAW,SAAAwG,EAAY,EACrCxG,EAAAA,IAACyG,EAAA,CACC,MAAOzG,EAAAA,IAAC+F,GAAA,CAAW,MAAAhF,CAAA,CAAc,EACjC,SAAU,CAACwF,EACX,SAAU,IAAMD,EAAiBvF,EAAM,KAAM,CAACwF,CAAS,EAEvD,SAAAvG,EAAAA,IAACgG,IAAS,MAAAjF,CAAA,CAAc,CAAA,CAAA,CAC1B,EACF,CAEJ,EC7GM2F,GAAoB,qEAEpBC,GAAe,CAAChG,EAAcY,IAA2C,CAC7EA,EAAeZ,CAAI,EACnB,sBAAsB,IAAM,QAC1BiG,EAAA,SACG,cAAc,oBAAoB,IAAI,OAAOjG,CAAI,CAAC,IAAI,IADzD,MAAAiG,EAEI,eAAe,CAAE,SAAU,SAAU,MAAO,SAClD,CAAC,CACH,EAIMC,GAAqB1H,GAAmB,CAC5C,KAAM,CAACsF,EAAGC,CAAC,EAAIvF,EACf,OAAOsF,IAAM,KAAOA,IAAM,KAAOC,IAAM,KAAOA,IAAM,GACtD,EAEaoC,GAAc,IAAM,CAC/B,KAAM,CACJ,MAAAtG,EACA,WAAAa,EACA,eAAAE,EACA,OAAAT,EACA,QAAAU,EACA,YAAAG,EACA,UAAAI,EACA,UAAAgF,EACA,aAAAC,CAAA,EACE5F,EAAA,EAEJ,MAAI,CAACZ,GAASA,EAAM,SAAW,EAAU,KAGvCN,EAAAA,KAAC,MAAA,CAAI,aAAW,gBAAgB,UAAU,gBACxC,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAW,GAAGwG,EAAiB,gDAClC,SAAA,CAAA1G,EAAAA,IAAC,QAAK,SAAA,eAAA,CAAa,EACnBA,EAAAA,IAACG,EAAA,CAAQ,QAAS4B,EAAY,qBAAuB,mBACnD,SAAA/B,EAAAA,IAACiH,EAAA,CACC,QAAQ,QACR,KAAK,OACL,UAAU,QACV,SAAUtF,EACV,MAAOI,EAAY,oBAAsB,kBACzC,QAASgF,EACT,WAAOG,EAAA,CAAA,CAAa,CAAA,CAAA,CACtB,CACF,CAAA,EACF,EAEAlH,EAAAA,IAAC,MAAG,UAAU,kCACX,WAAO,IAAKmH,GACXjH,EAAAA,KAAC,KAAA,CACC,SAAA,CAAAF,EAAAA,IAAC,MAAA,CACC,UAAU,0HACV,MAAOmH,EAAM,IAEZ,SAAAA,EAAM,GAAA,CAAA,EAETnH,EAAAA,IAAC,MAAG,UAAU,kCACX,WAAM,QAAQ,IAAKe,GAClBb,EAAAA,KAAC,KAAA,CAEC,UAAU,+DAEV,SAAA,CAAAF,EAAAA,IAACoH,EAAA,CACC,QAASrG,EAAM,OACf,cAAe8F,GAAkB9F,EAAM,MAAM,EAC7C,SAAUS,EAAQ,IAAIT,EAAM,IAAI,EAChC,SAAWsG,GAAML,EAAajG,EAAOsG,EAAE,OAAO,OAAO,EACrD,aAAYtG,EAAM,OAAS,WAAWA,EAAM,IAAI,GAAK,SAASA,EAAM,IAAI,EAAA,CAAA,QAEzE6D,EAAA,CAAgB,OAAQ7D,EAAM,OAAQ,QAAO,GAAC,EAC/Cf,EAAAA,IAACsH,EAAA,CACC,KAAK,QACL,OAAQvG,EAAM,OAASM,EACvB,QAAS,IAAMsF,GAAa5F,EAAM,KAAMQ,CAAc,EACtD,UAAU,yCACV,OACE,CAACR,EAAM,QACLf,EAAAA,IAAC8D,EAAA,CAAW,UAAW/C,EAAM,UAAW,UAAWA,EAAM,SAAA,CAAW,EAIxE,SAAAf,EAAAA,IAAC,OAAA,CACC,UAAU,mFACV,MAAOe,EAAM,KAEZ,SAAAL,EAAoBK,EAAM,IAAI,EAAE,IAAA,CAAA,CACnC,CAAA,CACF,CAAA,EA5BKA,EAAM,IAAA,CA8Bd,CAAA,CACH,CAAA,GAzCOoG,EAAM,GA0Cf,CACD,CAAA,CACH,CAAA,EACF,CAEJ,ECjGaI,GAAU,IAAM,CAC3B,KAAM,CAAE,MAAA/G,EAAO,WAAAoC,EAAY,cAAAtB,EAAe,YAAAwB,EAAa,WAAAG,CAAA,EAAeN,EAAA,EAEhE6E,EAAe,aAEfhC,EACJtF,EAAAA,KAAC,MAAA,CAAI,UAAU,mEACb,SAAA,CAAAF,EAAAA,IAACyH,EAAA,CAAU,UAAU,QAAQ,SAAA,MAAG,EAChCvH,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAF,EAAAA,IAAC0H,EAAA,EAAe,QACfC,EAAA,CAAA,CAAgB,CAAA,CAAA,CACnB,CAAA,EACF,EAGF,OAAI/E,SAEC,MAAA,CACE,SAAA,CAAA4C,EACDtF,EAAAA,KAAC,MAAA,CAAI,UAAW,GAAGsH,CAAY,mCAC7B,SAAA,CAAAxH,EAAAA,IAAC,IAAA,CAAE,UAAU,iBAAiB,SAAA,uCAAoC,EAClEA,EAAAA,IAACC,GAAO,QAAQ,YAAY,KAAK,QAAQ,QAASqB,EAAe,SAAA,OAAA,CAEjE,CAAA,CAAA,CACF,CAAA,EACF,EAICd,SAYF,MAAA,CACE,SAAA,CAAAgF,EACAhF,EAAM,SAAW,EAChBR,MAAC,OAAI,UAAWwH,EACd,SAAAxH,MAAC,IAAA,CAAE,UAAU,aAAa,SAAA,mBAAA,CAAiB,CAAA,CAC7C,EAEAE,EAAAA,KAAA0H,WAAA,CACE,SAAA,CAAA1H,EAAAA,KAAC,MAAA,CAAI,UAAU,sDACb,SAAA,CAAAF,EAAAA,IAAC,MAAA,CAAI,UAAU,SACb,SAAAA,EAAAA,IAAC6H,GAAoB,MAAO5E,EAAY,WAAY,EAAA,CAAO,CAAA,CAC7D,EACAjD,EAAAA,IAAChB,EAAA,CAAgB,MAAOiE,EAAY,WAAY,EAAA,CAAO,CAAA,EACzD,EACAjD,EAAAA,IAAC,MAAA,CAAI,IAAK8C,EAAa,UAAW,+BAA+B0E,CAAY,GAC1E,SAAAhH,EAAM,IAAI,CAACO,EAAO+G,IACjB5H,OAAC0H,EAAAA,SAAA,CACE,SAAA,CAAAE,EAAM,SAAMC,EAAA,CAAA,CAAQ,EACrB/H,MAACmG,IAAgB,MAAApF,CAAA,CAAc,CAAA,GAFlBA,EAAM,IAGrB,CACD,CAAA,CACH,CAAA,CAAA,CACF,CAAA,EAEJ,SAlCG,MAAA,CACE,SAAA,CAAAyE,EACDxF,EAAAA,IAAC,OAAI,UAAWwH,EACd,eAACQ,EAAA,CAAQ,MAAM,iCAAiC,CAAA,CAClD,CAAA,EACF,CA+BN"}
1
+ {"version":3,"file":"index-Ddz2TPW1.js","sources":["../../../src/app/features/git/actions/git-commit-button.tsx","../../../src/app/features/git/hooks/use-git-commit-form.ts","../../../src/app/utils/path-display.ts","../../../src/app/features/git/hooks/use-git-file-list.ts","../../../src/app/features/git/hooks/use-git-page.ts","../../../src/app/features/git/components/count-badge.tsx","../../../src/app/features/git/components/file-path.tsx","../../../src/app/features/git/components/git-status-marker.tsx","../../../src/app/utils/parse-diff.ts","../../../src/app/features/git/views/file-diff-section.tsx","../../../src/app/features/git/views/git-file-list.tsx","../../../src/app/features/git/git-page.tsx"],"sourcesContent":["import type { GitCommitFormState } from '@/app/features/git/hooks';\nimport { useDeskChecks } from '@/app/hooks/use-desk-checks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { deriveCheckStatuses } from '@/app/utils/check-status';\nimport { Button, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useMemo } from 'react';\n\ninterface GitCommitButtonProps {\n state: GitCommitFormState;\n filesEmpty: boolean;\n}\n\n// Never Fix (plan-scoped, and the git page never has one) — a failing check is a warning instead.\nexport const GitCommitButton = ({ state, filesEmpty }: GitCommitButtonProps) => {\n const status = useAppStore((s) => s.status);\n const { checks: deskChecks } = useDeskChecks();\n const { qualityStatus, testStatus, consistencyStatus } = useMemo(\n () => deriveCheckStatuses(status, deskChecks),\n [status, deskChecks],\n );\n const failingChecks = [\n qualityStatus === 'fail' && 'Quality',\n testStatus === 'fail' && 'Tests',\n consistencyStatus === 'fail' && 'Consistency',\n ].filter((label): label is Exclude<typeof label, false> => label !== false);\n\n const commitButton = (\n <Button\n size=\"small\"\n disabled={filesEmpty || !state.commitTitle.trim() || state.committing || state.commitInFlight}\n onClick={state.handleCommit}\n >\n {state.committing || state.commitInFlight\n ? 'Committing…'\n : state.stagedCount > 0\n ? `Commit ${state.stagedCount} staged`\n : 'Commit'}\n </Button>\n );\n\n if (failingChecks.length === 0) return commitButton;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Tooltip content={`${failingChecks.join(', ')} failing`}>\n <Stamp size=\"small\" variant=\"warning\">\n !\n </Stamp>\n </Tooltip>\n {commitButton}\n </div>\n );\n};\n","import { type CommitFormFile, useCommitForm } from '@/app/hooks/use-commit-form';\n\n// Stable across renders — keeps drafts saved under the git page's key from being orphaned.\nconst GIT_PAGE_FORM_KEY = '__git__';\n\nconst matchAnySuggestionTask = () => true;\n\n// No plan on the git page, so this is bare commit mechanics — no phase recording, no Fix.\nexport const useGitCommitForm = (files: CommitFormFile[]) =>\n useCommitForm(files, {\n formKey: GIT_PAGE_FORM_KEY,\n matchesSuggestionTask: matchAnySuggestionTask,\n });\n\nexport type GitCommitFormState = ReturnType<typeof useGitCommitForm>;\n","export interface SplitPath {\n dir: string;\n base: string;\n}\n\nexport function splitPathForDisplay(path: string): SplitPath {\n const slash = path.lastIndexOf('/');\n return slash === -1\n ? { dir: '', base: path }\n : { dir: path.slice(0, slash + 1), base: path.slice(slash + 1) };\n}\n","import { stagePath, unstagePath } from '@/app/services/git-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport { splitPathForDisplay } from '@/app/utils/path-display';\nimport type { FileDiffEntry } from '@/types/index';\nimport { useToast } from '@dendelion/paper-ui';\nimport { useMemo, useState } from 'react';\n\nfunction groupByFolder(files: FileDiffEntry[]): { dir: string; entries: FileDiffEntry[] }[] {\n const groups = new Map<string, FileDiffEntry[]>();\n for (const entry of files) {\n const { dir } = splitPathForDisplay(entry.path);\n const key = dir || './';\n const bucket = groups.get(key);\n if (bucket) bucket.push(entry);\n else groups.set(key, [entry]);\n }\n return [...groups].map(([dir, entries]) => ({ dir, entries }));\n}\n\nexport const useGitFileList = () => {\n const files = useAppStore((s) => s.diffFiles);\n const activePath = useAppStore((s) => s.activeDiffPath);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const expandDiffPath = useAppStore((s) => s.expandDiffPath);\n const [pending, setPending] = useState<Set<string>>(new Set());\n const [bulkPending, setBulkPending] = useState(false);\n const { toast } = useToast();\n const groups = useMemo(() => groupByFolder(files ?? []), [files]);\n const allStaged = (files ?? []).length > 0 && (files ?? []).every((f) => f.staged);\n\n // No bulk endpoint: fans out over per-path calls and reloads once at the end, so a\n // partial failure still reports and whatever landed shows up in that single reload.\n const toggleAll = async () => {\n const targets = (files ?? []).filter((f) => f.staged === allStaged);\n setBulkPending(true);\n try {\n const results = await Promise.allSettled(\n targets.map((f) => (allStaged ? unstagePath(f.path) : stagePath(f.path))),\n );\n const failed = results.filter((r) => r.status === 'rejected').length;\n if (failed > 0) {\n toast({\n title: allStaged ? 'Unstage failed' : 'Stage failed',\n description: `${failed} of ${targets.length} file(s) could not be updated.`,\n variant: 'error',\n });\n }\n } finally {\n await loadDiffFiles();\n setBulkPending(false);\n }\n };\n\n const toggleStaged = async (entry: FileDiffEntry, next: boolean) => {\n setPending((prev) => new Set(prev).add(entry.path));\n try {\n await (next ? stagePath(entry.path) : unstagePath(entry.path));\n await loadDiffFiles();\n } catch (err) {\n toast({\n title: next ? 'Stage failed' : 'Unstage failed',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n } finally {\n setPending((prev) => {\n const updated = new Set(prev);\n updated.delete(entry.path);\n return updated;\n });\n }\n };\n\n return {\n files,\n activePath,\n expandDiffPath,\n groups,\n pending,\n bulkPending,\n allStaged,\n toggleAll,\n toggleStaged,\n };\n};\n","import { useGitCommitForm } from '@/app/features/git/hooks/use-git-commit-form';\nimport { subscribeToActivityStream } from '@/app/services/activity-stream';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useEffect, useMemo, useRef } from 'react';\n\nexport const useGitPage = () => {\n const files = useAppStore((s) => s.diffFiles);\n const loadFailed = useAppStore((s) => s.diffLoadFailed);\n const loadDiffFiles = useAppStore((s) => s.loadDiffFiles);\n const setActiveDiffPath = useAppStore((s) => s.setActiveDiffPath);\n const sectionsRef = useRef<HTMLDivElement>(null);\n const commitFiles = useMemo(\n () => files?.map((entry) => ({ path: entry.path, staged: entry.staged })) ?? [],\n [files],\n );\n const commitForm = useGitCommitForm(commitFiles);\n\n useEffect(() => {\n loadDiffFiles();\n }, [loadDiffFiles]);\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const unsubscribe = subscribeToActivityStream((payload) => {\n if (payload.message !== 'changed') return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(loadDiffFiles, 250);\n });\n const onFocus = () => loadDiffFiles();\n window.addEventListener('focus', onFocus);\n return () => {\n if (timer) clearTimeout(timer);\n window.removeEventListener('focus', onFocus);\n unsubscribe();\n };\n }, [loadDiffFiles]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: files is the trigger to rebuild the observer, not a value read in the body.\n useEffect(() => {\n const root = sectionsRef.current;\n if (!root) return;\n const sections = Array.from(root.querySelectorAll<HTMLElement>('[data-diff-path]'));\n if (sections.length === 0) return;\n const visible = new Set<HTMLElement>();\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) visible.add(entry.target as HTMLElement);\n else visible.delete(entry.target as HTMLElement);\n }\n const topmost = sections.find((el) => visible.has(el));\n if (topmost) setActiveDiffPath(topmost.dataset.diffPath ?? null);\n },\n { rootMargin: '0px 0px -70% 0px' },\n );\n for (const el of sections) observer.observe(el);\n return () => observer.disconnect();\n }, [files, setActiveDiffPath]);\n\n return {\n files,\n loadFailed,\n loadDiffFiles,\n sectionsRef,\n commitForm,\n };\n};\n\nexport type GitPageState = ReturnType<typeof useGitPage>;\n","interface CountBadgeProps {\n additions: number;\n deletions: number;\n}\n\nexport const CountBadge = ({ additions, deletions }: CountBadgeProps) => (\n <span className=\"inline-flex shrink-0 gap-1.5 font-mono text-3xs\">\n <span className=\"text-watercolor-green-dark\">+{additions}</span>\n <span className=\"text-watercolor-rose-dark\">-{deletions}</span>\n </span>\n);\n","import { splitPathForDisplay } from '@/app/utils/path-display';\n\ninterface FilePathProps {\n path: string;\n prefix?: string;\n className?: string;\n}\n\nexport const FilePath = ({ path, prefix, className = '' }: FilePathProps) => {\n const { dir, base } = splitPathForDisplay(path);\n const dimmed = `${prefix ?? ''}${dir}`;\n return (\n <span className={`flex min-w-0 items-center font-mono ${className}`}>\n {dimmed && (\n <span className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-50\">\n {dimmed}\n </span>\n )}\n <span className=\"shrink-0 whitespace-nowrap\">{base}</span>\n </span>\n );\n};\n","import { Stamp, type StampVariant } from '@dendelion/paper-ui';\n\ninterface StatusInfo {\n letter: string;\n label: string;\n variant: StampVariant;\n}\n\n// Compact rows can't spare the ~39px a Stamp's blob costs for one letter; the colour\n// alone carries the same meaning in a fraction of the width.\nconst COMPACT_COLOR: Record<StampVariant, string> = {\n success: 'text-watercolor-green-dark',\n info: 'text-watercolor-blue-dark',\n error: 'text-watercolor-rose-dark',\n warning: 'text-watercolor-amber-dark',\n neutral: 'text-watercolor-slate-dark',\n};\n\nconst STATUS_INFO: Record<string, StatusInfo> = {\n A: { letter: 'A', label: 'Added', variant: 'success' },\n M: { letter: 'M', label: 'Modified', variant: 'info' },\n D: { letter: 'D', label: 'Deleted', variant: 'error' },\n R: { letter: 'R', label: 'Renamed', variant: 'info' },\n C: { letter: 'C', label: 'Copied', variant: 'info' },\n U: { letter: 'U', label: 'Conflicted', variant: 'warning' },\n};\n\n// Git's porcelain code is two characters: index status then worktree status.\n// The index one wins when both are set — it's the state that would actually commit.\nexport const gitStatusInfo = (status: string): StatusInfo => {\n if (status === '??') return { letter: '??', label: 'Untracked', variant: 'neutral' };\n const [x, y] = status;\n const code = x !== ' ' && x !== '?' ? x : y;\n return STATUS_INFO[code] ?? { letter: code ?? '?', label: code ?? 'Unknown', variant: 'neutral' };\n};\n\ninterface GitStatusMarkerProps {\n status: string;\n compact?: boolean;\n}\n\nexport const GitStatusMarker = ({ status, compact = false }: GitStatusMarkerProps) => {\n const info = gitStatusInfo(status);\n if (compact) {\n return (\n <span\n title={info.label}\n className={`w-4 shrink-0 text-center font-mono text-3xs font-semibold leading-none ${COMPACT_COLOR[info.variant] ?? ''}`}\n >\n {info.letter}\n </span>\n );\n }\n return (\n <span title={info.label}>\n <Stamp size=\"small\" variant={info.variant}>\n {info.letter}\n </Stamp>\n </span>\n );\n};\n","export type DiffLineType = 'add' | 'remove' | 'context';\n\nexport interface DiffLine {\n type: DiffLineType;\n text: string;\n oldLine: number | null;\n newLine: number | null;\n}\n\nexport interface DiffHunk {\n header: string;\n lines: DiffLine[];\n}\n\nconst HUNK_HEADER = /^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/;\n\n// Parses a unified diff (git.ts getWorkingDiff, contentKind: 'diff'). A real diff\n// with no hunks (pure rename, mode-only change) is just the preamble, so it yields [].\nexport function parsePatch(patch: string): DiffHunk[] {\n if (!patch) return [];\n const lines = (patch.endsWith('\\n') ? patch.slice(0, -1) : patch).split('\\n');\n\n const hunks: DiffHunk[] = [];\n let current: DiffHunk | null = null;\n let oldLine = 0;\n let newLine = 0;\n for (const line of lines) {\n const header = line.match(HUNK_HEADER);\n if (header) {\n current = { header: line, lines: [] };\n hunks.push(current);\n oldLine = Number(header[1]);\n newLine = Number(header[2]);\n continue;\n }\n if (!current) continue; // preamble: diff --git / index / --- / +++\n if (line.startsWith('\\\\')) continue; // \"\\"\n if (line.startsWith('+')) {\n current.lines.push({ type: 'add', text: line.slice(1), oldLine: null, newLine });\n newLine++;\n } else if (line.startsWith('-')) {\n current.lines.push({ type: 'remove', text: line.slice(1), oldLine, newLine: null });\n oldLine++;\n } else {\n current.lines.push({\n type: 'context',\n text: line.startsWith(' ') ? line.slice(1) : line,\n oldLine,\n newLine,\n });\n oldLine++;\n newLine++;\n }\n }\n return hunks;\n}\n\n// Untracked files store raw content, not a diff (git.ts getWorkingDiff, contentKind:\n// 'raw') — synthesize a single all-added hunk so the renderer only has one shape to draw.\nexport function rawContentHunks(content: string): DiffHunk[] {\n if (!content) return [];\n const lines = (content.endsWith('\\n') ? content.slice(0, -1) : content).split('\\n');\n return [\n {\n header: '',\n lines: lines.map((text, i) => ({ type: 'add', text, oldLine: null, newLine: i + 1 })),\n },\n ];\n}\n","import { CountBadge, FilePath, GitStatusMarker } from '@/app/features/git/components';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { type DiffLineType, parsePatch, rawContentHunks } from '@/app/utils/parse-diff';\nimport type { FileDiffEntry } from '@/types/index';\nimport { Accordion, Stamp } from '@dendelion/paper-ui';\n\nconst COLLAPSE_LINE_THRESHOLD = 60;\n\nconst LINE_CLASS: Record<DiffLineType, string> = {\n add: 'bg-watercolor-green/[18%] text-watercolor-green-dark',\n remove: 'bg-watercolor-rose/[18%] text-watercolor-rose-dark',\n context: '',\n};\n\nconst LINE_PREFIX: Record<DiffLineType, string> = { add: '+', remove: '-', context: ' ' };\n\ninterface FileHeaderProps {\n entry: FileDiffEntry;\n}\n\nconst FileHeader = ({ entry }: FileHeaderProps) => (\n <div className=\"flex w-full min-w-0 items-center gap-3\">\n <GitStatusMarker status={entry.status} />\n <FilePath\n path={entry.path}\n prefix={entry.renameSource ? `${entry.renameSource} → ` : undefined}\n className=\"min-w-0 flex-1 text-xs\"\n />\n <span className=\"flex shrink-0 items-center gap-2\">\n {entry.staged && <Stamp size=\"small\">staged</Stamp>}\n {!entry.binary && <CountBadge additions={entry.additions} deletions={entry.deletions} />}\n </span>\n </div>\n);\n\ninterface DiffBodyProps {\n entry: FileDiffEntry;\n}\n\nconst DiffBody = ({ entry }: DiffBodyProps) => {\n if (entry.binary) {\n return <p className=\"m-0 opacity-60\">Binary file not shown.</p>;\n }\n if (entry.contentKind === 'too-large') {\n return <p className=\"m-0 opacity-60\">File too large to preview.</p>;\n }\n const hunks =\n entry.contentKind === 'raw' ? rawContentHunks(entry.patch) : parsePatch(entry.patch);\n if (hunks.length === 0) {\n if (entry.renameSource) {\n return (\n <p className=\"m-0 opacity-60\">\n {entry.additions === 0 && entry.deletions === 0\n ? 'Renamed, no content changes.'\n : 'Renamed with unrelated content — diff omitted.'}\n </p>\n );\n }\n return <p className=\"m-0 opacity-60\">No changes to preview.</p>;\n }\n return (\n <div className=\"flex min-w-0 max-w-full flex-col gap-3\">\n {hunks.map((hunk, i) => (\n <div key={`${hunk.header}-${i}`} className=\"min-w-0 max-w-full\">\n {hunk.header && <div className=\"mb-1 font-mono text-2xs opacity-50\">{hunk.header}</div>}\n {/* paper-ui's CodeBlock has no per-line add/remove styling. */}\n <pre className=\"m-0 min-w-0 max-w-full overflow-x-auto font-mono text-2xs leading-normal\">\n {hunk.lines.map((line, j) => (\n <span key={`${line.type}-${j}`} className={`flex ${LINE_CLASS[line.type]}`}>\n <span\n className=\"inline-flex shrink-0 select-none gap-2 pr-2 opacity-40\"\n aria-hidden=\"true\"\n >\n <span className=\"w-8 text-right\">{line.oldLine ?? ''}</span>\n <span className=\"w-8 text-right\">{line.newLine ?? ''}</span>\n </span>\n <span>\n {LINE_PREFIX[line.type]}\n {line.text}\n </span>\n </span>\n ))}\n </pre>\n </div>\n ))}\n </div>\n );\n};\n\ninterface FileDiffSectionProps {\n entry: FileDiffEntry;\n}\n\nexport const FileDiffSection = ({ entry }: FileDiffSectionProps) => {\n const manuallyExpanded = useAppStore((s) => s.manuallyExpandedDiffPaths.has(entry.path));\n const manuallyCollapsed = useAppStore((s) => s.manuallyCollapsedDiffPaths.has(entry.path));\n const setDiffCollapsed = useAppStore((s) => s.setDiffCollapsed);\n const collapsed =\n manuallyCollapsed ||\n (!manuallyExpanded && entry.additions + entry.deletions > COLLAPSE_LINE_THRESHOLD);\n\n const headingText = entry.renameSource ? `${entry.renameSource} → ${entry.path}` : entry.path;\n\n return (\n <div data-diff-path={entry.path} className=\"min-w-0 max-w-full scroll-mt-4\">\n <h2 className=\"sr-only\">{headingText}</h2>\n <Accordion\n title={<FileHeader entry={entry} />}\n expanded={!collapsed}\n onToggle={() => setDiffCollapsed(entry.path, !collapsed)}\n >\n <DiffBody entry={entry} />\n </Accordion>\n </div>\n );\n};\n","import { CheckAllIcon } from '@/app/components/icons';\nimport { CountBadge, GitStatusMarker } from '@/app/features/git/components';\nimport { useGitFileList } from '@/app/features/git/hooks';\nimport { splitPathForDisplay } from '@/app/utils/path-display';\nimport { Checkbox, IconButton, ListItem, Tooltip } from '@dendelion/paper-ui';\n\nconst sectionLabelClass = 'font-handwritten text-xs font-semibold leading-none opacity-[0.45]';\n\nconst scrollToFile = (path: string, expandDiffPath: (path: string) => void) => {\n expandDiffPath(path);\n requestAnimationFrame(() => {\n document\n .querySelector(`[data-diff-path=\"${CSS.escape(path)}\"]`)\n ?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n};\n\n// Both status characters set (and neither '?', which pairs up for untracked) means\n// part of the file is staged and part isn't — git can't be checked or unchecked.\nconst isPartiallyStaged = (status: string) => {\n const [x, y] = status;\n return x !== ' ' && x !== '?' && y !== ' ' && y !== '?';\n};\n\nexport const GitFileList = () => {\n const {\n files,\n activePath,\n expandDiffPath,\n groups,\n pending,\n bulkPending,\n allStaged,\n toggleAll,\n toggleStaged,\n } = useGitFileList();\n\n if (!files || files.length === 0) return null;\n\n return (\n <nav aria-label=\"Changed files\" className=\"flex flex-col\">\n <div className={`${sectionLabelClass} flex h-[32px] items-end justify-between pb-1`}>\n <span>Changed files</span>\n <Tooltip content={allStaged ? 'Unstage every file' : 'Stage every file'}>\n <IconButton\n variant=\"ghost\"\n size=\"tiny\"\n className=\"-mb-1\"\n disabled={bulkPending}\n label={allStaged ? 'Unstage all files' : 'Stage all files'}\n onClick={toggleAll}\n icon={<CheckAllIcon />}\n />\n </Tooltip>\n </div>\n {/* Every row is exactly one 32px cell so the list tracks the ruled background. */}\n <ul className=\"m-0 flex list-none flex-col p-0\">\n {groups.map((group) => (\n <li key={group.dir}>\n <div\n className=\"flex h-[32px] items-end overflow-hidden text-ellipsis whitespace-nowrap pb-1 font-mono text-3xs leading-none opacity-50\"\n title={group.dir}\n >\n {group.dir}\n </div>\n <ul className=\"m-0 flex list-none flex-col p-0\">\n {group.entries.map((entry) => (\n <li\n key={entry.path}\n className=\"pc-git-file-row flex h-[32px] min-w-0 items-end gap-1.5 pb-1\"\n >\n <Checkbox\n checked={entry.staged}\n indeterminate={isPartiallyStaged(entry.status)}\n disabled={pending.has(entry.path)}\n onChange={(e) => toggleStaged(entry, e.target.checked)}\n aria-label={entry.staged ? `Unstage ${entry.path}` : `Stage ${entry.path}`}\n />\n <GitStatusMarker status={entry.status} compact />\n <ListItem\n size=\"small\"\n active={entry.path === activePath}\n onClick={() => scrollToFile(entry.path, expandDiffPath)}\n className=\"min-w-0 flex-1 items-end py-0 text-3xs\"\n action={\n !entry.binary && (\n <CountBadge additions={entry.additions} deletions={entry.deletions} />\n )\n }\n >\n <span\n className=\"block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-mono text-3xs\"\n title={entry.path}\n >\n {splitPathForDisplay(entry.path).base}\n </span>\n </ListItem>\n </li>\n ))}\n </ul>\n </li>\n ))}\n </ul>\n </nav>\n );\n};\n","import { CommitMessageFields, GitStashSurface, GitSyncActions } from '@/app/components';\nimport { PageTitle } from '@/app/components/page-title';\nimport { GitCommitButton } from '@/app/features/git/actions';\nimport { useGitPage } from '@/app/features/git/hooks';\nimport { FileDiffSection } from '@/app/features/git/views';\nimport { Button, Divider, Spinner } from '@dendelion/paper-ui';\nimport { Fragment } from 'react';\n\nexport const GitPage = () => {\n const { files, loadFailed, loadDiffFiles, sectionsRef, commitForm } = useGitPage();\n\n const contentClass = 'min-h-page';\n\n const header = (\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-x-4 gap-y-2\">\n <PageTitle className=\"!mb-0\">Git</PageTitle>\n <div className=\"flex items-center gap-2\">\n <GitSyncActions />\n <GitStashSurface />\n </div>\n </div>\n );\n\n if (loadFailed) {\n return (\n <div>\n {header}\n <div className={`${contentClass} flex flex-col items-start gap-3`}>\n <p className=\"opacity-50 m-0\">Couldn't load the working-tree diff.</p>\n <Button variant=\"secondary\" size=\"small\" onClick={loadDiffFiles}>\n Retry\n </Button>\n </div>\n </div>\n );\n }\n\n if (!files) {\n return (\n <div>\n {header}\n <div className={contentClass}>\n <Spinner label=\"Loading the working-tree diff…\" />\n </div>\n </div>\n );\n }\n\n return (\n <div>\n {header}\n {files.length === 0 ? (\n <div className={contentClass}>\n <p className=\"opacity-50\">No changed files.</p>\n </div>\n ) : (\n <>\n <div className=\"sticky top-0 z-10 mb-4 flex items-center gap-2 py-2\">\n <div className=\"flex-1\">\n <CommitMessageFields state={commitForm} filesEmpty={false} />\n </div>\n <GitCommitButton state={commitForm} filesEmpty={false} />\n </div>\n <div ref={sectionsRef} className={`flex min-w-0 flex-col gap-6 ${contentClass}`}>\n {files.map((entry, idx) => (\n <Fragment key={entry.path}>\n {idx > 0 && <Divider />}\n <FileDiffSection entry={entry} />\n </Fragment>\n ))}\n </div>\n </>\n )}\n </div>\n );\n};\n"],"names":["GitCommitButton","state","filesEmpty","status","useAppStore","s","deskChecks","useDeskChecks","qualityStatus","testStatus","consistencyStatus","useMemo","deriveCheckStatuses","failingChecks","label","commitButton","jsx","Button","jsxs","Tooltip","Stamp","GIT_PAGE_FORM_KEY","matchAnySuggestionTask","useGitCommitForm","files","useCommitForm","splitPathForDisplay","path","slash","groupByFolder","groups","entry","dir","key","bucket","entries","useGitFileList","activePath","loadDiffFiles","expandDiffPath","pending","setPending","useState","bulkPending","setBulkPending","toast","useToast","allStaged","f","targets","failed","unstagePath","stagePath","r","next","prev","err","oneLineErrorSummary","updated","useGitPage","loadFailed","setActiveDiffPath","sectionsRef","useRef","commitFiles","commitForm","useEffect","timer","unsubscribe","subscribeToActivityStream","payload","onFocus","root","sections","visible","observer","topmost","el","CountBadge","additions","deletions","FilePath","prefix","className","base","dimmed","COMPACT_COLOR","STATUS_INFO","gitStatusInfo","x","y","code","GitStatusMarker","compact","info","HUNK_HEADER","parsePatch","patch","lines","hunks","current","oldLine","newLine","line","header","rawContentHunks","content","text","COLLAPSE_LINE_THRESHOLD","LINE_CLASS","LINE_PREFIX","FileHeader","DiffBody","hunk","j","FileDiffSection","manuallyExpanded","manuallyCollapsed","setDiffCollapsed","collapsed","headingText","Accordion","sectionLabelClass","scrollToFile","_a","isPartiallyStaged","GitFileList","toggleAll","toggleStaged","IconButton","CheckAllIcon","group","Checkbox","e","ListItem","GitPage","contentClass","PageTitle","GitSyncActions","GitStashSurface","Fragment","CommitMessageFields","idx","Divider","Spinner"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{u as b,G as L,E as D,r as j,H as M,I as B,K as F,L as G,j as e,N as T,v as H,i as A,J as y,O as U,q,C as V,Q as $,S as J,R as O,M as z,T as K,g as R,U as _,V as N,P as w,p as E}from"./main-CDkrPxrg.js";import{W as je}from"./main-CDkrPxrg.js";const W=()=>{const s=b(n=>n.roadmap),t=b(n=>n.roadmapError),o=b(n=>n.loadRoadmap),i=b(n=>n.roadmapFilters),a=b(n=>n.plans),m=L(),{item:l}=D({from:"/roadmap"}),u=j.useRef(null),[d,h]=j.useState(null);j.useEffect(()=>{o()},[o]),j.useEffect(()=>{var x;if(!l||!s)return;const n=(x=u.current)==null?void 0:x.querySelector(".roadmap-item-highlighted");n==null||n.scrollIntoView({behavior:"smooth",block:"center"})},[l,s]);const f=n=>(a==null?void 0:a.entries.filter(x=>x.subject===n.name))??[],r=async(n,x,S)=>{await B(n,x,S),await o()},c=(n,x,S)=>{h({horizonTitle:n,item:x,candidateName:S})},p=s?M(s,i):[],g=p.reduce((n,x)=>n+x.items.length,0),v=i.horizons.length>0||i.statuses.length>0;return{roadmap:s,roadmapError:t,loadRoadmap:o,horizons:p,totalVisible:g,hasActiveFilters:v,highlightedItem:l,containerRef:u,promoting:d,setPromoting:h,graduatedByItem:f,handleAddCandidate:r,handlePromote:c,onOpenGraduated:m}},Q=["in-progress","review","planned","idea","done","dropped"],Z=()=>{const s=b(c=>c.roadmap),t=b(c=>c.roadmapFilters),o=b(c=>c.toggleRoadmapHorizon),i=b(c=>c.toggleRoadmapStatus),[a,m]=j.useState(!1),l=(s==null?void 0:s.horizons.map(c=>c.title))??[],u=s?F(s,t):{},d=s?G(s,t):{},h=new Set(t.horizons),f=new Set(t.statuses),r=Q.filter(c=>(d[c]??0)>0||f.has(c));return{roadmap:s,horizonTitles:l,horizonCounts:u,statusCounts:d,activeHorizons:h,activeStatuses:f,visibleStatuses:r,addOpen:a,setAddOpen:m,toggleRoadmapHorizon:o,toggleRoadmapStatus:i}},X=({open:s,horizonTitles:t,onClose:o})=>{const i=b(n=>n.loadRoadmap),[a,m]=j.useState(t[0]??""),[l,u]=j.useState(""),[d,h]=j.useState(""),[f,r]=j.useState(!1),[c,p]=j.useState(null),g=j.useRef(t);g.current=t,j.useEffect(()=>{s&&(m(g.current[0]??""),u(""),h(""),p(null),r(!1))},[s]);const v=async()=>{if(!(!l.trim()||!a)){r(!0),p(null);try{await U(a,l.trim(),d.trim()),await i(),o()}catch(n){p(n.message)}finally{r(!1)}}};return e.jsx(T,{open:s,onClose:o,title:"Add roadmap item",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(H,{size:"small",value:a,onChange:m,disabled:f,options:t.map(n=>({value:n,label:n}))}),e.jsx(A,{size:"small",value:l,onChange:n=>u(n.target.value),placeholder:"Item name…",disabled:f,autoFocus:!0}),e.jsx(A,{size:"small",value:d,onChange:n=>h(n.target.value),onKeyDown:n=>{n.key==="Enter"&&v()},placeholder:"Description…",disabled:f}),c&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:c}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:o,disabled:f,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:v,disabled:f||!l.trim()||!a,children:f?"Adding…":"Add item"})]})]})})},C="__no-subject__",Y=({horizonTitle:s,item:t,candidateName:o,onClose:i,onPromoted:a})=>{const m=b(x=>x.promoteRoadmapItem),l=b(x=>x.launchIdeaExtend),{subjects:u,available:d}=q(),[h,f]=j.useState(C),[r,c]=j.useState(!1),[p,g]=j.useState(null),{toast:v}=V();j.useEffect(()=>{t&&(f(o?t.name:C),c(!1),g(null))},[t,o]);const n=async()=>{if(!(!t||!s)){c(!0),g(null);try{const x=await m(s,t,h===C?void 0:h,o??void 0),S=b.getState().ideaEntries.find(k=>k.id===x);if(S)try{await l(x,$(S,s))}catch(k){v({title:"Idea created, but the refine agent failed to launch",description:J(k.message),variant:"error"})}a(),i()}catch(x){g(x.message)}finally{c(!1)}}};return e.jsx(T,{open:t!==null,onClose:i,title:o??(t==null?void 0:t.name)??"",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[!o&&e.jsx("p",{className:"m-0 opacity-80",children:t==null?void 0:t.description}),e.jsx("div",{children:e.jsx(H,{size:"small",value:h,onChange:f,disabled:r||!d,options:[{value:C,label:"No subject"},...!d&&h!==C?[{value:h,label:h}]:[],...u.map(x=>({value:x,label:x}))]})}),p&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:p}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:i,disabled:r,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:n,disabled:r,children:r?"Promoting…":"Promote to idea"})]})]})})},ee=({onAdd:s})=>{const[t,o]=j.useState(""),[i,a]=j.useState(!1),m=async()=>{if(t.trim()){a(!0);try{await s(t.trim()),o("")}finally{a(!1)}}};return e.jsxs("div",{className:"flex gap-2",children:[e.jsx(A,{size:"small",value:t,onChange:l=>o(l.target.value),onKeyDown:l=>{l.key==="Enter"&&m()},placeholder:"Add option…",disabled:i,className:"flex-1"}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:m,disabled:i||!t.trim(),children:"Add"})]})},se=({name:s,onPromote:t})=>e.jsx(O,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:t,children:"Promote to idea"})]})}),te=({goal:s})=>{const[t,o]=j.useState(!1),[i,...a]=s.split(/\n{2,}/),m=a.length>0;return e.jsxs("div",{className:"mb-6 pb-4 border-b border-black/[8%]",children:[e.jsx("span",{className:"font-handwritten text-xs font-semibold opacity-[0.55]",children:"The goal"}),e.jsxs("div",{className:"text-sm leading-relaxed opacity-80 mt-2",children:[e.jsx(z,{children:i}),t&&m&&e.jsx(z,{children:a.join(`
1
+ import{u as b,G as L,E as D,r as j,H as M,I as B,K as F,L as G,j as e,N as T,v as H,i as A,J as y,O as U,q,C as V,Q as $,S as J,R as O,M as z,T as K,g as R,U as _,V as N,P as w,p as E}from"./main-DkQCGPBX.js";import{W as je}from"./main-DkQCGPBX.js";const W=()=>{const s=b(n=>n.roadmap),t=b(n=>n.roadmapError),o=b(n=>n.loadRoadmap),i=b(n=>n.roadmapFilters),a=b(n=>n.plans),m=L(),{item:l}=D({from:"/roadmap"}),u=j.useRef(null),[d,h]=j.useState(null);j.useEffect(()=>{o()},[o]),j.useEffect(()=>{var x;if(!l||!s)return;const n=(x=u.current)==null?void 0:x.querySelector(".roadmap-item-highlighted");n==null||n.scrollIntoView({behavior:"smooth",block:"center"})},[l,s]);const f=n=>(a==null?void 0:a.entries.filter(x=>x.subject===n.name))??[],r=async(n,x,S)=>{await B(n,x,S),await o()},c=(n,x,S)=>{h({horizonTitle:n,item:x,candidateName:S})},p=s?M(s,i):[],g=p.reduce((n,x)=>n+x.items.length,0),v=i.horizons.length>0||i.statuses.length>0;return{roadmap:s,roadmapError:t,loadRoadmap:o,horizons:p,totalVisible:g,hasActiveFilters:v,highlightedItem:l,containerRef:u,promoting:d,setPromoting:h,graduatedByItem:f,handleAddCandidate:r,handlePromote:c,onOpenGraduated:m}},Q=["in-progress","review","planned","idea","done","dropped"],Z=()=>{const s=b(c=>c.roadmap),t=b(c=>c.roadmapFilters),o=b(c=>c.toggleRoadmapHorizon),i=b(c=>c.toggleRoadmapStatus),[a,m]=j.useState(!1),l=(s==null?void 0:s.horizons.map(c=>c.title))??[],u=s?F(s,t):{},d=s?G(s,t):{},h=new Set(t.horizons),f=new Set(t.statuses),r=Q.filter(c=>(d[c]??0)>0||f.has(c));return{roadmap:s,horizonTitles:l,horizonCounts:u,statusCounts:d,activeHorizons:h,activeStatuses:f,visibleStatuses:r,addOpen:a,setAddOpen:m,toggleRoadmapHorizon:o,toggleRoadmapStatus:i}},X=({open:s,horizonTitles:t,onClose:o})=>{const i=b(n=>n.loadRoadmap),[a,m]=j.useState(t[0]??""),[l,u]=j.useState(""),[d,h]=j.useState(""),[f,r]=j.useState(!1),[c,p]=j.useState(null),g=j.useRef(t);g.current=t,j.useEffect(()=>{s&&(m(g.current[0]??""),u(""),h(""),p(null),r(!1))},[s]);const v=async()=>{if(!(!l.trim()||!a)){r(!0),p(null);try{await U(a,l.trim(),d.trim()),await i(),o()}catch(n){p(n.message)}finally{r(!1)}}};return e.jsx(T,{open:s,onClose:o,title:"Add roadmap item",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(H,{size:"small",value:a,onChange:m,disabled:f,options:t.map(n=>({value:n,label:n}))}),e.jsx(A,{size:"small",value:l,onChange:n=>u(n.target.value),placeholder:"Item name…",disabled:f,autoFocus:!0}),e.jsx(A,{size:"small",value:d,onChange:n=>h(n.target.value),onKeyDown:n=>{n.key==="Enter"&&v()},placeholder:"Description…",disabled:f}),c&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:c}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:o,disabled:f,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:v,disabled:f||!l.trim()||!a,children:f?"Adding…":"Add item"})]})]})})},C="__no-subject__",Y=({horizonTitle:s,item:t,candidateName:o,onClose:i,onPromoted:a})=>{const m=b(x=>x.promoteRoadmapItem),l=b(x=>x.launchIdeaExtend),{subjects:u,available:d}=q(),[h,f]=j.useState(C),[r,c]=j.useState(!1),[p,g]=j.useState(null),{toast:v}=V();j.useEffect(()=>{t&&(f(o?t.name:C),c(!1),g(null))},[t,o]);const n=async()=>{if(!(!t||!s)){c(!0),g(null);try{const x=await m(s,t,h===C?void 0:h,o??void 0),S=b.getState().ideaEntries.find(k=>k.id===x);if(S)try{await l(x,$(S,s))}catch(k){v({title:"Idea created, but the refine agent failed to launch",description:J(k.message),variant:"error"})}a(),i()}catch(x){g(x.message)}finally{c(!1)}}};return e.jsx(T,{open:t!==null,onClose:i,title:o??(t==null?void 0:t.name)??"",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[!o&&e.jsx("p",{className:"m-0 opacity-80",children:t==null?void 0:t.description}),e.jsx("div",{children:e.jsx(H,{size:"small",value:h,onChange:f,disabled:r||!d,options:[{value:C,label:"No subject"},...!d&&h!==C?[{value:h,label:h}]:[],...u.map(x=>({value:x,label:x}))]})}),p&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:p}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:i,disabled:r,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:n,disabled:r,children:r?"Promoting…":"Promote to idea"})]})]})})},ee=({onAdd:s})=>{const[t,o]=j.useState(""),[i,a]=j.useState(!1),m=async()=>{if(t.trim()){a(!0);try{await s(t.trim()),o("")}finally{a(!1)}}};return e.jsxs("div",{className:"flex gap-2",children:[e.jsx(A,{size:"small",value:t,onChange:l=>o(l.target.value),onKeyDown:l=>{l.key==="Enter"&&m()},placeholder:"Add option…",disabled:i,className:"flex-1"}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:m,disabled:i||!t.trim(),children:"Add"})]})},se=({name:s,onPromote:t})=>e.jsx(O,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:t,children:"Promote to idea"})]})}),te=({goal:s})=>{const[t,o]=j.useState(!1),[i,...a]=s.split(/\n{2,}/),m=a.length>0;return e.jsxs("div",{className:"mb-6 pb-4 border-b border-black/[8%]",children:[e.jsx("span",{className:"font-handwritten text-xs font-semibold opacity-[0.55]",children:"The goal"}),e.jsxs("div",{className:"text-sm leading-relaxed opacity-80 mt-2",children:[e.jsx(z,{children:i}),t&&m&&e.jsx(z,{children:a.join(`
2
2
 
3
3
  `)})]}),m&&e.jsx("button",{type:"button",onClick:()=>o(l=>!l),className:"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline",children:t?"Show less":"Show more"})]})},ae="outline-[rgba(200,154,90,0.5)]",I={fill:"rgba(0, 0, 0, 0.06)",text:"rgba(0, 0, 0, 0.55)"},ne=(s,t)=>{const o=new Set,i=t.map(a=>(a.id&&o.add(a.id),a.idea&&o.add(a.idea),{key:a.title,label:a.title,status:a.status,pr:a.pr,planId:a.id,planTitle:a.title}));for(const a of s)o.has(a.id)||i.push({key:a.id,label:a.id,status:a.status,pr:a.pr});return i},oe=({idea:s,onOpen:t})=>e.jsx(O,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"flex items-center gap-3",children:[t?e.jsx("button",{type:"button",onClick:t,className:"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left",children:s.label}):e.jsx("span",{className:"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",children:s.label}),s.pr&&e.jsx(K,{pr:s.pr}),e.jsx(R,{size:"small",fillColor:N[s.status].fill,textColor:N[s.status].text,children:_[s.status]})]})}),le=({done:s,total:t})=>{const o=t>0?Math.round(s/t*100):0;return e.jsx("div",{className:"w-24 h-1.5 rounded-full bg-black/[0.08] overflow-hidden shrink-0",children:e.jsx("div",{className:`h-full rounded-full ${t>0?"bg-watercolor-green":"bg-transparent"}`,style:{width:`${o}%`}})})},re=s=>({shipped:s.filter(t=>t.status==="done").length,queued:s.filter(t=>t.status!=="done"&&t.status!=="dropped").length}),ie=({size:s=14})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),de=({item:s,graduated:t,highlighted:o,onPromote:i,onPromoteCandidate:a,onAddCandidate:m,onOpenGraduated:l})=>{const[u,d]=j.useState(o),{shipped:h,queued:f}=re(t),r=s.candidates.length,c=ne(s.links,t);return j.useEffect(()=>{o&&d(!0)},[o]),e.jsxs("div",{className:`border-b border-black/10 last:border-b-0 ${o?`roadmap-item-highlighted outline outline-2 outline-offset-[-2px] ${ae}`:""}`,children:[e.jsxs("button",{type:"button","aria-expanded":u,onClick:()=>d(p=>!p),className:"flex w-full items-center gap-3 py-2.5 px-0 bg-transparent border-none cursor-pointer text-left [font:inherit] text-inherit",children:[e.jsx("span",{className:`inline-flex items-center opacity-50 shrink-0 ${u?"rotate-90":""}`,children:e.jsx(ie,{})}),e.jsx("span",{className:"font-semibold flex-1 min-w-0 truncate",children:s.name}),e.jsx(le,{done:s.rollup.done,total:s.rollup.total}),f>0&&e.jsxs(R,{size:"small",fillColor:N.planned.fill,textColor:N.planned.text,children:[f," in queue"]}),h>0&&e.jsxs(R,{size:"small",fillColor:N.done.fill,textColor:N.done.text,children:[h," shipped"]}),r>0&&e.jsxs(R,{size:"small",fillColor:I.fill,textColor:I.text,children:[r," candidate",r===1?"":"s"]})]}),u&&e.jsxs("div",{className:"flex flex-col gap-1 pl-6 pb-4",children:[e.jsx("span",{className:"text-sm opacity-70",children:s.description}),c.map(p=>e.jsx(oe,{idea:p,onOpen:p.planTitle?()=>l(p.planId,p.planTitle):void 0},p.key)),s.candidates.map(p=>e.jsx(se,{name:p,onPromote:()=>a(p)},p)),e.jsx(ee,{onAdd:m}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:i,className:"self-start",children:"Promote to idea"})]})]})},ce="font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0",pe=({horizon:s,highlightedItem:t,graduatedByItem:o,onPromote:i,onAddCandidate:a,onOpenGraduated:m})=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("div",{className:ce,children:s.title}),e.jsx("div",{className:"flex flex-col",children:s.items.map(l=>e.jsx(de,{item:l,graduated:o(l),highlighted:l.name===t,onPromote:()=>i(l),onPromoteCandidate:u=>i(l,u),onAddCandidate:u=>a(l.name,u),onOpenGraduated:m},l.name))})]}),xe=()=>{const{roadmap:s,roadmapError:t,loadRoadmap:o,horizons:i,totalVisible:a,hasActiveFilters:m,highlightedItem:l,containerRef:u,promoting:d,setPromoting:h,graduatedByItem:f,handleAddCandidate:r,handlePromote:c,onOpenGraduated:p}=W();return t?e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"Couldn't load the roadmap — the server may need a restart to pick up new routes."})]}):s?s.horizons.length===0?e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"No `ROADMAP.md` found at the project root."})]}):e.jsxs("div",{ref:u,children:[e.jsx(w,{children:"Roadmap"}),e.jsx(te,{goal:s.goal}),a===0?e.jsx("p",{className:"opacity-50 py-6 px-0 text-center",children:m?"Nothing matches these filters — clear one from the sidebar to see more.":"No roadmap items yet — add one from the sidebar."}):e.jsx("div",{className:"flex flex-col gap-6",children:i.filter(g=>g.items.length>0).map(g=>e.jsx(pe,{horizon:g,highlightedItem:l,graduatedByItem:f,onPromote:(v,n)=>c(g.title,v,n),onAddCandidate:(v,n)=>r(g.title,v,n),onOpenGraduated:p},g.title))}),e.jsx(Y,{horizonTitle:(d==null?void 0:d.horizonTitle)??null,item:(d==null?void 0:d.item)??null,candidateName:d==null?void 0:d.candidateName,onClose:()=>h(null),onPromoted:o})]}):e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"Loading…"})]})},P="pc-row-label font-handwritten text-xs font-semibold opacity-[0.45]",ue=()=>{const{roadmap:s,horizonTitles:t,horizonCounts:o,statusCounts:i,activeHorizons:a,activeStatuses:m,visibleStatuses:l,addOpen:u,setAddOpen:d,toggleRoadmapHorizon:h,toggleRoadmapStatus:f}=Z();return s?e.jsxs("div",{className:"flex flex-col",children:[e.jsx("div",{className:"flex h-[64px] items-center",children:e.jsx(y,{type:"button",variant:"primary",size:"small",onClick:()=>d(!0),disabled:t.length===0,children:"+ Add item"})}),e.jsxs("div",{children:[e.jsx("div",{className:P,children:"Horizon"}),e.jsx("div",{className:"flex flex-col",children:t.map(r=>e.jsx(E,{size:"small",active:a.has(r),onClick:()=>h(r),className:"pc-row text-xs",action:e.jsx("span",{className:"text-2xs text-ink-500",children:o[r]??0}),children:r},r))})]}),e.jsxs("div",{children:[e.jsx("div",{className:P,children:"Status"}),e.jsxs("div",{className:"flex flex-col",children:[l.length===0&&e.jsx("span",{className:"opacity-50 text-2xs",children:"No linked ideas"}),l.map(r=>e.jsx(E,{size:"small",active:m.has(r),onClick:()=>f(r),className:"pc-row text-xs",icon:e.jsx("span",{className:"w-[9px] h-[9px] rounded-full shrink-0",style:{background:N[r].text}}),action:e.jsx("span",{className:"text-2xs text-ink-500",children:i[r]??0}),children:_[r]},r))]})]}),e.jsx(X,{open:u,horizonTitles:t,onClose:()=>d(!1)})]}):null};export{xe as RoadmapPage,ue as RoadmapSidebar,je as useRoadmapItemNames};
4
- //# sourceMappingURL=index-B0T4zOOc.js.map
4
+ //# sourceMappingURL=index-rxWn42R9.js.map