@polderlabs/bizar 5.5.3 → 5.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bizar-dash/dist/assets/{EnvVarsSection-DoIzqrlb.js → EnvVarsSection-Bi3Cptpr.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsSection-DoIzqrlb.js.map → EnvVarsSection-Bi3Cptpr.js.map} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-CoUCUsbr.js → MobileChat-H0ASvfzr.js} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-CoUCUsbr.js.map → MobileChat-H0ASvfzr.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-ndyqmLdP.js +1 -0
- package/bizar-dash/dist/assets/{MobileSettings-BeO04g52.js.map → MobileSettings-ndyqmLdP.js.map} +1 -1
- package/bizar-dash/dist/assets/{Toast-D9nv5N6m.js → Toast-BP5x9M-T.js} +1 -1
- package/bizar-dash/dist/assets/{Toast-D9nv5N6m.js.map → Toast-BP5x9M-T.js.map} +1 -1
- package/bizar-dash/dist/assets/{icons-Btipv2pp.js → icons-Cr5zfF_4.js} +96 -91
- package/bizar-dash/dist/assets/icons-Cr5zfF_4.js.map +1 -0
- package/bizar-dash/dist/assets/{main-UG4jKK-F.css → main-DAthMQSh.css} +1 -1
- package/bizar-dash/dist/assets/{main-DHXPuddY.js → main-dq0UZN8-.js} +10 -10
- package/bizar-dash/dist/assets/main-dq0UZN8-.js.map +1 -0
- package/bizar-dash/dist/assets/mobile-BIJt6dnI.js +1 -0
- package/bizar-dash/dist/assets/{mobile-H5KH9cTL.js.map → mobile-BIJt6dnI.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-layout-DKh7Pn9-.js +2 -0
- package/bizar-dash/dist/assets/{mobile-layout-BqHxVb6_.js.map → mobile-layout-DKh7Pn9-.js.map} +1 -1
- package/bizar-dash/dist/assets/{useSlashCommands-C24-O1e7.js → useSlashCommands-B8ixT4ub.js} +2 -2
- package/bizar-dash/dist/assets/{useSlashCommands-C24-O1e7.js.map → useSlashCommands-B8ixT4ub.js.map} +1 -1
- package/bizar-dash/dist/index.html +7 -7
- package/bizar-dash/dist/mobile.html +3 -3
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/memory-git.mjs +62 -19
- package/bizar-dash/src/server/memory-lightrag.mjs +21 -2
- package/bizar-dash/src/server/memory-store.mjs +115 -7
- package/bizar-dash/src/server/minimax.mjs +15 -1
- package/bizar-dash/src/server/routes/memory.mjs +54 -16
- package/bizar-dash/src/server/server.mjs +17 -0
- package/bizar-dash/src/web/components/SettingsNav.tsx +29 -9
- package/bizar-dash/src/web/styles/settings.css +0 -74
- package/bizar-dash/src/web/views/Settings.tsx +1 -1
- package/bizar-dash/tests/lightrag-startup-hook.test.mjs +32 -0
- package/bizar-dash/tests/memory-git.test.mjs +18 -0
- package/bizar-dash/tests/memory-store.test.mjs +102 -0
- package/bizar-dash/tests/minimax-chat-usage.test.mjs +75 -0
- package/bizar-dash/tests/settings-layout.test.tsx +1 -1
- package/bizar-dash/tests/settings-nav.test.tsx +3 -2
- package/package.json +1 -1
- package/bizar-dash/dist/assets/MobileSettings-BeO04g52.js +0 -1
- package/bizar-dash/dist/assets/icons-Btipv2pp.js.map +0 -1
- package/bizar-dash/dist/assets/main-DHXPuddY.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-H5KH9cTL.js +0 -1
- package/bizar-dash/dist/assets/mobile-layout-BqHxVb6_.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"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","names":["ModalContext","createContext","FOCUSABLE_SELECTOR","useModal","ctx","useContext","ModalProvider","children","stack","setStack","useState","close","useCallback","id","cur","idx","m","open","props","useEffect","handler","e","jsxs","createPortal","jsx","ModalShell","_a","modal","onClose","depth","modalRef","useRef","previousFocusRef","titleId","useId","getFocusableElements","root","el","onKeyDown","focusableElements","first","last","active","_b","_c","previous","X","MAX_CACHE","TTL_MS","_cache","cacheGet","path","entry","cacheSet","data","a","b","k","pathSegments","p","parts","result","accumulated","i","sortEntries","entries","validateDirName","name","trimmed","FileBrowser","value","onChange","initialPath","projectsDirectory","rootLabel","height","currentPath","setCurrentPath","expanded","setExpanded","selectedRow","setSelectedRow","listing","setListing","childrenMap","setChildrenMap","loading","setLoading","error","setError","mkdirOpen","setMkdirOpen","mkdirName","setMkdirName","mkdirError","setMkdirError","mkdirLoading","setMkdirLoading","mkdirInputRef","fetchListing","cached","api","load","err","msg","dirs","allEntries","navigateInto","navigateUp","navigateTo","goHome","home","goProjects","pd","openMkdir","cancelMkdir","submitMkdir","v","apiErr","handleMkdirKeyDown","toggleExpand","prev","next","handleKeyDown","x","files","selectable","r","sel","segments","parentPath","canGoUp","basename","seg","ArrowLeft","RefreshCw","FolderPlus","Home","FolderOpen","AlertCircle","TreeSkeleton","TreeNode","FlatSkeleton","Fragment","isDir","isSelected","isActive","Folder","File","onToggle","onNavigate","level","isExpanded","kids","ChevronDown","ChevronRight","w","TABS","LayoutDashboard","MessageSquare","Bot","Map","CheckSquare","Activity","Radio","Sparkles","Brain","Puzzle","Store","Clock","HistoryIcon","Coins","ClipboardCheck","Stethoscope","Sliders","Topbar","activeTab","onTabChange","wsStatus","version","activeProject","projects","onProjectChange","onProjectsRefresh","onOpenSearch","settings","rightSlot","notificationsSlot","showTabs","extraTabs","ProjectSelector","SearchIcon","cn","tab","Icon","Settings2","onRefresh","setOpen","onClick","onAdd","TopbarAddProjectDialog","Button","Plus","setPath","setName","preflighting","setPreflighting","preflightError","setPreflightError","handleAdd","SECTION_GROUPS","Palette","LayoutGrid","Terminal","Wifi","Bell","Shield","Cpu","Users","Gauge","FolderGit2","SettingsNav","activeSection","onSectionChange","onExitSettings","group","s","Sidebar","tabs","settingsMode","settingsActiveSection","onSettingsSectionChange","builtIn","t","modTabs","SCOPES","RESULT_TYPE_BY_SCOPE","SearchModal","onSelect","toast","useToast","q","setQ","scope","setScope","results","setResults","activeIdx","setActiveIdx","inputRef","focusTimer","cancelled","grouped","type","flat","resultType","onKey","Search","list","flatIdx","summarize","val","ICONS","Info","CheckCircle2","AlertTriangle","Notifications","onCountChange","wsSubscribe","items","setItems","stats","setStats","rootRef","unreadRef","reload","incoming","n","onDocClick","onMarkAllRead","onMarkRead","onRemove","removed","statsCur","unread","Check","formatRelative","VisualPlanDialog","enabled","mode","defaultTemplate","lastUsedSlug","wasToggled","KNOWN_TEMPLATES","ArtifactCreateDialog","templates","slug","setSlug","selectedTemplate","setSelectedTemplate","creating","setCreating","handleCreate","ArtifactListDialog","plans","count","handleOpen","HelpDialog","commands","statuses","AuditDialog","running","setRunning","setResult","handleRunAudit","res","f","GenericDialog","dialog","message","detail","url","CommandDialog","MemoryStatusCard","setActiveTab","refreshKey","setData","status","health","lightrag","openMemory","healthColor","Card","CardTitle","ExternalLink","CardMeta","FileText","GitBranch","formatTime","EmptyState","icon","title","action","className","Inbox","OverviewInner","snapshot","refreshSnapshot","overview","setOverview","setProjects","activeId","setActiveId","mods","setMods","submitting","setSubmitting","activityItems","setActivityItems","activityExpanded","setActivityExpanded","hiddenKeys","setHiddenKeys","itemKey","it","h","onHide","key","rollback","onClearAll","all","onRestoreAll","es","tok","parsed","onAddProject","AddProjectDialog","onUseCurrentDir","newActive","onActivate","Spinner","text","Send","Eye","EyeOff","VirtualList","vlIdx","originalIdx","ActivityFeedItem","FolderSearch","ProjectCard","project","onOpen","statusColor","Trash2","Power","sentenceCase","humanizeKind","kind","normalized","scopeRaw","actionRaw","scopeMap","actionMap","firstString","keys","formatActivitySummary","direct","agent","formatRelativeTime","ts","activitySeverity","activityIcon","Zap","AlertOctagon","activityNavTarget","item","activityKey","severity","navTarget","accentColor","OverviewMemo","React","SessionRowMenu","session","anchor","renameDraft","setRenameDraft","onEdit","onDeleteRequest","onConfirmDelete","onConfirmRename","ref","top","right","onDown","input","body","Edit","AgentNode","node","collapsible","isLast","controlledOpen","internalOpen","setInternalOpen","isControlled","hasChildren","headContent","child","isFullTree","AgentTree","SubAgentList","variant","DEFAULT_GROUPS","isSameDay","dayDiff","ms","defaultGroupBy","sessions","now","yesterday","weekAgo","groups","d","mtime","SessionStateIndicator","state","ChatRail","opencodeSessions","activeSessionId","activeOpencodeSessionId","onCreateSession","onSelectSession","onSelectOpencodeSession","onRenameSession","onDeleteSession","groupBy","allSessions","useMemo","sorted","openTree","setOpenTree","isTreeOpen","openMenuId","setOpenMenuId","menuMode","setMenuMode","menuAnchor","setMenuAnchor","rowRefs","openMenuFor","row","target","closeMenu","handleSelect","handleConfirmRename","sid","handleConfirmDelete","orderedGroups","g","isOpencode","tree","treeOpen","ChatComposer","sending","onSend","activeSource","takingOff","setTakingOff","handleSend","Composer","formatNumber","providerFromModel","model","approxCostPer1M","ChatInfoPanel","sessionId","messages","pinned","agents","mcps","allCommands","onRename","onDelete","onExport","busy","onRetry","usage","setUsage","msgCount","pinnedCount","totalChars","approxTokens","rate","approxCostUsd","tokensUsed","costUsd","tokensTotal","provider","RotateCw","Server","CircleDollarSign","Pencil","Download","JumpToLatest","streaming","newMessageCount","streamingLabel","ArrowDown","Chat","initialTaskId","onClearTaskId","chat","useChat","setText","setAgent","setModel","attachments","setAttachments","fileInputRef","suggestions","setQuery","useSlashCommands","onAttach","onFiles","newNames","handleCreateSession","handleDelete","handleRename","currentTitle","ok","handleDeleteSession","handleExport","who","c","blob","displaySessions","displayOpencodeSessions","activeSessionDisplay","threadSubtitle","base","sourceLabel","ChatTopBar","ChatThread","cmd","normalizeKind","StatusBadge","dot","TOOL_OPTIONS","MODELS","CATEGORIES","categoryColor","cat","StatusDot","isStuck","color","StatusPill","Agents","setAgents","categoryFilter","setCategoryFilter","search","setSearch","out","allTags","set","onCreate","nameEl","descEl","modelEl","modeEl","colorEl","promptEl","toolsContainer","tagsEl","categoryEl","tools","cb","tags","created","Save","full","updated","onInvoke","prompt","Play","onRestart","onSetStatus","TagIcon","AgentCard","catColor","isWorking","Circle","RichText","proseStyle","ReactMarkdown","remarkGfm","CALLOUT_TONE","XCircle","Callout","tone","Checklist","Table","columns","rows","ri","cell","ci","CodeTabs","selected","Decision","question","options","opt","isRec","OpenQuestions","questions","answers","setAnswers","setAnswer","qid","inputStyle","current","checked","o","FILE_CHANGE","FileTree","Diff","filename","language","before","after","beforeLines","afterLines","header","FileCode2","codeStyle","lineRow","sign","content","colors","signColor","l","TREND_STYLE","Minus","Stat","label","trend","hint","STEP_COLORS","BOX_W","BOX_H","GAP_X","GAP_Y","Workflow","steps","connections","Empty","byId","layout","layoutSteps","cols","width","nodeCenter","stepId","pos","from","to","dx","dy","fromX","toX","fromY","toY","midX","midY","y","cx","cy","points","Diamond","isNote","StickyNote","Mockup","html","BlockErrorBoundary","__publicField","info","validateBlock","SECTION_MAP","groupBlocksIntoSections","blocks","sections","heading","GlyphRenderer","onCommentAdded","compiled","setCompiled","comments","setComments","loadError","setLoadError","fullscreen","setFullscreen","ctxMenu","setCtxMenu","addingComment","setAddingComment","commentDraft","setCommentDraft","activePin","setActivePin","blockErrors","setBlockErrors","reportBlockError","blockId","blockType","canvasRef","TIMEOUT_MS","timeoutPromise","_","reject","renderData","artifactData","fromFile","onContainerContextMenu","rect","submitComment","submitFeedback","toggleFullscreen","renderBlock","validation","renderBlockInner","commentCount","Share2","Undo2","Redo2","Maximize2","MoreHorizontal","_d","section","MapPin","planStatusKind","Artifacts","artifacts","setPlans","activeSlug","setActiveSlug","filter","setFilter","showArchived","setShowArchived","filtered","artifact","MapIcon","ArchiveRestore","Archive","NewPlanCard","PlanCard","setTitle","Tag","BacklogItem","task","onPromote","handlePromote","priorityDot","ArrowUp","BacklogPanel","tasks","setTasks","handleEdit","_task","handlePromoteAll","COLUMNS","PRIORITIES","TasksInner","priorityFilter","setPriorityFilter","showBacklog","setShowBacklog","tick","setTick","statusAnnouncement","setStatusAnnouncement","priorityWeight","pa","pb","backlogCount","moveTask","taskId","newStatus","deleteTask","retryTask","submitToOdin","XIcon","openCreateTaskModal","col","KanbanColumn","openEditTaskModal","column","onMove","onSubmitToOdin","dragOver","setDragOver","TaskCard","dir","assignedAgent","priorityColors","tag","ChevronLeft","Edit2","titleEl","priorityEl","submit","description","priority","onTitleKeyDown","enhanced","enhancePrompt","Tasks","getArtifactContentUrl","artifactId","openArtifactViewer","_modal","ZOOM_RANGES","LANE_HEIGHT","TIME_AXIS_HEIGHT","EVENTS_STRIP_HEIGHT","MIN_BAR_WIDTH","REANCHOR_RATIO","STATUS_COLORS","shortLabel","parseTs","taskStartMs","taskEndMs","bgStartMs","bgEndMs","chooseTickStep","rangeMs","formatTickLabel","canvasWrapRef","setMode","zoom","setZoom","streamOpen","setStreamOpen","bgInstances","setBgInstances","events","setEvents","refreshTick","setRefreshTick","nowTick","setNowTick","viewStart","setViewStart","canvasSize","setCanvasSize","selectedItem","setSelectedItem","commentText","setCommentText","taskTitle","setTaskTitle","taskPriority","setTaskPriority","bgMessage","setBgMessage","bgOutput","setBgOutput","creatingTask","setCreatingTask","postingComment","setPostingComment","bgArtifactIds","setBgArtifactIds","rangeStart","rangeEnd","reloadAll","bgRes","evRes","useLayoutEffect","ro","lanes","bg","start","end","taskLaneEnds","assigned","laneById","timeToX","ticks","step","startAligned","bars","lane","visibleStart","visibleEnd","xEnd","statusClass","eventMarkers","ev","laneRects","nowX","onSelectBar","bar","bgData","artR","onAddComment","onCreateTaskFromNode","onSendBgMessage","onKillBg","refetchOutput","refresh","contentHeight","ActivityIcon","Pause","z","History","PanelLeftClose","PanelLeftOpen","Layers","Target","lr","fillColor","levenshtein","alen","blen","matrix","j","indicator","scoreField","query","field","words","word","compareLen","fuzzySearch","labelScore","valueScore","descScore","max","matchedField","matchedTerm","RECENT_KEY","getRecentSearches","stored","saveRecentSearch","recent","highlightMatch","escaped","regex","part","toSearchableItems","SettingsSearch","onJump","matches","setMatches","highlighted","setHighlighted","focused","setFocused","debounceRef","highlightTimerRef","allItems","immediate","run","jumpToSection","sectionId","fieldEl","sectionEl","highlightSection","commitSelection","handleKey","handleRecentClick","term","clearRecent","showRecent","THEMES","Moon","Sun","Monitor","PRESET_THEMES","FONT_FAMILIES","ThemeSection","patchTheme","patchUi","NetworkSection","tailscale","tailscaleDraft","setTailscaleDraft","onTailscaleToggle","ServerIcon","Plug","NotificationsSection","patchNotifications","AuthSection","authStatus","setAuthStatus","authToken","setAuthToken","revealedToken","setRevealedToken","onCopyToken","onRegenerateToken","onSaveToken","KeyRound","Copy","RotateCcw","AgentSection","patchAgents","patchDashboard","autoSave","pluginOptions","setPluginOptions","onSavePluginOptions","onCleanupBackground","Globe","AutosaveField","lines","onBlur","rawLines","warnings","line","InviteDialog","workspaceId","onInviteCreated","email","setEmail","role","setRole","invites","setInvites","copied","setCopied","loadInvites","Link2","handleRevoke","token","copyToClipboard","roleColors","Mail","inv","ROLE_ICONS","Crown","ROLE_COLORS","WorkspacesSection","workspaces","setWorkspaces","newName","setNewName","loadWorkspaces","copyInviteLink","workspace","RoleIcon","SECTION_LINKS","SETTINGS_SECTIONS","SettingsViewInner","initial","setSettingsActiveSection","setSettings","dirty","setDirty","saving","setSaving","setTailscale","handleExitSettings","applyThemeTokens","autoSaveTimeoutRef","patch","patchTop","localActiveSection","setLocalActiveSection","hash","handleJumpSection","onSave","applyTheme","onReload","onReset","sp","about","showAll","sectionOf","UpdatesSection","GeneralSection","EnvVarsSection","TailscaleSettings","SystemLlmSection","HeadroomSection","ActivitySection","SettingsView","PERMISSION_LABELS","Settings","PluginPermissions","permissions","perm","MarketplacePluginCard","plugin","onInstall","onView","InstallConfirmDialog","onConfirm","onCancel","installing","openedForRef","Marketplace","registry","setRegistry","category","setCategory","setInstalling","setSelected","refreshing","setRefreshing","fetchRegistry","opts","install","plugins","categories","sourceUrl","isCached","cacheTimestamp","Mods","modViews","setModViews","iframeUrl","setIframeUrl","registryOpen","setRegistryOpen","registryLoading","setRegistryLoading","loadRegistry","onInstallFromRegistry","onUpgradeFromRegistry","backup","backupNote","pathEl","onUninstall","onToggleEnabled","mod","ModDetails","ShieldCheck","rm","installed","isInstalling","instructions","setInstructions","instructionsLoading","setInstructionsLoading","instructionsOpen","setInstructionsOpen","expandedFile","setExpandedFile","loadInstructions","onReinstallInstructions","FileCode","User","BookOpen","Toggle","forwardRef","rest","PluginCard","onConfigure","Plugins","setPlugins","toggle","uninstall","configure","_id","ModView","viewId","reloadKey","view","setView","iframeReload","setIframeReload","found","src","componentPath","modId","ModComponent","lazy","__vitePreload","LayoutTemplate","ErrorBoundary","Suspense","ReactComponent","formatSchedule","template","secs","ScheduleTemplateCard","onUse","TYPES","ACTIONS","TIMEZONES","MINUTE_OPTIONS","HOUR_OPTIONS","DOW_OPTIONS","INTERVAL_UNITS","parseCronFields","expr","dow","minNum","hourNum","dowClean","parseIntervalParts","buildInitialState","parsedInterval","tz","tzKnown","toDatetimeLocal","iso","pad","composeSchedule","cron","dowName","hourLabel","minute","human","unit","u","Schedules","schedules","setSchedules","setActiveSection","setTemplates","templatesLoading","setTemplatesLoading","loadTemplates","openEditor","ScheduleEditorModal","saved","copy","onRun","onUseTemplate","humanizeSchedule","PlayCircle","resultTagClass","truncate","formatNextRun","onSubmitted","onError","setState","tzSelectValue","update","handleSubmit","trimmedName","composed","actionPayload","payload","Package","SOURCE_LABEL","SOURCE_ICON","SkillsInner","skills","setSkills","counts","setCounts","searchQ","setSearchQ","searchResults","setSearchResults","searching","setSearching","displayed","onShowDetail","skill","SkillCard","onShow","desc","Skills","MemoryOverview","setActiveSubPanel","vaultPath","setVaultPath","signal","storage","ctrl","vault","scoreColor","StatCard","Database","formatBytes","sub","Comp","LightragPanel","config","setConfig","logTail","setLogTail","setBusy","queryResult","setQueryResult","log","runCommand","fn","successMsg","onStart","onStop","onReindex","onRebuild","onQuery","Loader2","PowerOff","StatBox","FileTextCount","ObsidianPanel","notes","setNotes","setTree","backlinks","setBacklinks","pathSet","relPath","NoteEditor","frontmatter","note","rp","sortedNotes","countFolders","TreeView","FilePlus","titleOf","NoteDetail","acc","setNote","links","setRelPath","frontmatterYaml","setFrontmatterYaml","yamlStringify","setBody","onSubmit","fm","yamlParse","obj","yamlScalar","kk","vv","block","isList","isMap","parseScalar","nm","GitSyncPanel","setStatus","diff","setDiff","onPull","onPush","onCommit","onFetch","isLocal","Pill","GitCommit","GitPullRequest","GitMerge","SemanticSearchPanel","sources","setSources","lastQuery","setLastQuery","onSearch","activeSources","obs","ToggleChip","ConfigPanel","cfg","setCfg","remoteUrl","setRemoteUrl","memoryStatus","setMemoryStatus","vaultPathDraft","setVaultPathDraft","pathInitialising","setPathInitialising","pathSaving","setPathSaving","syncStatus","setSyncStatus","actionLoading","setActionLoading","tests","setTests","testing","setTesting","cfgRes","statusRes","loadSyncStatus","onSaveVaultPath","onInitVault","runAction","onTest","initialised","currentVaultPath","FolderInput","Row","GitCommitHorizontal","Upload","inline","CANVAS_SIZE","ITERATIONS","GROUP_COLORS","getGroupColor","nodeRadius","layoutNodes","nodes","edges","adj","angle","iter","dist","force","fx","fy","MemoryGraphView","onNodeClick","svgRef","transform","setTransform","dragging","dragStart","lastTouchDist","selectedId","setSelectedId","hoveredId","setHoveredId","nodeMap","onMouseDown","onMouseMove","onMouseUp","onWheel","factor","svg","mx","my","newScale","scaleChange","onTouchStart","touches","t0","t1","onTouchMove","onTouchEnd","handleNodeClick","strokeWidth","edge","tgt","isHighlighted","isHovered","LEGEND_ITEMS","MemoryGraphLegend","MemoryGraphPanel","setDepth","setRoot","selectedNode","setSelectedNode","fetchGraph","params","filteredData","Network","ScreenshotCapture","onTextExtracted","imageUrl","setImageUrl","processing","setProcessing","capturing","setCapturing","capture","stream","video","canvas","processImage","reader","base64","resolve","b64","dismiss","Camera","ScreenshotOCR","ocrText","setOcrText","notePath","setNotePath","handleTextExtracted","FromScreenshotPanel","_refreshKey","VaultFromClipboardPanel","setUrl","setContent","handleSave","Clipboard","VoiceRecorder","onSaved","recording","setRecording","transcribing","setTranscribing","mediaRecorderRef","chunksRef","startRecording","mimeType","recorder","uploadAndTranscribe","stopRecording","rec","form","transcription","Mic","Square","NoteCard","playing","setPlaying","audio","togglePlay","VoiceNotesPanel","loadNotes","vaultParam","handleMessage","wsUrl","ws","SOURCES","Scan","MemoryInner","_props","setActive","setRefreshKey","onRefreshAll","renderPanel","Memory","TIME_RANGES","renderProjectCard","toggleProject","isOpen","rangeId","setRangeId","since","range","eventsByProject","pid","onExportJson","Filter","PADDING","UsageChart","series","onHover","containerRef","tooltip","setTooltip","labels","requests","tokens","innerW","innerH","maxReq","maxTok","barW","gap","barX","barH","lineY","linePoints","leftTicks","rightTicks","labelStep","xLabels","handleMouseMove","svgX","svgY","relX","clamped","handleMouseLeave","tip","bh","bx","by","SortHeader","sortKey","sortDir","onSort","UsageTable","MiniMaxUsageInner","BarChart2","QuotaView","AnalyticsView","remains","setRemains","onboarding","setOnboarding","testResult","setTestResult","wizardStep","setWizardStep","wizardVerifying","setWizardVerifying","wizardVerifyResult","setWizardVerifyResult","keyDraft","setKeyDraft","showKey","setShowKey","savingKey","setSavingKey","dismissWizard","verifyKeyBeforeSave","clearRemainsCacheClient","saveKey","sendTest","OnboardingWizard","relativeTime","ModelQuotaCard","setRange","customFrom","setCustomFrom","customTo","setCustomTo","setRecent","setSortKey","setSortDir","fromMs","toMs","handleSort","sortedModels","av","bv","cmp","chartSeries","errors","perKey","KpiCard","fivePct","clamp","weekPct","fiveConsumed","weekConsumed","QuotaBar","Calendar","remainingPct","consumedPct","used","total","resetIn","resetISO","lo","hi","setStep","verifying","verifyResult","onVerify","onSkip","onManualKeySave","CircleCheck","MiniMaxUsage","STATUS_KIND","STATUS_LABELS","BgStatusBadge","KillConfirmDialog","instanceId","instanceName","openKillConfirmDialog","onSuccess","TmuxAttachCard","instance","opening","setOpening","sessionName","attachCommand","copyCommand","openTerminal","DEFAULT_AGENTS","TIMEOUT_PRESETS","SpawnAgentModal","onCreated","setPrompt","timeoutMs","setTimeoutMs","persistent","setPersistent","tagsRaw","setTagsRaw","POLL_INTERVAL_MS","OUTPUT_REFRESH_MS","PROMPT_TRUNCATE","STREAM_BUFFER_LIMIT","isPaused","formatDuration","BackgroundAgents","instances","setInstances","showSpawn","setShowSpawn","Ws","off","onOpenOutput","openOutputModal","onOpenTmux","openTmuxModal","onKill","onPause","onResume","onSteer","openSteerModal","BackgroundAgentCard","inst","onViewOutput","startedMs","startedLabel","durationMs","progress","PauseCircle","OutputModalBody","bufRef","output","setOutput","available","setAvailable","streamingActive","setStreamingActive","toolCalls","setToolCalls","showToolCalls","setShowToolCalls","refBottom","refAutoscroll","recomputeOutput","offStatus","offMsg","onScroll","atBottom","ToolCallHistory","calls","dur","TmuxModalBody","SteerModalBody","setMessage","onCopy","CATEGORY_DEFAULTS","Wrench","statusIcon","CircleDot","statusLabel","DoctorPanel","checks","meta","def","hasContent","CheckIcon","REFRESH_INTERVAL_MS","DoctorInner","lastFetched","setLastFetched","autoRefresh","setAutoRefresh","cancelledRef","fetchSnapshot","onRunCheck","checkName","onViewLogs","countsInfo","overall","OverallIcon","overallLabel","Doctor","pickStatus","EvalRunCard","ariaLabel","passRate","interactive","RECENT_RUNS_LIMIT","AddScheduleForm","onAdded","suitePath","setSuitePath","setCron","EvalInner","runs","setRuns","subTab","setSubTab","loadingSchedules","setLoadingSchedules","showAddSchedule","setShowAddSchedule","loadSchedules","deleteSchedule","totals","overallRate","ArrowRight","newSchedule","Eval","computeEvalDiff","runA","runB","mapA","mapB","ids","change","order","EvalDiff","improved","regressed","unchanged","changed","EvalExportButton","runId","size","RunDetail","onClearCompare","compareRun","onClearSelection","runsForDiff","sortedResults","baseRun","ArrowLeftRight","EvalReportInner","loadingRuns","setLoadingRuns","selectedRunId","setSelectedRunId","compareRunId","setCompareRunId","setDetail","detailLoading","setDetailLoading","compareDetail","setCompareDetail","loadRuns","loadDetail","loadCompareDetail","selectRun","useAsBaseline","EvalReport","VIEW_MAP","Overview","Config","VERSION","renderActiveView","viewProps","V","mv","TokenEntryForm","setValue","App","ToastProvider","Shell","modalApi","isModalOpen","isModalOpenRef","setSnapshot","setWsStatus","bootError","setBootError","setSettingsMode","authPromptOpen","setAuthPromptOpen","searchOpen","setSearchOpen","stuckAgents","setStuckAgents","stuckBannerDismissed","setStuckBannerDismissed","modViewsReloadKey","setModViewsReloadKey","wsRef","setWs","mql","retryBoot","loadBootData","applyBootData","snap","stuck","auth","retrySnap","retrySet","retryStuck","ApiError","defaultTab","file","exists","subscribeToWs","safeUntilRef","bump","map","activeEl","isFormControl","inForm","handleTabChange","mergedTabs","renderedView","refreshProjects","onActivateProject","onSearchSelect","settingId","tryScroll","tries","showHeader","ViewErrorBoundary","Component","Root","isMobile","setIsMobile","MobileApp","createRoot","StrictMode"],"ignoreList":[],"sources":["../../src/web/components/Modal.tsx","../../src/web/components/FileBrowser.tsx","../../src/web/components/Topbar.tsx","../../src/web/components/SettingsNav.tsx","../../src/web/components/Sidebar.tsx","../../src/web/components/SearchModal.tsx","../../src/web/components/Notifications.tsx","../../src/web/components/VisualPlanDialog.tsx","../../src/web/components/ArtifactCreateDialog.tsx","../../src/web/components/ArtifactListDialog.tsx","../../src/web/components/HelpDialog.tsx","../../src/web/components/AuditDialog.tsx","../../src/web/components/CommandDialog.tsx","../../src/web/views/memory/MemoryStatusCard.tsx","../../src/web/components/EmptyState.tsx","../../src/web/views/Overview.tsx","../../src/web/components/chat/EmptyState.tsx","../../src/web/components/chat/SessionRowMenu.tsx","../../src/web/components/chat/AgentNode.tsx","../../src/web/components/chat/AgentTree.tsx","../../src/web/components/chat/ChatRail.tsx","../../src/web/components/chat/ChatComposer.tsx","../../src/web/components/chat/ChatInfoPanel.tsx","../../src/web/components/chat/JumpToLatest.tsx","../../src/web/views/Chat.tsx","../../src/web/components/StatusBadge.tsx","../../src/web/views/Agents.tsx","../../src/web/views/glyphs/components.tsx","../../src/web/views/glyphs/GlyphRenderer.tsx","../../src/web/views/Artifacts.tsx","../../src/web/components/Tag.tsx","../../src/web/components/tasks/BacklogPanel.tsx","../../src/web/views/Tasks.tsx","../../src/web/components/ArtifactViewer.tsx","../../src/web/views/Activity.tsx","../../src/web/lib/search.ts","../../src/web/components/SettingsSearch.tsx","../../src/web/views/settings/ThemeSection.tsx","../../src/web/views/settings/NetworkSection.tsx","../../src/web/views/settings/NotificationsSection.tsx","../../src/web/views/settings/AuthSection.tsx","../../src/web/views/settings/AgentSection.tsx","../../src/web/components/InviteDialog.tsx","../../src/web/views/settings/WorkspacesSection.tsx","../../src/web/views/Settings.tsx","../../src/web/components/PluginPermissions.tsx","../../src/web/components/MarketplacePluginCard.tsx","../../src/web/components/InstallConfirmDialog.tsx","../../src/web/views/Marketplace.tsx","../../src/web/views/Mods.tsx","../../src/web/components/Toggle.tsx","../../src/web/components/PluginCard.tsx","../../src/web/views/Plugins.tsx","../../src/web/views/ModView.tsx","../../src/web/components/ScheduleTemplateCard.tsx","../../src/web/views/Schedules.tsx","../../src/web/views/Skills.tsx","../../src/web/views/memory/MemoryOverview.tsx","../../src/web/views/memory/LightragPanel.tsx","../../src/web/views/memory/ObsidianPanel.tsx","../../src/web/views/memory/GitSyncPanel.tsx","../../src/web/views/memory/SemanticSearchPanel.tsx","../../src/web/views/memory/ConfigPanel.tsx","../../src/web/views/memory/MemoryGraphView.tsx","../../src/web/views/memory/MemoryGraphLegend.tsx","../../src/web/views/memory/MemoryGraphPanel.tsx","../../src/web/components/ScreenshotCapture.tsx","../../src/web/components/ScreenshotOCR.tsx","../../src/web/views/memory/FromScreenshotPanel.tsx","../../src/web/views/memory/VaultFromClipboardPanel.tsx","../../src/web/components/VoiceRecorder.tsx","../../src/web/components/VoiceNotesPanel.tsx","../../src/web/views/Memory.tsx","../../src/web/views/History.tsx","../../src/web/components/UsageChart.tsx","../../src/web/components/UsageTable.tsx","../../src/web/views/MiniMaxUsage.tsx","../../src/web/components/BgStatusBadge.tsx","../../src/web/components/KillConfirmDialog.tsx","../../src/web/components/background/TmuxAttachCard.tsx","../../src/web/views/SpawnAgentModal.tsx","../../src/web/views/BackgroundAgents.tsx","../../src/web/components/DoctorPanel.tsx","../../src/web/views/Doctor.tsx","../../src/web/components/EvalRunCard.tsx","../../src/web/views/Eval.tsx","../../src/web/components/EvalDiff.tsx","../../src/web/components/EvalExportButton.tsx","../../src/web/views/EvalReport.tsx","../../src/web/App.tsx","../../src/web/main.tsx"],"sourcesContent":["// src/components/Modal.tsx — modal context + provider + portal.\n\nimport {\n createContext,\n useId,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { X } from 'lucide-react';\n\nexport type ModalProps = {\n title?: string;\n children: ReactNode;\n footer?: ReactNode;\n onClose?: () => void;\n width?: number;\n};\n\nexport type ModalApi = {\n open: (props: ModalProps) => string;\n close: (id?: string) => void;\n isModalOpen: boolean;\n};\n\nconst ModalContext = createContext<ModalApi | null>(null);\n\nconst FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n '[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ');\n\nexport function useModal(): ModalApi {\n const ctx = useContext(ModalContext);\n if (!ctx) {\n return { open: () => '', close: () => undefined, isModalOpen: false };\n }\n return ctx;\n}\n\ntype OpenModal = ModalProps & { id: string };\n\nexport function ModalProvider({ children }: { children: ReactNode }) {\n const [stack, setStack] = useState<OpenModal[]>([]);\n\n const close = useCallback((id?: string) => {\n setStack((cur) => {\n if (!id) return cur.slice(0, -1);\n const idx = cur.findIndex((m) => m.id === id);\n if (idx === -1) return cur;\n // close only the top-most matching\n if (idx !== cur.length - 1) return cur;\n return cur.slice(0, -1);\n });\n }, []);\n\n const open = useCallback((props: ModalProps) => {\n const id = `m${Math.random().toString(36).slice(2, 9)}`;\n setStack((cur) => [...cur, { ...props, id }]);\n return id;\n }, []);\n\n // Escape key — close the topmost\n useEffect(() => {\n if (stack.length === 0) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n close();\n }\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [stack.length, close]);\n\n return (\n <ModalContext.Provider value={{ open, close, isModalOpen: stack.length > 0 }}>\n {children}\n {typeof document !== 'undefined' &&\n createPortal(\n <div className=\"modal-stack\" aria-hidden={stack.length === 0}>\n {stack.map((m, idx) => (\n <ModalShell\n key={m.id}\n modal={m}\n onClose={() => {\n m.onClose?.();\n close(m.id);\n }}\n depth={idx}\n />\n ))}\n </div>,\n document.body,\n )}\n </ModalContext.Provider>\n );\n}\n\nfunction ModalShell({\n modal,\n onClose,\n depth,\n}: {\n modal: OpenModal;\n onClose: () => void;\n depth: number;\n}) {\n const modalRef = useRef<HTMLDivElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const titleId = useId();\n\n const getFocusableElements = (): HTMLElement[] => {\n const root = modalRef.current;\n if (!root) return [];\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (el) => !el.hasAttribute('disabled') && el.tabIndex !== -1,\n );\n };\n\n useEffect(() => {\n previousFocusRef.current = document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n const focusable = getFocusableElements();\n (focusable[0] ?? modalRef.current)?.focus();\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const focusableElements = getFocusableElements();\n if (focusableElements.length === 0) {\n e.preventDefault();\n modalRef.current?.focus();\n return;\n }\n\n const first = focusableElements[0];\n const last = focusableElements[focusableElements.length - 1];\n const active = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n\n if (e.shiftKey) {\n if (!active || active === first || !modalRef.current?.contains(active)) {\n e.preventDefault();\n last.focus();\n }\n return;\n }\n\n if (!active || active === last || !modalRef.current?.contains(active)) {\n e.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('keydown', onKeyDown);\n const previous = previousFocusRef.current;\n if (previous && previous.isConnected) previous.focus();\n };\n }, []);\n\n // v3.3.0 — Backdrop click stops propagation. This stops a click on\n // the dim area from bubbling to the document/App level where it\n // could otherwise be misread by the digit-key shortcut handler\n // (the click that closes the modal would otherwise leave focus on\n // <body>, and any subsequent accidental digit press would fire\n // setActiveTab(\"overview\")). The click itself only fires onClose()\n // when the user actually clicked the backdrop, not a child.\n return (\n <div\n className=\"modal-backdrop\"\n onClick={(e) => {\n e.stopPropagation();\n if (e.target === e.currentTarget) onClose();\n }}\n style={depth > 0 ? { background: 'rgba(0,0,0,0.4)' } : undefined}\n >\n <div\n ref={modalRef}\n className=\"modal\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={modal.title ? titleId : undefined}\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n style={modal.width ? { maxWidth: modal.width } : undefined}\n >\n {modal.title && (\n <header className=\"modal-header\">\n <h2 id={titleId} className=\"modal-title\">{modal.title}</h2>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n <X size={16} />\n </button>\n </header>\n )}\n <div className=\"modal-body\">{modal.children}</div>\n {modal.footer && <footer className=\"modal-footer\">{modal.footer}</footer>}\n </div>\n </div>\n );\n}\n","// src/components/FileBrowser.tsx — Interactive directory browser with tree + flat pane.\n// Replaces raw path text inputs in Add Project dialogs.\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { ChevronRight, ChevronDown, FolderOpen, Folder, File, RefreshCw, ArrowLeft, Home, AlertCircle, FolderPlus } from 'lucide-react';\nimport { api } from '../lib/api';\nimport type { DirectoryEntry, DirectoryListing, MkdirRequest, MkdirResponse } from '../lib/types';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type FileBrowserProps = {\n /** Currently selected directory (absolute path). */\n value: string;\n /** Fires when the user selects a directory. */\n onChange: (path: string) => void;\n /** Where the browser starts (default: homedir via GET /api/fs with no path). */\n initialPath?: string;\n /** If set, used as default initialPath and shown as a quick-jump chip. */\n projectsDirectory?: string;\n /** Label for the filesystem-root breadcrumb (default: \"Home\"). */\n rootLabel?: string;\n /** Scroll viewport height in px (default: 360). */\n height?: number;\n};\n\n// ─── Cache (LRU-ish, 200 entries max, 5-minute TTL) ───────────────────────────\n\nconst MAX_CACHE = 200;\nconst TTL_MS = 5 * 60 * 1000;\n\ntype CacheEntry = { data: DirectoryListing; ts: number };\n\nconst _cache = new Map<string, CacheEntry>();\n\nfunction cacheGet(path: string): DirectoryListing | null {\n const entry = _cache.get(path);\n if (!entry) return null;\n if (Date.now() - entry.ts > TTL_MS) { _cache.delete(path); return null; }\n return entry.data;\n}\n\nfunction cacheSet(path: string, data: DirectoryListing) {\n if (_cache.size >= MAX_CACHE) {\n // Evict oldest 50\n const oldest = [..._cache.entries()]\n .sort((a, b) => a[1].ts - b[1].ts)\n .slice(0, 50)\n .map(([k]) => k);\n oldest.forEach((k) => _cache.delete(k));\n }\n _cache.set(path, { data, ts: Date.now() });\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction pathSegments(p: string): { label: string; path: string }[] {\n if (!p || p === '/') return [{ label: '/', path: '/' }];\n const parts = p.split('/').filter(Boolean);\n const result: { label: string; path: string }[] = [];\n let accumulated = '';\n for (let i = 0; i < parts.length; i++) {\n accumulated += '/' + parts[i];\n result.push({ label: parts[i], path: accumulated });\n }\n return result;\n}\n\nfunction sortEntries(entries: DirectoryEntry[]): DirectoryEntry[] {\n return [...entries].sort((a, b) => {\n if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });\n });\n}\n\n/**\n * Validates a directory name against the same denylist the server enforces.\n * Returns an ok object or { ok: false, reason }.\n * Mirrors the validation in POST /api/fs/mkdir on the server side.\n */\nexport function validateDirName(name: string): { ok: true } | { ok: false; reason: string } {\n const trimmed = name.trim();\n if (!trimmed) return { ok: false, reason: 'Name cannot be empty.' };\n if (trimmed !== name) return { ok: false, reason: 'Name cannot have leading or trailing whitespace.' };\n if (trimmed === '.') return { ok: false, reason: \"Name cannot be '.'.\" };\n if (trimmed === '..') return { ok: false, reason: \"Name cannot be '..'.\" };\n if (trimmed.startsWith('-')) return { ok: false, reason: \"Name cannot start with '-'.\" };\n if (trimmed.length > 255) return { ok: false, reason: 'Name cannot be longer than 255 characters.' };\n if (/[/\\0:*?\"<>|]/.test(trimmed)) {\n return { ok: false, reason: \"Name cannot contain / \\\\ : * ? \\\" < > |\" };\n }\n return { ok: true };\n}\n\n// ─── Component ─────────────────────────────────────────────────────────────────\n\nexport function FileBrowser({\n value,\n onChange,\n initialPath,\n projectsDirectory,\n rootLabel = 'Home',\n height = 360,\n}: FileBrowserProps) {\n const [currentPath, setCurrentPath] = useState<string>(\n initialPath ?? projectsDirectory ?? '',\n );\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [selectedRow, setSelectedRow] = useState<number>(-1);\n const [listing, setListing] = useState<DirectoryListing | null>(null);\n const [childrenMap, setChildrenMap] = useState<Record<string, DirectoryEntry[]>>({});\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [mkdirOpen, setMkdirOpen] = useState(false);\n const [mkdirName, setMkdirName] = useState('');\n const [mkdirError, setMkdirError] = useState<string | null>(null);\n const [mkdirLoading, setMkdirLoading] = useState(false);\n const mkdirInputRef = useRef<HTMLInputElement | null>(null);\n\n const fetchListing = useCallback(async (path: string): Promise<DirectoryListing | null> => {\n try {\n const cached = cacheGet(path);\n if (cached) return cached;\n const data = await api.get<DirectoryListing>('/fs?path=' + encodeURIComponent(path));\n cacheSet(path, data);\n return data;\n } catch {\n return null;\n }\n }, []);\n\n const load = useCallback(async (path: string) => {\n setLoading(true);\n setError(null);\n try {\n const data = await api.get<DirectoryListing>('/fs?path=' + encodeURIComponent(path));\n cacheSet(path, data);\n setListing(data);\n setSelectedRow(-1);\n } catch (err) {\n const msg = (err as { data?: { message?: string }; message?: string }).data?.message\n ?? (err as Error).message\n ?? 'Failed to load directory';\n setError(msg);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Load current path on mount or when currentPath changes\n useEffect(() => {\n if (!currentPath) {\n // Default to homedir by fetching empty-path listing\n api.get<DirectoryListing>('/fs').then((data) => {\n cacheSet('', data);\n setListing(data);\n setCurrentPath(data.path);\n if (data.path !== value) onChange(data.path);\n }).catch(() => {\n setError('Could not determine home directory.');\n setLoading(false);\n });\n } else {\n load(currentPath);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [currentPath]);\n\n // Keep selected path in sync when value changes externally (e.g. breadcrumb click)\n useEffect(() => {\n if (value && value !== currentPath) {\n setCurrentPath(value);\n }\n }, [value]);\n\n const entries = listing ? sortEntries(listing.entries) : [];\n\n const dirs = entries.filter((e) => e.isDir);\n const allEntries = entries;\n\n // ─── Navigation helpers ──────────────────────────────────────────────────────\n\n const navigateInto = (entry: DirectoryEntry) => {\n if (!entry.isDir) return;\n setCurrentPath(entry.path);\n onChange(entry.path);\n };\n\n const navigateUp = () => {\n if (!listing?.parent) return;\n setCurrentPath(listing.parent);\n onChange(listing.parent);\n };\n\n const navigateTo = (path: string) => {\n if (path === currentPath) return;\n setCurrentPath(path);\n onChange(path);\n };\n\n const goHome = async () => {\n const home = await fetchListing('');\n if (home) {\n setCurrentPath(home.path);\n onChange(home.path);\n }\n };\n\n const goProjects = async () => {\n if (!projectsDirectory) return;\n const pd = await fetchListing(projectsDirectory);\n if (pd) {\n setCurrentPath(pd.path);\n onChange(pd.path);\n }\n };\n\n // ─── New folder ────────────────────────────────────────────────────────────\n\n // Open the inline mkdir input, focusing it on the next tick\n const openMkdir = () => {\n setMkdirOpen(true);\n setMkdirName('');\n setMkdirError(null);\n // Autofocus after the input renders\n setTimeout(() => mkdirInputRef.current?.focus(), 0);\n };\n\n const cancelMkdir = () => {\n setMkdirOpen(false);\n setMkdirName('');\n setMkdirError(null);\n };\n\n const submitMkdir = async () => {\n const v = validateDirName(mkdirName);\n if (!v.ok) {\n setMkdirError(v.reason);\n return;\n }\n setMkdirLoading(true);\n setMkdirError(null);\n try {\n const result = await api.post<MkdirResponse>('/fs/mkdir', {\n parent: currentPath,\n name: mkdirName.trim(),\n } as MkdirRequest);\n // Invalidate cache for the current path so the new folder appears\n _cache.delete(currentPath);\n await load(currentPath);\n // Select the new directory\n onChange(result.path);\n setMkdirOpen(false);\n setMkdirName('');\n } catch (err) {\n const apiErr = err as { data?: { message?: string }; status?: number };\n if (apiErr.status === 409) {\n setMkdirError(`A folder named \"${mkdirName.trim()}\" already exists.`);\n } else {\n setMkdirError(\n apiErr.data?.message ??\n (err as Error).message ??\n 'Failed to create folder.',\n );\n }\n } finally {\n setMkdirLoading(false);\n }\n };\n\n const handleMkdirKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n submitMkdir();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n cancelMkdir();\n }\n };\n\n const toggleExpand = (path: string) => {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(path)) next.delete(path);\n else next.add(path);\n return next;\n });\n // Lazy-load children when expanding\n if (!childrenMap[path]) {\n fetchListing(path).then((data) => {\n if (data) setChildrenMap((prev) => ({ ...prev, [path]: data.entries.filter((e) => e.isDir) }));\n });\n }\n };\n\n // ─── Keyboard handler ────────────────────────────────────────────────────────\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (!listing) return;\n const dirs = allEntries.filter((x) => x.isDir);\n const files = allEntries.filter((x) => !x.isDir);\n const selectable = [...dirs, ...files];\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setSelectedRow((r) => Math.min(r + 1, selectable.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setSelectedRow((r) => Math.max(r - 1, 0));\n } else if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n const sel = selectable[selectedRow];\n if (sel) {\n if (e.key === 'Enter' && sel.isDir) navigateInto(sel);\n else if (!sel.isDir) { /* files are not selectable */ }\n else onChange(sel.path);\n }\n } else if (e.key === 'Backspace') {\n e.preventDefault();\n navigateUp();\n }\n };\n\n // ─── Render ─────────────────────────────────────────────────────────────────\n\n const segments = pathSegments(listing?.path ?? currentPath ?? '/');\n const parentPath = listing?.parent;\n const canGoUp = parentPath !== null && parentPath !== undefined;\n\n const basename = currentPath.split('/').filter(Boolean).at(-1) ?? '/';\n\n return (\n <div className=\"file-browser\" onKeyDown={handleKeyDown} tabIndex={-1}>\n {/* Breadcrumb */}\n <div className=\"file-browser-breadcrumb\" role=\"navigation\" aria-label=\"Path breadcrumb\">\n {segments.map((seg, i) => (\n <span key={seg.path} className=\"file-browser-breadcrumb-item\">\n {i > 0 && <span className=\"file-browser-breadcrumb-sep\" aria-hidden>/</span>}\n <button\n type=\"button\"\n className=\"file-browser-breadcrumb-btn\"\n onClick={() => navigateTo(seg.path)}\n title={seg.path}\n >\n {i === 0 ? (seg.path === '/' ? '/' : rootLabel) : seg.label}\n </button>\n </span>\n ))}\n </div>\n\n {/* Toolbar */}\n <div className=\"file-browser-toolbar\">\n <div className=\"file-browser-toolbar-left\">\n <button\n type=\"button\"\n className=\"file-browser-tool-btn\"\n onClick={navigateUp}\n disabled={!canGoUp}\n title=\"Go up (Backspace)\"\n aria-label=\"Go up one level\"\n >\n <ArrowLeft size={13} />\n </button>\n\n <button\n type=\"button\"\n className=\"file-browser-tool-btn\"\n onClick={() => load(currentPath)}\n disabled={loading}\n title=\"Refresh\"\n aria-label=\"Refresh\"\n >\n <RefreshCw size={13} className={loading ? 'spin' : ''} />\n </button>\n\n <button\n type=\"button\"\n className=\"file-browser-tool-btn\"\n onClick={openMkdir}\n title=\"New folder\"\n aria-label=\"Create new folder\"\n >\n <FolderPlus size={13} />\n </button>\n\n <div className=\"file-browser-chips\">\n <button type=\"button\" className=\"file-browser-chip\" onClick={goHome}>\n <Home size={11} /> {rootLabel}\n </button>\n {projectsDirectory && (\n <button type=\"button\" className=\"file-browser-chip\" onClick={goProjects} title={projectsDirectory}>\n <FolderOpen size={11} /> {projectsDirectory.split('/').filter(Boolean).at(-1) ?? 'Projects'}\n </button>\n )}\n </div>\n </div>\n\n {mkdirOpen ? (\n <div className=\"file-browser-mkdir\">\n <input\n ref={mkdirInputRef}\n type=\"text\"\n className=\"file-browser-mkdir-input\"\n placeholder=\"Folder name\"\n value={mkdirName}\n onChange={(e) => {\n setMkdirName(e.target.value);\n setMkdirError(null);\n }}\n onKeyDown={handleMkdirKeyDown}\n aria-label=\"New folder name\"\n aria-invalid={mkdirError ? 'true' : undefined}\n aria-describedby={mkdirError ? 'mkdir-error' : undefined}\n disabled={mkdirLoading}\n maxLength={255}\n />\n {mkdirError ? (\n <span id=\"mkdir-error\" className=\"file-browser-mkdir-error\" role=\"alert\">\n {mkdirError}\n </span>\n ) : (\n <span className=\"file-browser-mkdir-hint\">\n Enter to create, Esc to cancel\n </span>\n )}\n </div>\n ) : (\n <span className=\"file-browser-count-hint\">\n {loading ? '…' : `${entries.length} in ${basename}`}\n </span>\n )}\n </div>\n\n {/* Error banner */}\n {error && (\n <div className=\"file-browser-error\">\n <AlertCircle size={13} />\n <span>{error}</span>\n <button type=\"button\" className=\"file-browser-retry\" onClick={() => load(currentPath)}>\n Retry\n </button>\n </div>\n )}\n\n {/* Body: tree (left) + flat (right) */}\n <div className=\"file-browser-body\" style={{ height }}>\n {/* Left: tree */}\n <div className=\"file-browser-pane file-browser-tree\" aria-label=\"Folder tree\">\n {loading && !listing ? (\n <TreeSkeleton />\n ) : (\n <TreeNode\n path={currentPath}\n entries={dirs}\n expanded={expanded}\n childrenMap={childrenMap}\n onToggle={toggleExpand}\n onNavigate={navigateInto}\n level={0}\n />\n )}\n </div>\n\n {/* Right: flat listing */}\n <div className=\"file-browser-pane file-browser-flat\" aria-label=\"Directory contents\">\n <div className=\"file-browser-flat-header\">\n <span>Name</span>\n <span>Type</span>\n </div>\n\n {loading && !listing ? (\n <FlatSkeleton />\n ) : (\n <>\n {/* Truncation notice */}\n {listing?.truncated && (\n <div className=\"file-browser-truncated-banner\" role=\"status\">\n Showing first 500 of {listing.totalEntries} entries.\n Navigate into a subfolder to see more.\n </div>\n )}\n\n {allEntries.length === 0 ? (\n <div className=\"file-browser-empty\">This folder is empty</div>\n ) : (\n <div className=\"file-browser-flat-list\">\n {allEntries.map((entry, idx) => {\n const isDir = entry.isDir;\n const isSelected = idx === selectedRow;\n const isActive = entry.path === value;\n return (\n <div\n key={entry.path}\n role=\"option\"\n aria-selected={isActive}\n className={[\n 'file-browser-row',\n isDir ? 'file-browser-row--dir' : 'file-browser-row--file',\n isSelected && 'file-browser-row--selected',\n isActive && isDir && 'file-browser-row--active',\n !isDir && 'file-browser-row--disabled',\n ].filter(Boolean).join(' ')}\n onClick={() => {\n if (isDir) {\n setSelectedRow(idx);\n onChange(entry.path);\n }\n }}\n onDoubleClick={() => {\n if (isDir) navigateInto(entry);\n }}\n title={entry.path}\n >\n <span className=\"file-browser-row-icon\">\n {isDir ? <Folder size={13} /> : <File size={13} />}\n </span>\n <span className=\"file-browser-row-name\">{entry.name}</span>\n <span className=\"file-browser-row-type\">\n {isDir ? 'Folder' : ''}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n\n {/* Footer hint */}\n <div className=\"file-browser-footer-hint\">\n Select a folder, then click Add. Use <kbd>↑</kbd> <kbd>↓</kbd> to navigate, <kbd>Enter</kbd> to confirm.\n </div>\n </div>\n );\n}\n\n// ─── TreeNode ─────────────────────────────────────────────────────────────────\n\nfunction TreeNode({\n path,\n entries,\n expanded,\n childrenMap,\n onToggle,\n onNavigate,\n level,\n}: {\n path: string;\n entries: DirectoryEntry[];\n expanded: Set<string>;\n childrenMap: Record<string, DirectoryEntry[]>;\n onToggle: (p: string) => void;\n onNavigate: (e: DirectoryEntry) => void;\n level: number;\n}) {\n return (\n <ul className=\"file-browser-tree-list\" role=\"group\">\n {entries.map((entry) => {\n const isExpanded = expanded.has(entry.path);\n const kids = childrenMap[entry.path] ?? [];\n return (\n <li key={entry.path} className=\"file-browser-tree-node\">\n <div\n className={[\n 'file-browser-tree-row',\n isExpanded && 'file-browser-tree-row--expanded',\n ].filter(Boolean).join(' ')}\n style={{ paddingLeft: `${level * 16 + 8}px` }}\n >\n <button\n type=\"button\"\n className=\"file-browser-tree-toggle\"\n onClick={(e) => { e.stopPropagation(); onToggle(entry.path); }}\n aria-label={isExpanded ? 'Collapse' : 'Expand'}\n >\n {kids.length > 0 || true ? (\n isExpanded ? <ChevronDown size={11} /> : <ChevronRight size={11} />\n ) : (\n <span style={{ width: 11 }} />\n )}\n </button>\n\n <button\n type=\"button\"\n className=\"file-browser-tree-name\"\n onClick={() => onNavigate(entry)}\n title={entry.path}\n >\n <Folder size={12} />\n <span>{entry.name}</span>\n </button>\n </div>\n\n {isExpanded && kids.length > 0 && (\n <TreeNode\n path={entry.path}\n entries={kids}\n expanded={expanded}\n childrenMap={childrenMap}\n onToggle={onToggle}\n onNavigate={onNavigate}\n level={level + 1}\n />\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n\n// ─── Skeletons ────────────────────────────────────────────────────────────────\n\nfunction TreeSkeleton() {\n return (\n <div className=\"file-browser-skeleton-wrap\">\n {[80, 60, 90, 55, 70].map((w, i) => (\n <div key={i} className=\"file-browser-skeleton-row\" style={{ width: w }} />\n ))}\n </div>\n );\n}\n\nfunction FlatSkeleton() {\n return (\n <div className=\"file-browser-skeleton-wrap\">\n {[60, 90, 70, 50, 80, 65].map((w, i) => (\n <div key={i} className=\"file-browser-skeleton-row\" style={{ width: w }} />\n ))}\n </div>\n );\n}\n","// src/components/Topbar.tsx — header with brand, project selector, search, tabs, ws status.\nimport { useEffect, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport {\n LayoutDashboard,\n MessageSquare,\n Bot,\n Map,\n Folder,\n CheckSquare,\n Settings2,\n Sliders,\n Puzzle,\n Clock,\n History as HistoryIcon,\n Search as SearchIcon,\n ChevronDown,\n Plus,\n RefreshCw,\n Power,\n Sparkles,\n Activity,\n Radio,\n Coins,\n Brain,\n Stethoscope,\n ClipboardCheck,\n Store,\n type LucideIcon,\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport type { ProjectRecord, WsStatus, WsMessage, Settings, DirectoryListing } from '../lib/types';\nimport { api } from '../lib/api';\nimport { useModal } from './Modal';\nimport { FileBrowser } from './FileBrowser';\nimport { Button } from './Button';\n\nexport type TabDef = {\n id: string;\n label: string;\n icon: LucideIcon;\n};\n\nexport const TABS: TabDef[] = [\n { id: 'overview', label: 'Overview', icon: LayoutDashboard },\n { id: 'chat', label: 'Chat', icon: MessageSquare },\n { id: 'agents', label: 'Agents', icon: Bot },\n { id: 'artifacts', label: 'Glyphs', icon: Map },\n { id: 'tasks', label: 'Tasks', icon: CheckSquare },\n { id: 'activity', label: 'Activity', icon: Activity },\n { id: 'background', label: 'Active', icon: Radio },\n { id: 'skills', label: 'Skills', icon: Sparkles },\n { id: 'memory', label: 'Memory', icon: Brain },\n { id: 'mods', label: 'Mods', icon: Puzzle },\n // v5.3.0 — Plugin marketplace browse + install UI.\n { id: 'marketplace', label: 'Marketplace', icon: Store },\n { id: 'schedules', label: 'Schedules', icon: Clock },\n { id: 'plugins', label: 'Plugins', icon: Puzzle },\n { id: 'history', label: 'History', icon: HistoryIcon },\n { id: 'minimax', label: 'Usage', icon: Coins },\n // v5.2.0 — Eval framework UI. Lives next to Doctor (both are\n // operator-quality surfaces) so the \"did the last eval pass?\"\n // question is one click from the home screen.\n { id: 'eval', label: 'Eval', icon: ClipboardCheck },\n // v6.0.0 — Doctor page. Lives between Overview and Settings so the\n // \"is everything healthy?\" question is always one click from the\n // home screen and from the settings surface (where an operator\n // typically arrives after something looks off).\n { id: 'doctor', label: 'Doctor', icon: Stethoscope },\n { id: 'settings', label: 'Settings', icon: Sliders },\n];\n\nexport type TopbarProps = {\n activeTab: string;\n onTabChange: (id: string) => void;\n wsStatus: WsStatus;\n version: string;\n activeProject: ProjectRecord | null;\n projects: ProjectRecord[];\n onProjectChange: (id: string) => void;\n onProjectsRefresh: () => void;\n onOpenSearch: () => void;\n settings?: Settings | null;\n rightSlot?: ReactNode;\n /**\n * v3.3.0 — Optional slot for the notifications bell. The host\n * (App.tsx) mounts the Notifications component here so it can\n * subscribe to the same WebSocket the rest of the app uses.\n */\n notificationsSlot?: ReactNode;\n /**\n * Whether to render the tabs row. In sidebar/both layouts the sidebar\n * carries navigation, so we hide this row to keep the topbar slim.\n */\n showTabs?: boolean;\n /**\n * v3.20.3 — Optional extra tabs (mod views) appended after the built-in\n * tabs. Each entry is the same shape as TabDef with an `id` matching\n * the mod view id (e.g. 'graphify:web').\n */\n extraTabs?: TabDef[];\n};\n\nexport function Topbar({\n activeTab,\n onTabChange,\n wsStatus,\n version,\n activeProject,\n projects,\n onProjectChange,\n onProjectsRefresh,\n onOpenSearch,\n settings,\n rightSlot,\n notificationsSlot,\n showTabs = true,\n extraTabs,\n}: TopbarProps) {\n return (\n <header className=\"topbar\">\n <div className=\"topbar-row\">\n <div className=\"brand\">\n <span className=\"brand-logo\" aria-hidden=\"true\">ᛒ</span>\n <span className=\"brand-title\">Bizar</span>\n <span className=\"brand-version\">{version}</span>\n </div>\n <ProjectSelector\n activeProject={activeProject}\n projects={projects}\n onChange={onProjectChange}\n onRefresh={onProjectsRefresh}\n settings={settings ?? null}\n />\n <button\n type=\"button\"\n className=\"topbar-search\"\n onClick={onOpenSearch}\n title=\"Search (Ctrl/Cmd+K)\"\n aria-label=\"Open search\"\n >\n <SearchIcon size={14} />\n <span className=\"muted\">Search…</span>\n <kbd>⌘K</kbd>\n </button>\n <div className=\"topbar-spacer\" />\n <div className=\"topbar-right\">\n {notificationsSlot}\n {rightSlot}\n <div className={cn('ws-status', `ws-${wsStatus}`)} title={`WebSocket: ${wsStatus}`}>\n <span className=\"ws-dot\" />\n <span className=\"ws-label\">{wsStatus}</span>\n </div>\n </div>\n </div>\n {showTabs && (\n <nav className=\"tabs-row\" role=\"tablist\" aria-label=\"Primary tabs\">\n {TABS.map((tab) => {\n const Icon = tab.icon;\n const active = tab.id === activeTab;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n className={cn('tab', active && 'tab-active')}\n onClick={() => onTabChange(tab.id)}\n title={tab.label}\n >\n <Icon size={14} className=\"tab-icon\" />\n <span className=\"tab-label\">{tab.label}</span>\n {tab.id === 'settings' && active && (\n <span className=\"settings-mode-indicator\" title=\"Settings mode active\">\n <Settings2 size={12} />\n </span>\n )}\n </button>\n );\n })}\n {extraTabs && extraTabs.length > 0 && (\n <>\n <span className=\"tab-separator\" aria-hidden=\"true\" />\n {extraTabs.map((tab) => {\n const Icon = tab.icon;\n const active = tab.id === activeTab;\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n className={cn('tab', 'tab-mod', active && 'tab-active')}\n onClick={() => onTabChange(tab.id)}\n title={`${tab.label} (mod)`}\n >\n <Icon size={14} className=\"tab-icon\" />\n <span className=\"tab-label\">{tab.label}</span>\n <span className=\"tab-badge\">mod</span>\n </button>\n );\n })}\n </>\n )}\n </nav>\n )}\n </header>\n );\n}\n\nfunction ProjectSelector({\n activeProject,\n projects,\n onChange,\n onRefresh,\n settings,\n}: {\n activeProject: ProjectRecord | null;\n projects: ProjectRecord[];\n onChange: (id: string) => void;\n onRefresh: () => void;\n settings: Settings | null;\n}) {\n const [open, setOpen] = useState(false);\n const modal = useModal();\n\n useEffect(() => {\n if (!open) return;\n const onClick = () => setOpen(false);\n document.addEventListener('click', onClick);\n return () => document.removeEventListener('click', onClick);\n }, [open]);\n\n const onAdd = () => {\n modal.open({\n title: 'Add project',\n children: (\n <TopbarAddProjectDialog\n settings={settings}\n onAdd={async (path: string, name: string | null) => {\n try {\n await api.post('/projects', { path, name });\n onRefresh();\n setOpen(false);\n modal.close();\n } catch (err) {\n alert(`Add failed: ${(err as Error).message}`);\n }\n }}\n />\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n </div>\n ),\n });\n };\n\n return (\n <div className=\"project-selector\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"project-selector-btn\"\n onClick={() => setOpen((v) => !v)}\n title=\"Switch active project\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n <Folder size={14} />\n <span className=\"project-selector-name\">\n {activeProject?.name || '(no project)'}\n </span>\n <ChevronDown size={12} />\n </button>\n {open && (\n <div className=\"project-selector-menu\">\n <div className=\"project-selector-menu-head\">\n <span className=\"muted\">{projects.length} project{projects.length === 1 ? '' : 's'}</span>\n <div className=\"project-selector-menu-actions\">\n <button type=\"button\" className=\"icon-btn\" onClick={onRefresh} title=\"Refresh\" aria-label=\"Refresh projects\">\n <RefreshCw size={12} />\n </button>\n <button type=\"button\" className=\"icon-btn\" onClick={onAdd} title=\"Add project\" aria-label=\"Add project\">\n <Plus size={12} />\n </button>\n </div>\n </div>\n <ul className=\"project-selector-list\">\n {projects.length === 0 && (\n <li className=\"muted project-selector-empty\">No projects. Add one to start.</li>\n )}\n {projects.map((p) => (\n <li key={p.id}>\n <button\n type=\"button\"\n className={cn('project-selector-item', activeProject?.id === p.id && 'active')}\n onClick={() => {\n onChange(p.id);\n setOpen(false);\n }}\n >\n <span className=\"project-selector-item-name\">{p.name}</span>\n <span className=\"project-selector-item-status\">{p.status}</span>\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n\n// ─── TopbarAddProjectDialog ───────────────────────────────────────────────────\n\nfunction TopbarAddProjectDialog({\n settings,\n onAdd,\n}: {\n settings: Settings | null;\n onAdd: (path: string, name: string | null) => void;\n}) {\n const [path, setPath] = useState(settings?.dashboard?.projectsDirectory ?? '');\n const [name, setName] = useState('');\n const [preflighting, setPreflighting] = useState(false);\n const [preflightError, setPreflightError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n if (!path) return;\n setPreflighting(true);\n setPreflightError(null);\n try {\n // Pre-flight: verify the path still exists\n await api.get<DirectoryListing>('/fs?path=' + encodeURIComponent(path));\n onAdd(path, name || null);\n } catch (err) {\n const apiErr = err as { status?: number; data?: { message?: string } };\n if (apiErr.status === 404) {\n setPreflightError('That folder no longer exists. Pick another.');\n } else {\n setPreflightError(\n apiErr.data?.message ?? (err as Error).message ?? 'Validation failed.',\n );\n }\n } finally {\n setPreflighting(false);\n }\n };\n\n return (\n <div>\n <label className=\"field-label\">Folder</label>\n <FileBrowser\n value={path}\n onChange={(p) => {\n setPath(p);\n setPreflightError(null);\n }}\n projectsDirectory={settings?.dashboard?.projectsDirectory}\n height={320}\n />\n {preflightError && (\n <p className=\"field-help\" style={{ color: 'var(--error)', marginTop: 4 }}>\n {preflightError}\n </p>\n )}\n <div style={{ marginTop: 'var(--space-3)' }}>\n <label className=\"field-label\" htmlFor=\"topbar-add-project-name\">Name (optional)</label>\n <input\n id=\"topbar-add-project-name\"\n className=\"input\"\n type=\"text\"\n placeholder=\"My App\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </div>\n <div style={{ marginTop: 'var(--space-3)', display: 'flex', justifyContent: 'flex-end' }}>\n <Button\n variant=\"primary\"\n onClick={handleAdd}\n disabled={!path || preflighting}\n >\n {preflighting ? <span className=\"btn-spinner\" /> : null}\n {preflighting ? 'Checking…' : 'Add'}\n </Button>\n </div>\n </div>\n );\n}\n","// src/components/SettingsNav.tsx — v4.9.0 full-sidebar settings navigation.\n// Shown in the sidebar rail when settingsMode is active. All sections are\n// visible at once; clicking one scrolls the Settings view to that section.\nimport {\n ChevronRight, Palette, Terminal, Cpu, RefreshCw, Gauge, ArrowLeft,\n LayoutGrid, Wifi, Bell, Shield, Users, Activity, FolderGit2,\n type LucideIcon,\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\n\nexport type SettingsSection = {\n id: string;\n label: string;\n icon?: LucideIcon;\n};\n\nexport type SettingsSectionGroup = {\n label: string;\n sections: SettingsSection[];\n};\n\nconst SECTION_GROUPS: SettingsSectionGroup[] = [\n {\n label: 'General',\n sections: [\n { id: 'theme', label: 'Theme', icon: Palette },\n // Layout & General are both rendered by GeneralSection; one nav item covers both\n { id: 'layout', label: 'Layout', icon: LayoutGrid },\n ],\n },\n {\n label: 'Core',\n sections: [\n { id: 'env-vars', label: 'Env Vars', icon: Terminal },\n { id: 'network', label: 'Network', icon: Wifi },\n { id: 'notifications', label: 'Notifications', icon: Bell },\n { id: 'auth', label: 'Auth', icon: Shield },\n { id: 'system-llm', label: 'System LLM', icon: Cpu },\n ],\n },\n {\n label: 'Agents',\n sections: [\n { id: 'agents', label: 'Agents', icon: Users },\n ],\n },\n {\n label: 'Experience',\n sections: [\n { id: 'updates', label: 'Updates', icon: RefreshCw },\n { id: 'headroom', label: 'Headroom', icon: Gauge },\n ],\n },\n {\n label: 'Data',\n sections: [\n { id: 'activity-log', label: 'Activity', icon: Activity },\n { id: 'workspaces', label: 'Workspaces', icon: FolderGit2 },\n ],\n },\n];\n\nexport type SettingsNavProps = {\n activeSection: string | null;\n onSectionChange: (id: string | null) => void;\n onExitSettings: () => void;\n};\n\nexport function SettingsNav({ activeSection, onSectionChange, onExitSettings }: SettingsNavProps) {\n return (\n <div className=\"settings-nav-root\" aria-label=\"Settings sections\">\n {/* Back button */}\n <button\n type=\"button\"\n className=\"sidebar-tab\"\n onClick={onExitSettings}\n aria-label=\"Exit settings\"\n >\n <ArrowLeft size={14} aria-hidden />\n <span className=\"sidebar-tab-label\">Back</span>\n </button>\n\n <div className=\"settings-nav-divider\" aria-hidden=\"true\" />\n\n {/* Section groups */}\n {SECTION_GROUPS.map((group) => (\n <div key={group.label} className=\"settings-nav-group\">\n <div className=\"settings-nav-group-label\">{group.label}</div>\n {group.sections.map((s) => {\n const Icon = s.icon;\n const active = activeSection === s.id;\n return (\n <button\n key={s.id}\n type=\"button\"\n className={cn('sidebar-tab', active && 'sidebar-tab-active')}\n onClick={() => onSectionChange(active ? null : s.id)}\n aria-current={active ? 'page' : undefined}\n >\n {Icon && <Icon size={14} aria-hidden />}\n <span className=\"sidebar-tab-label\">{s.label}</span>\n {active && (\n <ChevronRight size={12} aria-hidden />\n )}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n","// src/components/Sidebar.tsx — vertical navigation rail for sidebar/both layouts.\nimport type { TabDef } from './Topbar';\nimport { SettingsNav } from './SettingsNav';\nimport { cn } from '../lib/utils';\n\nexport type SidebarProps = {\n tabs: TabDef[];\n activeTab: string;\n onTabChange: (id: string) => void;\n /** v4.9.0 — When true, show the full settings sidebar nav instead of tabs. */\n settingsMode?: boolean;\n /** v4.9.0 — The currently highlighted settings section. */\n settingsActiveSection?: string | null;\n /** v4.9.0 — Called when user clicks a section in the settings sidebar. */\n onSettingsSectionChange?: (id: string | null) => void;\n /** v4.9.0 — Called when user clicks the back button in settings mode. */\n onExitSettings?: () => void;\n};\n\nexport function Sidebar({ tabs, activeTab, onTabChange, settingsMode, settingsActiveSection, onSettingsSectionChange, onExitSettings }: SidebarProps) {\n // v4.9.0 — When settingsMode is active, render the full settings nav instead\n // of the normal tab rail. This lets users see all sections at a glance.\n if (settingsMode) {\n return (\n <aside className=\"sidebar sidebar-settings-mode\" aria-label=\"Settings navigation\">\n <SettingsNav\n activeSection={settingsActiveSection ?? null}\n onSectionChange={onSettingsSectionChange ?? (() => {})}\n onExitSettings={onExitSettings ?? (() => {})}\n />\n </aside>\n );\n }\n\n // Split tabs into built-in (no `isMod` flag) and mod-added entries.\n // Render a separator + small \"Mods\" label between them so users can\n // tell what's part of Bizar vs what an installed mod contributed.\n const builtIn = tabs.filter((t) => !(t as TabDef & { isMod?: boolean }).isMod);\n const modTabs = tabs.filter((t) => (t as TabDef & { isMod?: boolean }).isMod);\n\n return (\n <aside className=\"sidebar\" aria-label=\"Primary navigation\">\n <nav className=\"sidebar-nav\" role=\"tablist\">\n {builtIn.map((t) => {\n const Icon = t.icon;\n const active = t.id === activeTab;\n return (\n <button\n key={t.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n className={cn('sidebar-tab', active && 'sidebar-tab-active')}\n onClick={() => onTabChange(t.id)}\n title={t.label}\n >\n <Icon size={18} aria-hidden />\n <span className=\"sidebar-tab-label\">{t.label}</span>\n </button>\n );\n })}\n {modTabs.length > 0 && (\n <>\n <div className=\"sidebar-section-divider\" aria-hidden=\"true\" />\n <div className=\"sidebar-section-label\">Mods</div>\n {modTabs.map((t) => {\n const Icon = t.icon;\n const active = t.id === activeTab;\n return (\n <button\n key={t.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n className={cn('sidebar-tab', 'sidebar-tab-mod', active && 'sidebar-tab-active')}\n onClick={() => onTabChange(t.id)}\n title={`${t.label} (mod)`}\n >\n <Icon size={18} aria-hidden />\n <span className=\"sidebar-tab-label\">{t.label}</span>\n </button>\n );\n })}\n </>\n )}\n </nav>\n </aside>\n );\n}\n","// src/components/SearchModal.tsx — fuzzy search modal opened by / or Cmd/Ctrl+K.\nimport { useEffect, useRef, useState } from 'react';\nimport { Search, X } from 'lucide-react';\nimport { useToast } from './Toast';\nimport { api } from '../lib/api';\nimport type { SearchResult } from '../lib/types';\nimport { cn } from '../lib/utils';\n\ntype Props = {\n open: boolean;\n onClose: () => void;\n onSelect: (r: SearchResult) => void;\n};\n\nconst SCOPES = [\n { id: 'all', label: 'All' },\n { id: 'projects', label: 'Projects' },\n { id: 'agents', label: 'Agents' },\n { id: 'tasks', label: 'Tasks' },\n { id: 'mods', label: 'Mods' },\n { id: 'schedules', label: 'Schedules' },\n { id: 'commands', label: 'Commands' },\n { id: 'settings', label: 'Settings' },\n] as const;\n\nconst RESULT_TYPE_BY_SCOPE: Record<(typeof SCOPES)[number]['id'], string | null> = {\n all: null,\n projects: 'project',\n agents: 'agent',\n tasks: 'task',\n mods: 'mod',\n schedules: 'schedule',\n commands: 'command',\n settings: 'setting',\n};\n\nexport function SearchModal({ open, onClose, onSelect }: Props) {\n const toast = useToast();\n const [q, setQ] = useState('');\n const [scope, setScope] = useState<typeof SCOPES[number]['id']>('all');\n const [results, setResults] = useState<SearchResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [activeIdx, setActiveIdx] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n let focusTimer: number | undefined;\n if (open) {\n previousFocusRef.current = document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n setQ('');\n setResults([]);\n setActiveIdx(0);\n focusTimer = window.setTimeout(() => inputRef.current?.focus(), 30);\n }\n return () => {\n if (focusTimer) window.clearTimeout(focusTimer);\n if (!open) return;\n const previous = previousFocusRef.current;\n if (previous && previous.isConnected) previous.focus();\n };\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n if (!q.trim()) {\n setResults([]);\n setActiveIdx(0);\n return;\n }\n let cancelled = false;\n setLoading(true);\n const t = setTimeout(() => {\n api\n .get<{ results: SearchResult[] }>(`/search?q=${encodeURIComponent(q)}&scope=${scope}`)\n .then((r) => {\n if (cancelled) return;\n setResults(r.results || []);\n setActiveIdx(0);\n })\n .catch((err) => {\n if (cancelled) return;\n toast.error(`Search failed: ${(err as Error).message}`);\n })\n .finally(() => !cancelled && setLoading(false));\n }, 150);\n return () => {\n cancelled = true;\n clearTimeout(t);\n };\n }, [q, scope, open, toast]);\n\n if (!open) return null;\n\n const grouped: Record<string, SearchResult[]> = {};\n for (const r of results) {\n const type = r.type.toLowerCase();\n grouped[type] = grouped[type] || [];\n grouped[type].push(r);\n }\n\n const flat: SearchResult[] = [];\n for (const scope of SCOPES.map((s) => s.id)) {\n const resultType = RESULT_TYPE_BY_SCOPE[scope];\n if (resultType && grouped[resultType]) flat.push(...grouped[resultType]);\n }\n\n const onKey = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (flat.length === 0) return;\n setActiveIdx((i) => Math.min(i + 1, flat.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n if (flat.length === 0) return;\n setActiveIdx((i) => Math.max(i - 1, 0));\n } else if (e.key === 'Enter' && flat[activeIdx]) {\n e.preventDefault();\n onSelect(flat[activeIdx]);\n onClose();\n }\n };\n\n return (\n <div className=\"search-modal-backdrop\" onClick={onClose}>\n <div className=\"search-modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"search-modal-title\" onClick={(e) => e.stopPropagation()}>\n <div className=\"search-modal-head\" role=\"search\">\n <Search size={14} aria-hidden />\n <span id=\"search-modal-title\" className=\"sr-only\">Search</span>\n <input\n ref={inputRef}\n className=\"search-modal-input\"\n placeholder=\"Search tasks, agents, settings, projects…\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={onKey}\n aria-label=\"Search\"\n />\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n <X size={14} />\n </button>\n </div>\n <div className=\"search-modal-scopes\" role=\"tablist\" aria-label=\"Search scope\">\n {SCOPES.map((s) => (\n <button\n key={s.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={scope === s.id}\n className={cn('search-scope', scope === s.id && 'search-scope-active')}\n onClick={() => setScope(s.id)}\n >\n {s.label}\n </button>\n ))}\n </div>\n <div className=\"search-modal-body\">\n {loading && <div className=\"muted\">Searching…</div>}\n {!loading && q && flat.length === 0 && <div className=\"muted\">No results.</div>}\n {!loading && !q && <div className=\"muted\">Type to search…</div>}\n {SCOPES.map((s) => {\n const resultType = RESULT_TYPE_BY_SCOPE[s.id];\n if (!resultType) return null;\n const list = grouped[resultType];\n if (!list || list.length === 0) return null;\n return (\n <div key={s.id} className=\"search-group\">\n <div className=\"search-group-head\">{s.label}</div>\n {list.map((r) => {\n const flatIdx = flat.indexOf(r);\n return (\n <button\n type=\"button\"\n key={`${r.type}-${flatIdx}`}\n className={cn('search-result', flatIdx === activeIdx && 'search-result-active')}\n onMouseEnter={() => setActiveIdx(flatIdx)}\n onClick={() => {\n onSelect(r);\n onClose();\n }}\n >\n <span className=\"search-result-type\">{r.type}</span>\n <span className=\"search-result-label\">\n {summarize(r)}\n </span>\n </button>\n );\n })}\n </div>\n );\n })}\n </div>\n <div className=\"search-modal-foot\">\n <span className=\"muted\">↑↓ navigate · ↵ open · esc close</span>\n </div>\n </div>\n </div>\n );\n}\n\nfunction summarize(r: SearchResult): string {\n const i = r.item || {};\n if (r.type === 'project') return `${i.name} — ${i.path}`;\n if (r.type === 'agent') return `${i.name} — ${i.description || i.model || ''}`;\n if (r.type === 'task') return `${i.title} — ${(i.status || '')}`;\n if (r.type === 'mod') return `${i.name} v${i.version} — ${i.description || ''}`;\n if (r.type === 'schedule') return `${i.name} (${i.type}: ${i.schedule})`;\n if (r.type === 'command') return `${i.name} — ${i.description || ''}`;\n if (r.type === 'setting') {\n const val = i.value === null || i.value === undefined\n ? ''\n : typeof i.value === 'string'\n ? ` = ${i.value}`\n : ` = ${JSON.stringify(i.value)}`;\n return `${i.label}${val} — ${i.desc || ''}`.trim();\n }\n return JSON.stringify(i).slice(0, 80);\n}\n","// src/components/Notifications.tsx — v3.3.0 bell icon + dropdown panel.\n\nimport { useEffect, useRef, useState } from 'react';\nimport { Bell, Check, X, Info, AlertTriangle, AlertCircle, CheckCircle2 } from 'lucide-react';\nimport { Button } from './Button';\nimport { useToast } from './Toast';\nimport { api } from '../lib/api';\nimport { cn, formatRelative } from '../lib/utils';\nimport type { Notification, NotificationStats, WsMessage } from '../lib/types';\n\nconst ICONS: Record<string, typeof Info> = {\n info: Info,\n success: CheckCircle2,\n warning: AlertTriangle,\n error: AlertCircle,\n};\n\ntype Props = {\n /** Setter for unread count so the rest of the app can react. */\n onCountChange?: (unread: number) => void;\n /** Optional hook to subscribe to incoming WS messages. */\n wsSubscribe?: (cb: (msg: WsMessage) => void) => () => void;\n};\n\nexport function Notifications({ onCountChange, wsSubscribe }: Props) {\n const toast = useToast();\n const [open, setOpen] = useState(false);\n const [items, setItems] = useState<Notification[]>([]);\n const [stats, setStats] = useState<NotificationStats | null>(null);\n const [loading, setLoading] = useState(false);\n const rootRef = useRef<HTMLDivElement | null>(null);\n const unreadRef = useRef(0);\n\n const reload = async () => {\n try {\n setLoading(true);\n const r = await api.get<{ notifications: Notification[]; stats: NotificationStats }>(\n '/notifications?limit=200',\n );\n setItems(r.notifications || []);\n setStats(r.stats || null);\n unreadRef.current = r.stats?.unread || 0;\n onCountChange?.(unreadRef.current);\n } catch (err) {\n // Soft-fail: the bell just shows no items.\n // eslint-disable-next-line no-console\n console.warn('[notifications] reload failed:', (err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Subscribe to incoming notification:new events.\n useEffect(() => {\n if (!wsSubscribe) return;\n const off = wsSubscribe((msg) => {\n if (msg.type === 'notification:new') {\n const incoming = msg.notification;\n setItems((cur) => [incoming, ...cur.filter((n) => n.id !== incoming.id)]);\n // Bump unread count.\n if (!incoming.read) {\n unreadRef.current += 1;\n setStats((cur) =>\n cur ? { ...cur, unread: (cur.unread || 0) + 1 } : { total: 1, unread: 1, lastTs: incoming.ts, counts: { [incoming.severity || 'info']: 1 } },\n );\n onCountChange?.(unreadRef.current);\n }\n } else if (msg.type === 'notifications:change') {\n // External change (mark-all-read, etc.) — refresh from server.\n reload();\n }\n });\n return off;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wsSubscribe]);\n\n // Close the panel on outside click.\n useEffect(() => {\n if (!open) return;\n const onDocClick = (e: MouseEvent) => {\n if (!rootRef.current) return;\n if (!rootRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false);\n };\n document.addEventListener('mousedown', onDocClick);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onDocClick);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n\n const onMarkAllRead = async () => {\n try {\n await api.post('/notifications/read-all', {});\n setItems((cur) => cur.map((n) => ({ ...n, read: true })));\n setStats((cur) => (cur ? { ...cur, unread: 0 } : cur));\n unreadRef.current = 0;\n onCountChange?.(0);\n toast.success('All notifications marked as read.', 1500);\n } catch (err) {\n toast.error(`Failed: ${(err as Error).message}`);\n }\n };\n\n const onMarkRead = async (id: string) => {\n try {\n await api.post(`/notifications/${encodeURIComponent(id)}/read`, {});\n setItems((cur) => cur.map((n) => (n.id === id ? { ...n, read: true } : n)));\n setStats((cur) => (cur ? { ...cur, unread: Math.max(0, (cur.unread || 1) - 1) } : cur));\n unreadRef.current = Math.max(0, unreadRef.current - 1);\n onCountChange?.(unreadRef.current);\n } catch (err) {\n toast.error(`Failed: ${(err as Error).message}`);\n }\n };\n\n const onRemove = async (id: string) => {\n try {\n await api.del(`/notifications/${encodeURIComponent(id)}`);\n setItems((cur) => {\n const removed = cur.find((n) => n.id === id);\n if (removed && !removed.read) {\n unreadRef.current = Math.max(0, unreadRef.current - 1);\n setStats((statsCur) => (statsCur ? { ...statsCur, unread: Math.max(0, statsCur.unread - 1) } : statsCur));\n onCountChange?.(unreadRef.current);\n }\n return cur.filter((n) => n.id !== id);\n });\n } catch (err) {\n toast.error(`Failed: ${(err as Error).message}`);\n }\n };\n\n const unread = stats?.unread || 0;\n\n return (\n <div className=\"notifications-root\" ref={rootRef}>\n <button\n type=\"button\"\n className={cn('topbar-icon-btn notifications-bell', open && 'is-open')}\n onClick={() => setOpen((v) => !v)}\n title=\"Notifications\"\n aria-label=\"Notifications\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n >\n <Bell size={16} />\n {unread > 0 && <span className=\"notifications-badge\">{unread > 99 ? '99+' : unread}</span>}\n </button>\n {open && (\n <div className=\"notifications-panel\" role=\"dialog\" aria-label=\"Notifications\">\n <header className=\"notifications-panel-head\">\n <div>\n <strong>Notifications</strong>\n {unread > 0 && <span className=\"muted text-sm\"> · {unread} unread</span>}\n </div>\n <div className=\"notifications-panel-head-actions\">\n <Button size=\"sm\" variant=\"ghost\" onClick={onMarkAllRead} disabled={unread === 0}>\n <Check size={12} /> Mark all read\n </Button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => setOpen(false)}\n aria-label=\"Close\"\n title=\"Close\"\n >\n <X size={14} />\n </button>\n </div>\n </header>\n <div className=\"notifications-list\">\n {loading && items.length === 0 ? (\n <div className=\"notifications-empty muted\">Loading…</div>\n ) : items.length === 0 ? (\n <div className=\"notifications-empty muted\">No notifications yet.</div>\n ) : (\n items.map((n) => {\n const Icon = ICONS[n.severity] || Info;\n return (\n <div\n key={n.id}\n className={cn('notification-item', !n.read && 'is-unread', `severity-${n.severity}`)}\n >\n <Icon size={14} className={`notification-icon severity-${n.severity}`} />\n <div className=\"notification-body\">\n {n.title && <div className=\"notification-title\">{n.title}</div>}\n <div className=\"notification-msg\">{n.message}</div>\n <div className=\"notification-meta muted\">\n <span className=\"mono\">{n.source}</span>\n <span>·</span>\n <span>{formatRelative(n.ts)}</span>\n </div>\n </div>\n <div className=\"notification-actions\">\n {!n.read && (\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => onMarkRead(n.id)}\n title=\"Mark as read\"\n aria-label=\"Mark as read\"\n >\n <Check size={12} />\n </button>\n )}\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n onClick={() => onRemove(n.id)}\n title=\"Remove\"\n aria-label=\"Remove\"\n >\n <X size={12} />\n </button>\n </div>\n </div>\n );\n })\n )}\n </div>\n <footer className=\"notifications-panel-foot\">\n <span className=\"muted text-sm\">\n {stats ? `${stats.total} total · last ${formatRelative(stats.lastTs || new Date().toISOString())}` : ''}\n </span>\n </footer>\n </div>\n )}\n </div>\n );\n}\n","// src/components/VisualPlanDialog.tsx — Dialog for /visual-plan command.\n\nimport { Button } from './Button';\n\ntype VisualPlanDialogProps = {\n data?: Record<string, unknown>;\n onClose: () => void;\n};\n\nexport function VisualPlanDialog({ data, onClose }: VisualPlanDialogProps) {\n const enabled = data?.enabled as boolean | undefined;\n const previousEnabled = data?.previousEnabled as boolean | undefined;\n const mode = data?.mode as string | undefined;\n const defaultTemplate = data?.defaultTemplate as string | undefined;\n const lastUsedSlug = data?.lastUsedSlug as string | null | undefined;\n\n const wasToggled = mode === 'toggle';\n\n return (\n <div>\n {wasToggled ? (\n <p style={{ marginBottom: 16, lineHeight: 1.6 }}>\n Visual plan mode has been <strong>{enabled ? 'enabled' : 'disabled'}</strong>.\n {enabled\n ? ' The agent will create a plan and wait for your feedback on complex tasks.'\n : ' The agent will work without a visual plan canvas.'}\n </p>\n ) : (\n <div style={{ marginBottom: 16 }}>\n <p style={{ marginBottom: 8, fontWeight: 600 }}>\n Visual Plan: <span style={{ color: enabled ? 'var(--color-success)' : 'var(--color-muted)' }}>\n {enabled ? 'ON' : 'OFF'}\n </span>\n </p>\n <p style={{ lineHeight: 1.6, color: 'var(--color-muted)', fontSize: 13 }}>\n When enabled, the agent creates a visual plan and waits for your feedback before proceeding with complex tasks.\n </p>\n {defaultTemplate && (\n <p style={{ marginTop: 8, fontSize: 13, color: 'var(--color-muted)' }}>\n Default template: <code>{defaultTemplate}</code>\n </p>\n )}\n {lastUsedSlug && (\n <p style={{ fontSize: 13, color: 'var(--color-muted)' }}>\n Last used plan: <code>{lastUsedSlug}</code>\n </p>\n )}\n <p style={{ marginTop: 12, fontSize: 13, color: 'var(--color-muted)' }}>\n Use <code>/visual-plan on</code> or <code>/visual-plan off</code> to toggle.\n </p>\n </div>\n )}\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Close</Button>\n </div>\n </div>\n );\n}\n","// src/components/ArtifactCreateDialog.tsx — Dialog for /artifact new command.\n\nimport { useState } from 'react';\nimport { Button } from './Button';\nimport { api } from '../lib/api';\n\ntype ArtifactCreateDialogProps = {\n data?: Record<string, unknown>;\n onClose: () => void;\n};\n\nconst KNOWN_TEMPLATES = [\n 'blank',\n 'feature-design',\n 'bug-investigation',\n 'decision-record',\n 'horizontal',\n 'vertical',\n];\n\nexport function ArtifactCreateDialog({ data, onClose }: ArtifactCreateDialogProps) {\n const templates = (data?.templates as string[]) ?? KNOWN_TEMPLATES;\n const defaultTemplate = (data?.defaultTemplate as string) ?? 'blank';\n\n const [slug, setSlug] = useState('');\n const [selectedTemplate, setSelectedTemplate] = useState(defaultTemplate);\n const [creating, setCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleCreate = async () => {\n if (!slug.trim()) {\n setError('Slug is required.');\n return;\n }\n if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(slug)) {\n setError('Invalid slug. Use lowercase letters, numbers, and hyphens. Must start with an alphanumeric character.');\n return;\n }\n setCreating(true);\n setError(null);\n try {\n await api.post('/artifacts', { slug, template: selectedTemplate });\n onClose();\n } catch (err) {\n setError((err as Error).message);\n setCreating(false);\n }\n };\n\n return (\n <div>\n <p style={{ marginBottom: 16, color: 'var(--color-muted)', fontSize: 13 }}>\n Create a new visual plan. Plans are stored in <code>artifacts/</code> in your worktree.\n </p>\n\n <div style={{ marginBottom: 12 }}>\n <label className=\"field-label\" htmlFor=\"plan-slug\">Plan slug</label>\n <input\n id=\"plan-slug\"\n className=\"input\"\n type=\"text\"\n placeholder=\"e.g. my-feature\"\n value={slug}\n onChange={(e) => { setSlug(e.target.value); setError(null); }}\n autoFocus\n />\n </div>\n\n <div style={{ marginBottom: 16 }}>\n <label className=\"field-label\" htmlFor=\"plan-template\">Template</label>\n <select\n id=\"plan-template\"\n className=\"select\"\n value={selectedTemplate}\n onChange={(e) => setSelectedTemplate(e.target.value)}\n >\n {templates.map((t) => (\n <option key={t} value={t}>{t}</option>\n ))}\n </select>\n </div>\n\n {error && (\n <p style={{ marginBottom: 12, color: 'var(--color-danger)', fontSize: 13 }}>{error}</p>\n )}\n\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose} disabled={creating}>Cancel</Button>\n <Button variant=\"primary\" onClick={handleCreate} disabled={creating || !slug.trim()}>\n {creating ? 'Creating…' : 'Create'}\n </Button>\n </div>\n </div>\n );\n}\n","// src/components/ArtifactListDialog.tsx — Dialog for /plan list command.\n\nimport { Button } from './Button';\n\ntype ArtifactListDialogProps = {\n data?: Record<string, unknown>;\n onClose: () => void;\n};\n\nexport function ArtifactListDialog({ data, onClose }: ArtifactListDialogProps) {\n const plans = (data?.plans as string[]) ?? [];\n const count = (data?.count as number) ?? plans.length;\n\n const handleOpen = (slug: string) => {\n window.open(`/artifacts/${slug}/`, '_blank');\n };\n\n return (\n <div>\n {plans.length === 0 ? (\n <p style={{ marginBottom: 16, color: 'var(--color-muted)' }}>\n No plans found in this worktree. Use <code>/artifact new <slug></code> to create one.\n </p>\n ) : (\n <div style={{ marginBottom: 16 }}>\n <p style={{ marginBottom: 12, fontSize: 13, color: 'var(--color-muted)' }}>\n {count} plan{count !== 1 ? 's' : ''} in this worktree:\n </p>\n <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>\n {plans.map((slug) => (\n <li\n key={slug}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '6px 0',\n borderBottom: '1px solid var(--color-border)',\n }}\n >\n <code style={{ fontSize: 13 }}>{slug}</code>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => handleOpen(slug)}>\n Open\n </Button>\n </li>\n ))}\n </ul>\n </div>\n )}\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Close</Button>\n </div>\n </div>\n );\n}\n","// src/components/HelpDialog.tsx — Dialog for /help and /bizar commands.\n\nimport { Button } from './Button';\n\ntype HelpDialogProps = {\n data?: Record<string, unknown>;\n onClose: () => void;\n};\n\ntype CmdEntry = { cmd: string; desc: string };\n\nexport function HelpDialog({ data, onClose }: HelpDialogProps) {\n const commands = (data?.commands as CmdEntry[]) ?? [];\n const templates = (data?.templates as string[]) ?? [];\n const statuses = (data?.statuses as string[]) ?? [];\n\n return (\n <div>\n {commands.length > 0 ? (\n <table style={{ width: '100%', borderCollapse: 'collapse', marginBottom: 16, fontSize: 13 }}>\n <tbody>\n {commands.map((entry) => (\n <tr key={entry.cmd} style={{ borderBottom: '1px solid var(--color-border)' }}>\n <td style={{ padding: '5px 8px 5px 0', whiteSpace: 'nowrap' }}>\n <code style={{ fontSize: 12 }}>{entry.cmd}</code>\n </td>\n <td style={{ padding: '5px 0', color: 'var(--color-muted)' }}>{entry.desc}</td>\n </tr>\n ))}\n </tbody>\n </table>\n ) : (\n <p style={{ marginBottom: 16, color: 'var(--color-muted)' }}>No commands available.</p>\n )}\n\n {templates.length > 0 && (\n <div style={{ marginBottom: 12 }}>\n <p style={{ fontSize: 12, color: 'var(--color-muted)', marginBottom: 4 }}>Available templates:</p>\n <p style={{ fontSize: 13 }}>{templates.join(', ')}</p>\n </div>\n )}\n\n {statuses.length > 0 && (\n <div style={{ marginBottom: 12 }}>\n <p style={{ fontSize: 12, color: 'var(--color-muted)', marginBottom: 4 }}>Available statuses:</p>\n <p style={{ fontSize: 13 }}>{statuses.join(', ')}</p>\n </div>\n )}\n\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Close</Button>\n </div>\n </div>\n );\n}\n","// src/components/AuditDialog.tsx — Dialog for /audit command.\n\nimport { useState } from 'react';\nimport { Button } from './Button';\nimport { api } from '../lib/api';\n\ntype AuditDialogProps = {\n data?: Record<string, unknown>;\n onClose: () => void;\n};\n\ntype AuditResult = {\n ok: boolean;\n findings: string[];\n error?: string;\n};\n\nexport function AuditDialog({ data, onClose }: AuditDialogProps) {\n const [running, setRunning] = useState(false);\n const [result, setResult] = useState<AuditResult | null>(null);\n\n const handleRunAudit = async () => {\n setRunning(true);\n setResult(null);\n try {\n // The audit is run by posting to /api/chat with an /audit message,\n // which forwards to the opencode serve child where the plugin handles it.\n // We poll for a response via the chat session.\n const res = await api.post<AuditResult>('/chat/audit', {});\n setResult(res);\n } catch (err) {\n setResult({ ok: false, findings: [], error: (err as Error).message });\n } finally {\n setRunning(false);\n }\n };\n\n return (\n <div>\n {result === null ? (\n <>\n <p style={{ marginBottom: 16, lineHeight: 1.6 }}>\n Run a security audit of your Bizar agent configuration. The audit checks for common misconfigurations, exposed secrets, and insecure defaults.\n </p>\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Cancel</Button>\n <Button variant=\"primary\" onClick={handleRunAudit} disabled={running}>\n {running ? 'Running…' : 'Run Audit'}\n </Button>\n </div>\n </>\n ) : (\n <>\n {result.ok ? (\n <div>\n <p style={{ marginBottom: 12, fontWeight: 600, color: 'var(--color-success)' }}>\n Audit passed — no issues found.\n </p>\n {result.findings.length > 0 && (\n <ul style={{ marginBottom: 16, paddingLeft: 20 }}>\n {result.findings.map((f, i) => (\n <li key={i} style={{ marginBottom: 4, fontSize: 13 }}>{f}</li>\n ))}\n </ul>\n )}\n </div>\n ) : (\n <p style={{ marginBottom: 16, color: 'var(--color-danger)' }}>\n Audit failed: {result.error ?? 'unknown error'}\n </p>\n )}\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Close</Button>\n </div>\n </>\n )}\n </div>\n );\n}\n","// src/components/CommandDialog.tsx — Generic dialog wrapper that routes to the\n// correct specific dialog component based on the DialogDescriptor's `component` field.\n\nimport { VisualPlanDialog } from './VisualPlanDialog';\nimport { ArtifactCreateDialog } from './ArtifactCreateDialog';\nimport { ArtifactListDialog } from './ArtifactListDialog';\nimport { HelpDialog } from './HelpDialog';\nimport { AuditDialog } from './AuditDialog';\nimport type { DialogDescriptor } from '../lib/types';\n\nexport type { DialogDescriptor };\n\nfunction GenericDialog({ dialog, onClose }: { dialog: DialogDescriptor; onClose: () => void }) {\n if (!dialog.data) {\n return (\n <div>\n <p style={{ marginBottom: 16, lineHeight: 1.6 }}>\n {`Command: ${dialog.command}`}\n </p>\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <button type=\"button\" className=\"btn\" onClick={onClose}>Close</button>\n </div>\n </div>\n );\n }\n\n const { message, detail, url } = dialog.data as { message?: string; detail?: string; url?: string };\n\n return (\n <div>\n <p style={{ marginBottom: 16, lineHeight: 1.6 }}>\n {message ?? `Command: ${dialog.command}`}\n </p>\n {detail && (\n <p style={{ marginBottom: 16, color: 'var(--color-muted)', fontSize: 13 }}>\n {detail}\n </p>\n )}\n {url && (\n <p style={{ marginBottom: 16 }}>\n <a href={url} target=\"_blank\" rel=\"noopener noreferrer\">{url}</a>\n </p>\n )}\n <div style={{ display: 'flex', justifyContent: 'flex-end' }}>\n <button type=\"button\" className=\"btn\" onClick={onClose}>Close</button>\n </div>\n </div>\n );\n}\n\nexport function CommandDialog({ dialog, onClose }: { dialog: DialogDescriptor; onClose: () => void }) {\n switch (dialog.component) {\n case 'visual-artifact':\n return <VisualPlanDialog data={dialog.data} onClose={onClose} />;\n case 'artifact-create':\n return <ArtifactCreateDialog data={dialog.data} onClose={onClose} />;\n case 'artifact-list':\n return <ArtifactListDialog data={dialog.data} onClose={onClose} />;\n case 'help':\n return <HelpDialog data={dialog.data} onClose={onClose} />;\n case 'audit':\n return <AuditDialog data={dialog.data} onClose={onClose} />;\n default:\n return <GenericDialog dialog={dialog} onClose={onClose} />;\n }\n}\n","// src/web/views/memory/MemoryStatusCard.tsx — overview status card for the Memory subsystem.\n//\n// Slimmed-down version of MemoryOverview: a single Card with lightrag status,\n// vault note count, git sync state, and a button to open the full Memory tab.\nimport { useEffect, useState } from 'react';\nimport {\n Activity,\n Brain,\n ExternalLink,\n FileText,\n GitBranch,\n RefreshCw,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { api } from '../../lib/api';\nimport { formatTime, cn } from '../../lib/utils';\n\ntype MemoryCardData = {\n initialized: boolean;\n mode?: string;\n projectId?: string;\n vaultRoot?: string;\n branch?: string;\n gitClean?: boolean | null;\n noteCount?: number;\n healthScore?: number;\n healthStatus?: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured';\n lightrag?: { running: boolean; indexedApprox: number };\n};\n\ntype Props = {\n setActiveTab: (id: string) => void;\n refreshKey?: number;\n};\n\nexport function MemoryStatusCard({ setActiveTab, refreshKey = 0 }: Props) {\n const [data, setData] = useState<MemoryCardData | null>(null);\n const [loading, setLoading] = useState(true);\n\n const reload = async () => {\n setLoading(true);\n try {\n const [status, health, lightrag] = await Promise.all([\n api.get<MemoryCardData>('/memory/status').catch(() => null),\n api.get<{ score: number; status: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured' }>(\n '/memory/health',\n ).catch(() => null),\n api.get<{ running: boolean; indexedApprox: number }>('/memory/lightrag/stats').catch(() => null),\n ]);\n setData({\n initialized: !!status?.initialized,\n mode: status?.mode,\n projectId: status?.projectId,\n vaultRoot: status?.vaultRoot,\n branch: status?.branch,\n gitClean: status?.gitClean,\n noteCount: status?.noteCount || 0,\n healthScore: health?.score,\n healthStatus: health?.status,\n lightrag: lightrag ? { running: lightrag.running, indexedApprox: lightrag.indexedApprox } : undefined,\n });\n } catch {\n setData({ initialized: false });\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n const openMemory = () => setActiveTab('memory');\n\n const healthColor =\n data?.healthStatus === 'healthy' ? 'var(--success)' :\n data?.healthStatus === 'degraded' ? 'var(--warning)' :\n data?.healthStatus === 'unhealthy' ? 'var(--error)' :\n 'var(--text-dim)';\n\n return (\n <Card className=\"memory-overview-card\">\n <CardTitle>\n <Brain size={14} /> Memory\n <Button variant=\"ghost\" size=\"sm\" style={{ marginLeft: 'auto' }} onClick={openMemory}>\n Open Memory <ExternalLink size={12} />\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={reload} aria-label=\"Refresh\" title=\"Refresh\">\n <RefreshCw size={12} />\n </Button>\n </CardTitle>\n <CardMeta>\n LightRAG + Obsidian vault + git sync — opens the dedicated Memory tab.\n </CardMeta>\n\n {!data?.initialized ? (\n <div className=\"muted\">\n Memory not initialised. Click <strong>Open Memory</strong> to set it up.\n </div>\n ) : (\n <div className=\"memory-status-card-grid\">\n <div className=\"memory-status-card-cell\">\n <div className=\"memory-status-card-label\">\n <Activity size={11} /> Health\n </div>\n <div className=\"memory-status-card-value\" style={{ color: healthColor }}>\n {data.healthScore !== undefined ? `${data.healthScore}/100` : '—'}\n </div>\n <div className=\"memory-status-card-sub muted\">{data.healthStatus || '—'}</div>\n </div>\n\n <div className=\"memory-status-card-cell\">\n <div className=\"memory-status-card-label\">\n <Brain size={11} /> LightRAG\n </div>\n <div className=\"memory-status-card-value\">\n {data.lightrag?.running ? 'running' : 'stopped'}\n </div>\n <div className=\"memory-status-card-sub muted\">\n {data.lightrag ? `${data.lightrag.indexedApprox} chunks` : '—'}\n </div>\n </div>\n\n <div className=\"memory-status-card-cell\">\n <div className=\"memory-status-card-label\">\n <FileText size={11} /> Vault\n </div>\n <div className=\"memory-status-card-value\">{data.noteCount} notes</div>\n <div className=\"memory-status-card-sub muted ellipsis\" title={data.vaultRoot || ''}>\n {data.vaultRoot ? data.vaultRoot.split('/').slice(-2).join('/') : '—'}\n </div>\n </div>\n\n <div className=\"memory-status-card-cell\">\n <div className=\"memory-status-card-label\">\n <GitBranch size={11} /> Git\n </div>\n <div className=\"memory-status-card-value\">\n {data.gitClean === null\n ? data.mode === 'local-only' ? 'local-only' : '—'\n : data.gitClean ? 'clean' : 'dirty'}\n </div>\n <div className=\"memory-status-card-sub muted\">\n {data.branch ? `branch ${data.branch}` : formatTime(data.branch || '') || '—'}\n </div>\n </div>\n </div>\n )}\n\n {loading && !data && (\n <div className=\"muted text-sm\">Loading…</div>\n )}\n </Card>\n );\n}\n\n// Allow css class composition without TS complaining about missing module declarations.\nvoid cn;","// src/components/EmptyState.tsx — friendly empty / error placeholder.\n\nimport type { ReactNode } from 'react';\nimport { Inbox } from 'lucide-react';\nimport { cn } from '../lib/utils';\n\nexport type EmptyStateProps = {\n icon?: ReactNode;\n title: string;\n message?: ReactNode;\n action?: ReactNode;\n className?: string;\n};\n\nexport function EmptyState({\n icon,\n title,\n message,\n action,\n className,\n}: EmptyStateProps) {\n return (\n <div className={cn('empty-state', className)}>\n <div className=\"empty-icon\">{icon ?? <Inbox size={32} />}</div>\n <div className=\"empty-title\">{title}</div>\n {message && <div className=\"empty-message\">{message}</div>}\n {action && <div className=\"empty-action\">{action}</div>}\n </div>\n );\n}\n","// src/views/Overview.tsx — v3.7.0 activity cards + SSE stream.\nimport React, { useEffect, useRef, useState } from 'react';\nimport {\n Bot,\n CheckSquare,\n Folder,\n LayoutDashboard,\n Map,\n MessageSquare,\n RefreshCw,\n PlayCircle,\n ShieldCheck,\n FileText,\n Zap,\n Plus,\n Trash2,\n Power,\n Send,\n Sparkles,\n AlertOctagon,\n AlertTriangle,\n CheckCircle2,\n Activity,\n Puzzle,\n Clock,\n FolderSearch,\n EyeOff,\n Eye,\n X,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { MemoryStatusCard } from './memory/MemoryStatusCard';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { VirtualList } from '../components/VirtualList';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { FileBrowser } from '../components/FileBrowser';\nimport { api } from '../lib/api';\nimport { formatRelative, formatTime } from '../lib/utils';\nimport type { Overview, Settings, Snapshot, ActivityItem, ProjectRecord, Mod, ScanResult, DirectoryListing } from '../lib/types';\nimport { cn } from '../lib/utils';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nfunction OverviewInner({\n snapshot,\n settings,\n setActiveTab,\n refreshSnapshot,\n}: Props) {\n const toast = useToast();\n const modal = useModal();\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n const [overview, setOverview] = useState<Overview | null>(\n snapshot.overview ?? null,\n );\n const [loading, setLoading] = useState(!snapshot.overview);\n const [projects, setProjects] = useState<ProjectRecord[]>(snapshot.projects || []);\n const [activeId, setActiveId] = useState<string | null>(\n snapshot.activeProject?.id || null,\n );\n const [mods, setMods] = useState<Mod[]>(snapshot.mods || []);\n const [submitting, setSubmitting] = useState(false);\n // v3.7.0 — Live activity feed via SSE\n const [activityItems, setActivityItems] = useState<ActivityItem[]>(\n snapshot.overview?.recentActivity ?? [],\n );\n const [activityExpanded, setActivityExpanded] = useState(false);\n // v3.15.0 — Hidden event keys are stored server-side; we just track\n // the set in client state. Hiding does NOT delete — see Settings →\n // Activity Log for the full feed.\n const [hiddenKeys, setHiddenKeys] = useState<Set<string>>(new Set());\n\n // v3.15.0 — Load hidden set once on mount\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const r = await api.get<{ hidden: string[] }>('/activity/hidden');\n if (!cancelled) setHiddenKeys(new Set(r.hidden || []));\n } catch { /* non-fatal */ }\n })();\n return () => { cancelled = true; };\n }, []);\n\n // v3.15.0 — Helper: stable key per activity item\n const itemKey = (it: ActivityItem, idx: number): string => {\n const k = `${it.kind || ''}|${it.ts || ''}|${(it.slug as string) || (it.title as string) || ''}|${idx}`;\n // hash to a short key (matches server-side activityKey derivation)\n let h = 0;\n for (let i = 0; i < k.length; i++) h = ((h << 5) - h + k.charCodeAt(i)) | 0;\n return Math.abs(h).toString(16).padStart(8, '0').slice(0, 16);\n };\n\n const onHide = async (key: string) => {\n const next = new Set(hiddenKeys);\n next.add(key);\n setHiddenKeys(next);\n try {\n await api.post('/activity/hide', { keys: [key] });\n } catch (err) {\n // rollback on failure\n const rollback = new Set(hiddenKeys);\n setHiddenKeys(rollback);\n toast.error(`Hide failed: ${(err as Error).message}`);\n }\n };\n\n const onClearAll = async () => {\n if (!confirm('Hide every recent activity item from the overview? The full log stays in Settings → Activity Log.')) return;\n const all = activityItems.map((it, idx) => itemKey(it, idx));\n const next = new Set(hiddenKeys);\n all.forEach((k) => next.add(k));\n setHiddenKeys(next);\n try {\n await api.post('/activity/hide', { keys: all });\n toast.success(`Hidden ${all.length} item(s). Restore them in Settings → Activity Log.`);\n } catch (err) {\n toast.error(`Clear failed: ${(err as Error).message}`);\n }\n };\n\n const onRestoreAll = async () => {\n setHiddenKeys(new Set());\n try {\n await api.del('/activity/hide');\n toast.success('All hidden activity restored to the overview.');\n } catch (err) {\n toast.error(`Restore failed: ${(err as Error).message}`);\n }\n };\n\n // v3.7.0 — Sync initial snapshot data\n useEffect(() => {\n if (snapshot.overview) {\n setOverview(snapshot.overview);\n setActivityItems(snapshot.overview.recentActivity ?? []);\n setLoading(false);\n }\n setProjects(snapshot.projects || []);\n setActiveId(snapshot.activeProject?.id || null);\n setMods(snapshot.mods || []);\n }, [snapshot.overview, snapshot.projects, snapshot.activeProject, snapshot.mods]);\n\n // v3.7.0 — Subscribe to SSE activity stream\n // v3.6.0 — Append ?token=… for auth. EventSource can't set custom\n // headers, so the server accepts the token via query string too.\n useEffect(() => {\n let es: EventSource;\n try {\n const tok = api.getToken();\n const url = tok\n ? `/api/activity/stream?token=${encodeURIComponent(tok)}`\n : '/api/activity/stream';\n es = new EventSource(url);\n es.addEventListener('snapshot', (e) => {\n try {\n const parsed = JSON.parse((e as MessageEvent).data) as { events: ActivityItem[]; generatedAt?: string };\n setActivityItems(Array.isArray(parsed.events) ? parsed.events.slice(0, 50) : []);\n } catch { /* ignore parse errors */ }\n });\n es.addEventListener('activity', (e) => {\n try {\n const entry = JSON.parse((e as MessageEvent).data) as ActivityItem;\n setActivityItems((cur) => [entry, ...cur].slice(0, 50));\n } catch { /* ignore parse errors */ }\n });\n } catch { /* SSE not available — fallback to snapshot data */ }\n return () => { try { es?.close(); } catch { /* ignore */ } };\n }, []);\n\n const onRefresh = async () => {\n toast.info('Refreshing…', 1500);\n await refreshSnapshot();\n try {\n const data = await api.get<{ projects: ProjectRecord[]; active: string | null }>('/projects');\n setProjects(data.projects || []);\n setActiveId(data.active || null);\n } catch { /* ignore */ }\n };\n\n const onAddProject = () => {\n modal.open({\n title: 'Add project',\n children: (\n <AddProjectDialog\n settings={settings}\n onAdd={async (path: string, name: string | null) => {\n try {\n const r = await api.post<ProjectRecord>('/projects', { path, name });\n setProjects((cur) => [...cur.filter((p) => p.id !== r.id), r]);\n toast.success('Project added.');\n modal.close();\n } catch (err) {\n toast.error(`Add failed: ${(err as Error).message}`);\n }\n }}\n />\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n </div>\n ),\n });\n };\n\n const onUseCurrentDir = async () => {\n try {\n const data = await api.post<{ projects: ProjectRecord[]; active: string | null }>(\n '/projects/auto-detect',\n );\n setProjects(data.projects || []);\n setActiveId(data.active || null);\n const newActive = data.projects?.find((p) => p.id === data.active);\n toast.success(newActive ? `Active: ${newActive.name}` : 'Projects refreshed.');\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Auto-detect failed: ${(err as Error).message}`);\n }\n };\n\n const onActivate = async (id: string) => {\n try {\n await api.post(`/projects/${encodeURIComponent(id)}/activate`);\n setActiveId(id);\n toast.success('Project activated.');\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Activate failed: ${(err as Error).message}`);\n }\n };\n\n const onRemove = async (id: string) => {\n if (!confirm(`Remove project \"${id}\" from the registry?`)) return;\n try {\n await api.del(`/projects/${encodeURIComponent(id)}`);\n setProjects((cur) => cur.filter((p) => p.id !== id));\n if (activeId === id) setActiveId(null);\n toast.success('Project removed.');\n } catch (err) {\n toast.error(`Remove failed: ${(err as Error).message}`);\n }\n };\n\n if (loading || !overview) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading overview…</p>\n </div>\n );\n }\n\n return (\n <div className=\"view view-overview\">\n {/* v3.4.0 — Hero takes the spotlight. No card wrapper. */}\n <div className=\"overview-hero-noframe\">\n <h1>What do you want to do?</h1>\n <p className=\"overview-hero-subtitle\">\n Describe what you want — Odin will split it into tasks, create a plan,\n delegate to background agents, and track progress in real time.\n </p>\n <form\n className=\"overview-hero-form-noframe\"\n onSubmit={async (e) => {\n e.preventDefault();\n const text = (inputRef.current?.value || '').trim();\n if (!text) return;\n setSubmitting(true);\n try {\n const r = await api.post<{ subtasks?: unknown[] }>('/tasks/submit', { title: text });\n toast.success(`Odin split it into ${(r.subtasks?.length || 1)} task(s)`);\n if (inputRef.current) inputRef.current.value = '';\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Failed: ${(err as Error).message}`);\n } finally {\n setSubmitting(false);\n }\n }}\n >\n <label htmlFor=\"overview-hero-input\" className=\"sr-only\">Describe what you want Odin to do</label>\n <textarea\n id=\"overview-hero-input\"\n ref={inputRef}\n className=\"overview-input-hero\"\n placeholder=\"e.g. Implement user authentication with email + password, including registration, login, password reset, and integration tests. Use Bcrypt, JWT tokens, and the existing API style.\"\n disabled={submitting}\n aria-label=\"Describe what you want Odin to do\"\n />\n <div style={{ display: 'flex', gap: 'var(--space-2)', alignItems: 'center', flexWrap: 'wrap' }}>\n <Button\n type=\"submit\"\n variant=\"primary\"\n size=\"lg\"\n disabled={submitting}\n >\n {submitting ? <Spinner size=\"sm\" /> : <Send size={16} />}\n Submit to Odin\n </Button>\n <span className=\"muted\" style={{ fontSize: 12 }}>\n <Sparkles size={12} style={{ display: 'inline', verticalAlign: -2, color: 'var(--accent)' }} />\n {' '}Odin + 12 specialist agents available\n </span>\n </div>\n </form>\n\n <div className=\"overview-quick-actions-row\">\n {['Implement feature', 'Fix bug', 'Refactor', 'Investigate', 'Add tests', 'Document', 'Optimize', 'Deploy'].map((action) => (\n <button\n key={action}\n type=\"button\"\n className=\"overview-quick-chip\"\n onClick={() => {\n if (inputRef.current) {\n inputRef.current.value = action;\n inputRef.current.focus();\n }\n }}\n >\n {action}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"overview-feed\">\n <div className=\"overview-feed-head\">\n <h2>Recent activity</h2>\n <div className=\"overview-feed-head-actions\">\n {hiddenKeys.size > 0 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onRestoreAll} title=\"Restore hidden items to this overview\">\n <Eye size={12} /> Show {hiddenKeys.size} hidden\n </Button>\n )}\n {activityItems.length > 8 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setActivityExpanded((v) => !v)}>\n {activityExpanded ? 'Show less' : 'Show all'}\n </Button>\n )}\n {activityItems.length > 0 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearAll} title=\"Hide every item from the overview (full log kept)\">\n <EyeOff size={12} /> Hide all\n </Button>\n )}\n </div>\n </div>\n {hiddenKeys.size > 0 && (\n <div className=\"activity-hidden-banner\" role=\"status\">\n <span>\n <EyeOff size={12} style={{ verticalAlign: -2, marginRight: 6 }} />\n {hiddenKeys.size} item{hiddenKeys.size === 1 ? '' : 's'} hidden from the overview.\n </span>\n <Button variant=\"ghost\" size=\"sm\" onClick={onRestoreAll}>\n <Eye size={12} /> Show them again\n </Button>\n </div>\n )}\n {activityItems.length === 0 ? (\n <div className=\"muted\" style={{ padding: '24px 0', fontSize: 13 }}>\n No activity yet. Use the chat above or invoke a Bizar command to start a feed.\n </div>\n ) : (\n <div\n className={cn('activity-feed-list-wrap', !activityExpanded && 'activity-feed-list-wrap-collapsed')}\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n >\n <VirtualList\n items={activityItems.slice(0, 30).filter((it, idx) => !hiddenKeys.has(itemKey(it, idx)))}\n itemHeight={60}\n height={Math.min(activityItems.filter((it, idx) => !hiddenKeys.has(itemKey(it, idx))).length * 60, 480)}\n className=\"activity-feed-list\"\n renderItem={(it, vlIdx) => {\n const originalIdx = activityItems.slice(0, 30).findIndex((a) => a === it);\n return (\n <ActivityFeedItem\n item={it}\n activityKey={itemKey(it, originalIdx)}\n onNavigate={setActiveTab}\n onHide={onHide}\n />\n );\n }}\n />\n {!activityExpanded && activityItems.length > 8 && <div className=\"activity-feed-fade\" aria-hidden=\"true\" />}\n </div>\n )}\n </div>\n\n {/* v3.4.0 — Below-the-fold: projects + meta (compact) */}\n <Card className=\"project-picker\">\n <CardTitle>\n <Folder size={14} /> Projects\n <Button variant=\"ghost\" size=\"sm\" style={{ marginLeft: 'auto' }} onClick={onAddProject}>\n <Plus size={12} /> Add\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onUseCurrentDir} title=\"Use the server's working directory\">\n <Plus size={12} /> Auto-detect\n </Button>\n {settings?.dashboard?.projectsDirectory && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n title={`Scan ${settings.dashboard.projectsDirectory} for projects`}\n onClick={async () => {\n try {\n const r = await api.post<ScanResult>('/projects/scan');\n if (r.error) {\n toast.error(r.error);\n } else {\n toast.success(`Added ${r.added.length}, skipped ${r.skipped}.`);\n }\n await refreshSnapshot();\n const data = await api.get<{ projects: ProjectRecord[]; active: string | null }>('/projects');\n setProjects(data.projects || []);\n setActiveId(data.active || null);\n } catch (err) {\n toast.error(`Scan failed: ${(err as Error).message}`);\n }\n }}\n >\n <FolderSearch size={12} /> Scan\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" onClick={onRefresh} title=\"Refresh\">\n <RefreshCw size={12} />\n </Button>\n </CardTitle>\n <CardMeta>\n {projects.length} project{projects.length === 1 ? '' : 's'} ·\n {' '}{overview.counts.agents} agents ·\n {' '}{overview.counts.sessions} session{overview.counts.sessions === 1 ? '' : 's'}\n </CardMeta>\n {projects.length === 0 ? (\n <EmptyState\n icon={<Folder size={32} />}\n title=\"No projects yet\"\n message=\"Add a project to start tracking its tasks, plans, and schedules.\"\n action={\n <div className=\"empty-state-actions\">\n <Button variant=\"primary\" onClick={onUseCurrentDir}>\n <Plus size={14} /> Use current directory\n </Button>\n <Button variant=\"secondary\" onClick={onAddProject}>\n Add by path…\n </Button>\n </div>\n }\n />\n ) : (\n <div className=\"project-grid\">\n {projects.map((p) => (\n <ProjectCard\n key={p.id}\n project={p}\n active={activeId === p.id}\n onOpen={() => onActivate(p.id)}\n onRemove={() => onRemove(p.id)}\n />\n ))}\n </div>\n )}\n </Card>\n\n <MemoryStatusCard setActiveTab={setActiveTab} />\n\n <div className=\"overview-cols\">\n <Card>\n <CardTitle>Mods</CardTitle>\n <CardMeta>Extensions installed under <code>~/.config/bizar/mods/</code></CardMeta>\n {mods.length === 0 ? (\n <div className=\"muted\">No mods installed.</div>\n ) : (\n <ul className=\"mod-mini-list\">\n {mods.map((m) => (\n <li key={m.id} className=\"mod-mini\">\n <span className=\"mod-mini-name\">{m.name}</span>\n <span className=\"mod-mini-meta\">v{m.version} · {m.type}</span>\n <span className={`mod-mini-pill ${m.enabled ? 'mod-mini-pill-on' : 'mod-mini-pill-off'}`}>\n {m.enabled ? 'on' : 'off'}\n </span>\n </li>\n ))}\n </ul>\n )}\n </Card>\n\n <Card>\n <CardTitle>Environment</CardTitle>\n <CardMeta>Runtime + paths</CardMeta>\n <dl className=\"env-table\">\n <dt>Node</dt>\n <dd className=\"mono\">{overview.versions.node}</dd>\n <dt>Platform</dt>\n <dd className=\"mono\">{overview.versions.platform}</dd>\n <dt>Project root</dt>\n <dd className=\"mono ellipsis\" title={overview.versions.projectRoot}>\n {overview.versions.projectRoot}\n </dd>\n <dt>Bizar root</dt>\n <dd className=\"mono ellipsis\" title={overview.versions.bizarRoot}>\n {overview.versions.bizarRoot}\n </dd>\n <dt>Generated</dt>\n <dd className=\"mono tabular-nums\">\n {formatTime(overview.generatedAt)}\n </dd>\n </dl>\n </Card>\n </div>\n </div>\n );\n}\n\n// ─── AddProjectDialog ─────────────────────────────────────────────────────────\n\n/**\n * Pre-flight approach: before POST /projects we verify the selected path\n * still exists (GET /fs?path=...). This avoids the ugly 404 toast when a\n * directory is deleted between selection and submit.\n */\nfunction AddProjectDialog({\n settings,\n onAdd,\n}: {\n settings: Settings;\n onAdd: (path: string, name: string | null) => void;\n}) {\n const [path, setPath] = useState(settings?.dashboard?.projectsDirectory ?? '');\n const [name, setName] = useState('');\n const [preflighting, setPreflighting] = useState(false);\n const [preflightError, setPreflightError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n if (!path) return;\n setPreflighting(true);\n setPreflightError(null);\n try {\n // Pre-flight: verify the path still exists\n await api.get<DirectoryListing>('/fs?path=' + encodeURIComponent(path));\n // Path is valid — proceed with the POST\n onAdd(path, name || null);\n } catch (err) {\n const apiErr = err as { status?: number; data?: { message?: string } };\n if (apiErr.status === 404) {\n setPreflightError('That folder no longer exists. Pick another.');\n } else {\n setPreflightError(\n apiErr.data?.message ?? (err as Error).message ?? 'Validation failed.',\n );\n }\n } finally {\n setPreflighting(false);\n }\n };\n\n return (\n <div>\n <label className=\"field-label\">Folder</label>\n <FileBrowser\n value={path}\n onChange={(p) => {\n setPath(p);\n setPreflightError(null);\n }}\n projectsDirectory={settings?.dashboard?.projectsDirectory}\n height={320}\n />\n {preflightError && (\n <p className=\"field-help\" style={{ color: 'var(--error)', marginTop: 4 }}>\n {preflightError}\n </p>\n )}\n <div style={{ marginTop: 'var(--space-3)' }}>\n <label className=\"field-label\" htmlFor=\"add-project-name\">Name (optional)</label>\n <input\n id=\"add-project-name\"\n className=\"input\"\n type=\"text\"\n placeholder=\"My App\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n <p className=\"field-help\" style={{ marginTop: 4 }}>\n Display name for this project. Defaults to the folder name.\n </p>\n </div>\n <div style={{ marginTop: 'var(--space-3)', display: 'flex', justifyContent: 'flex-end' }}>\n <Button\n variant=\"primary\"\n onClick={handleAdd}\n disabled={!path || preflighting}\n >\n {preflighting ? <span className=\"btn-spinner\" /> : null}\n {preflighting ? 'Checking…' : 'Add'}\n </Button>\n </div>\n </div>\n );\n}\n\nfunction ProjectCard({\n project,\n active,\n onOpen,\n onRemove,\n}: {\n project: ProjectRecord;\n active: boolean;\n onOpen: () => void;\n onRemove: () => void;\n}) {\n const statusColor = {\n active: 'status-on',\n inactive: 'status-neutral',\n error: 'status-error',\n }[project.status] || 'status-neutral';\n return (\n <div className={`project-card ${active ? 'project-card-active' : ''}`}>\n <div className=\"project-card-head\">\n <span className={`project-card-status ${statusColor}`}>\n {project.status}\n </span>\n <div className=\"project-card-name\">{project.name}</div>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Remove project\"\n title=\"Remove\"\n onClick={(e) => {\n e.stopPropagation();\n onRemove();\n }}\n >\n <Trash2 size={12} />\n </button>\n </div>\n <div className=\"project-card-path mono ellipsis\" title={project.path}>\n {project.path}\n </div>\n <div className=\"project-card-meta\">\n {project.lastAccessed && (\n <span className=\"muted\">Last opened {formatRelative(project.lastAccessed)}</span>\n )}\n </div>\n <div className=\"project-card-actions\">\n <Button variant={active ? 'ghost' : 'primary'} size=\"sm\" onClick={onOpen}>\n {active ? <><Power size={12} /> Active</> : <>Open</>}\n </Button>\n </div>\n </div>\n );\n}\n\nfunction sentenceCase(s: string): string {\n if (!s) return s;\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction humanizeKind(kind: string): string {\n const normalized = (kind || 'activity').trim().toLowerCase().replace(/[:_]/g, '.');\n const [scopeRaw, actionRaw = 'updated'] = normalized.split('.');\n const scopeMap: Record<string, string> = {\n settings: 'Settings',\n task: 'Task',\n tasks: 'Task',\n agent: 'Agent',\n agents: 'Agent',\n plan: 'Plan',\n plans: 'Plan',\n bg: 'Background job',\n background: 'Background job',\n session: 'Session',\n mod: 'Mod',\n mods: 'Mod',\n provider: 'Provider',\n providers: 'Provider',\n };\n const actionMap: Record<string, string> = {\n create: 'created', created: 'created',\n add: 'added', added: 'added',\n update: 'updated', updated: 'updated',\n delegate: 'delegated', delegated: 'delegated',\n invoke: 'invoked', invoked: 'invoked',\n restart: 'restarted', restarted: 'restarted',\n delete: 'deleted', deleted: 'deleted',\n remove: 'removed', removed: 'removed',\n archive: 'archived', archived: 'archived',\n restore: 'restored', restored: 'restored',\n complete: 'completed', completed: 'completed',\n fail: 'failed', failed: 'failed',\n error: 'errored', stuck: 'marked stuck',\n };\n const scope = scopeMap[scopeRaw] || sentenceCase(scopeRaw.replace(/-/g, ' '));\n const action = actionMap[actionRaw] || actionRaw.replace(/-/g, ' ');\n return `${scope} ${action}`.trim();\n}\n\nfunction firstString(it: ActivityItem, keys: string[]): string {\n for (const key of keys) {\n const value = it[key];\n if (typeof value === 'string' && value.trim()) return value.trim();\n }\n return '';\n}\n\nfunction formatActivitySummary(it: ActivityItem): string {\n const direct = firstString(it, ['message', 'text', 'prompt', 'title', 'name']);\n if (direct) return direct;\n const parts: string[] = [];\n const slug = firstString(it, ['slug']);\n const agent = firstString(it, ['agent', 'author']);\n const status = firstString(it, ['status']);\n if (slug) parts.push(`Plan ${slug}`);\n if (agent) parts.push(agent);\n if (status) parts.push(status);\n return parts.length ? parts.join(' · ') : 'No additional details.';\n}\n\n// v3.7.0 — Format a timestamp as a relative string (\"2m ago\", \"1h ago\")\nfunction formatRelativeTime(ts: string): string {\n return formatRelative(ts);\n}\n\n// v3.7.0 — Get severity color token from kind or status field\nfunction activitySeverity(it: ActivityItem): 'error' | 'warning' | 'success' | 'info' {\n const k = ((it.kind as string) || '').toLowerCase();\n const s = ((it.status as string) || '').toLowerCase();\n if (k.includes('error') || s === 'error' || s === 'failure') return 'error';\n if (k.includes('warn') || s === 'blocked') return 'warning';\n if (k.includes('done') || k.includes('success') || s === 'done') return 'success';\n return 'info';\n}\n\n// v3.7.0 — Map activity kind to icon\nfunction activityIcon(kind: string) {\n const k = kind.toLowerCase();\n if (k === 'task') return CheckSquare;\n if (k === 'agent') return Bot;\n if (k === 'plan') return Map;\n if (k.includes('bg') || k.includes('background') || k.includes('job')) return Zap;\n if (k === 'mod') return Puzzle;\n if (k === 'skill') return Sparkles;\n if (k.includes('error') || k.includes('failure')) return AlertOctagon;\n if (k.includes('warn')) return AlertTriangle;\n return Activity;\n}\n\n// v3.7.0 — Navigate to the relevant tab when a card is clicked\nfunction activityNavTarget(kind: string): string | null {\n const k = kind.toLowerCase();\n if (k === 'task') return 'tasks';\n if (k === 'agent') return 'agents';\n if (k === 'plan') return 'artifacts';\n if (k.includes('bg') || k.includes('background')) return 'activity';\n if (k === 'mod') return 'mods';\n if (k === 'skill') return 'skills';\n return null;\n}\n\n// v3.7.0 — Activity card component\nfunction ActivityFeedItem({\n item,\n activityKey,\n onNavigate,\n onHide,\n}: {\n item: ActivityItem;\n activityKey: string;\n onNavigate: (tab: string) => void;\n onHide: (key: string) => void;\n}) {\n const severity = activitySeverity(item);\n const Icon = activityIcon(item.kind || '');\n const title = humanizeKind(item.kind || 'activity');\n const msg = formatActivitySummary(item);\n const navTarget = activityNavTarget(item.kind || '');\n\n const accentColor =\n severity === 'error' ? 'var(--error)' :\n severity === 'warning' ? 'var(--warning)' :\n severity === 'success' ? 'var(--success)' :\n 'var(--accent)';\n\n return (\n <div className={cn('activity-feed-row', `activity-feed-row-${severity}`)}>\n <button\n type=\"button\"\n className=\"activity-feed-row-main\"\n onClick={() => { if (navTarget) onNavigate(navTarget); }}\n title={navTarget ? `Open ${navTarget}` : title}\n >\n <div className=\"activity-feed-icon\" style={{ color: accentColor }}>\n <Icon size={14} />\n </div>\n <div className=\"activity-feed-body\">\n <div className=\"activity-feed-title-row\">\n <div className=\"activity-feed-title\">{title}</div>\n <div className=\"activity-feed-time text-xs muted tabular-nums\">{formatRelativeTime(item.ts)}</div>\n </div>\n <div className=\"activity-feed-summary text-sm\">{msg}</div>\n </div>\n </button>\n <button\n type=\"button\"\n className=\"activity-feed-hide-btn\"\n onClick={() => onHide(activityKey)}\n title=\"Hide this from the overview (kept in Settings → Activity Log)\"\n aria-label=\"Hide from overview\"\n >\n <X size={12} />\n </button>\n </div>\n );\n}\nconst OverviewMemo = React.memo(OverviewInner);\nexport { OverviewMemo as Overview };\n","// src/components/chat/EmptyState.tsx — chat-local empty state (variant of shared EmptyState).\n\nimport type { ReactNode } from 'react';\n\ninterface Props {\n icon?: ReactNode;\n title: string;\n message: ReactNode;\n action?: ReactNode;\n}\n\nexport function EmptyState({ icon, title, message, action }: Props) {\n return (\n <div className=\"chat-empty-state\">\n {icon && <div className=\"chat-empty-state-icon\">{icon}</div>}\n <h2 className=\"chat-empty-state-title\">{title}</h2>\n <p className=\"chat-empty-state-message\">{message}</p>\n {action && <div className=\"chat-empty-state-action\">{action}</div>}\n </div>\n );\n}","// src/components/chat/SessionRowMenu.tsx — three-mode popover for a session rail row.\n//\n// Three modes:\n// 'main' — Rename + Delete buttons\n// 'rename' — Inline input with Cancel/Save\n// 'confirm-delete' — Inline confirmation with Cancel/Delete\n//\n// Rendered via createPortal on document.body so it isn't clipped by\n// the rail's overflow:auto scroll container. The parent row supplies\n// the anchor's bounding rect (or the menu uses an anchor prop).\n\nimport { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Edit, Trash2 } from 'lucide-react';\n\nexport type SessionMenuMode = 'main' | 'rename' | 'confirm-delete';\n\nexport interface SessionRowMenuAnchor {\n /** Bounding rect of the trigger / row used to position the popover. */\n rect: DOMRect;\n}\n\nexport interface SessionRowMenuProps {\n session: { id: string; title: string };\n mode: SessionMenuMode;\n anchor: SessionRowMenuAnchor;\n renameDraft: string;\n setRenameDraft: (s: string) => void;\n onEdit: () => void;\n onDeleteRequest: () => void;\n onConfirmDelete: () => void;\n onConfirmRename: () => void;\n onClose: () => void;\n}\n\nexport function SessionRowMenu({\n session,\n mode,\n anchor,\n renameDraft,\n setRenameDraft,\n onEdit,\n onDeleteRequest,\n onConfirmDelete,\n onConfirmRename,\n onClose,\n}: SessionRowMenuProps) {\n const ref = useRef<HTMLDivElement | null>(null);\n\n // Position the popover just below the row's right edge.\n const top = Math.round(anchor.rect.bottom + 2);\n const right = Math.max(8, Math.round(window.innerWidth - anchor.rect.right));\n\n // Close on outside click + Esc.\n useEffect(() => {\n const onDown = (e: MouseEvent) => {\n const t = e.target as Node | null;\n if (!ref.current || !t) return;\n if (ref.current.contains(t)) return;\n onClose();\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n // Defer attaching the outside-click handler so the click that opened\n // the menu doesn't immediately close it.\n const id = window.setTimeout(() => {\n document.addEventListener('mousedown', onDown);\n document.addEventListener('keydown', onKey);\n }, 0);\n return () => {\n window.clearTimeout(id);\n document.removeEventListener('mousedown', onDown);\n document.removeEventListener('keydown', onKey);\n };\n }, [onClose]);\n\n // Auto-focus the rename input when entering rename mode.\n useEffect(() => {\n if (mode !== 'rename') return;\n const id = window.setTimeout(() => {\n const input = ref.current?.querySelector<HTMLInputElement>('input.session-row-menu-input');\n input?.focus();\n input?.select();\n }, 0);\n return () => window.clearTimeout(id);\n }, [mode]);\n\n const body = (\n <div\n ref={ref}\n className=\"session-row-menu\"\n role=\"menu\"\n aria-label={`Options for ${session.title}`}\n style={{ position: 'fixed', top, right }}\n onClick={(e) => e.stopPropagation()}\n >\n {mode === 'main' && (\n <>\n <button\n type=\"button\"\n className=\"session-row-menu-item\"\n role=\"menuitem\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit();\n }}\n >\n <Edit size={13} aria-hidden />\n <span>Rename</span>\n <kbd>R</kbd>\n </button>\n <button\n type=\"button\"\n className=\"session-row-menu-item session-row-menu-item-danger\"\n role=\"menuitem\"\n onClick={(e) => {\n e.stopPropagation();\n onDeleteRequest();\n }}\n >\n <Trash2 size={13} aria-hidden />\n <span>Delete</span>\n <kbd>⌫</kbd>\n </button>\n </>\n )}\n {mode === 'rename' && (\n <div className=\"session-row-menu-inline\">\n <div className=\"session-row-menu-inline-label chat-mono\">Rename session</div>\n <input\n type=\"text\"\n className=\"session-row-menu-input\"\n value={renameDraft}\n onChange={(e) => setRenameDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n onConfirmRename();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n }}\n onClick={(e) => e.stopPropagation()}\n aria-label=\"New session name\"\n />\n <div className=\"session-row-menu-inline-actions\">\n <button\n type=\"button\"\n className=\"btn btn-ghost\"\n onClick={(e) => {\n e.stopPropagation();\n onClose();\n }}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn btn-primary\"\n onClick={(e) => {\n e.stopPropagation();\n onConfirmRename();\n }}\n >\n Save\n </button>\n </div>\n </div>\n )}\n {mode === 'confirm-delete' && (\n <div className=\"session-row-menu-inline\">\n <div className=\"session-row-menu-inline-label chat-mono\">Delete this session?</div>\n <div className=\"session-row-menu-inline-message\">\n \"{session.title}\" and its sub-agents will be removed.\n </div>\n <div className=\"session-row-menu-inline-actions\">\n <button\n type=\"button\"\n className=\"btn btn-ghost\"\n onClick={(e) => {\n e.stopPropagation();\n onClose();\n }}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn btn-danger\"\n onClick={(e) => {\n e.stopPropagation();\n onConfirmDelete();\n }}\n >\n Delete\n </button>\n </div>\n </div>\n )}\n </div>\n );\n\n return createPortal(body, document.body);\n}","// src/components/chat/AgentNode.tsx — single card in the agent orchestration tree.\n//\n// Two modes:\n// collapsible=true — header is a button with a chevron; toggles its\n// own summary + children visibility.\n// collapsible=false — header is a static div (no chevron / no toggle).\n// Children render if present but cannot be\n// collapsed by the user.\n//\n// FIX #1 (session-collapsed-by-default) is handled at the *parent*\n// (SubAgentList / AgentTree) which decides whether to mount this\n// node's children at all. This component is purely presentational.\n\nimport { useState } from 'react';\n\nexport type AgentStatus = 'idle' | 'streaming' | 'done' | 'blocked' | 'awaiting';\n\nexport interface AgentTreeNode {\n id: string;\n name: string;\n role?: string;\n status: AgentStatus;\n summary?: string;\n children?: AgentTreeNode[];\n}\n\ninterface Props {\n node: AgentTreeNode;\n depth?: number;\n collapsible?: boolean;\n isLast?: boolean;\n /** Controlled open state — used by SubAgentList so the parent rail\n * row's tree-chevron is the single source of truth for collapse. */\n open?: boolean;\n onToggle?: (next: boolean) => void;\n}\n\nexport function AgentNode({\n node,\n depth = 0,\n collapsible = false,\n isLast = true,\n open: controlledOpen,\n onToggle,\n}: Props) {\n const [internalOpen, setInternalOpen] = useState<boolean>(collapsible);\n const isControlled = controlledOpen !== undefined;\n const open = isControlled ? controlledOpen : internalOpen;\n const setOpen = (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onToggle?.(next);\n };\n\n const hasChildren = (node.children?.length ?? 0) > 0;\n\n const headContent = (\n <>\n {collapsible && (\n <span\n className={`agent-node-chevron ${open ? 'open' : ''}`}\n aria-hidden\n >\n ›\n </span>\n )}\n <span\n className={`agent-node-dot status-${node.status}`}\n aria-hidden\n />\n <span className=\"agent-node-name\">{node.name}</span>\n {node.role && <span className=\"agent-node-role chat-mono\">{node.role}</span>}\n <span className={`agent-node-pill status-${node.status}`}>{node.status}</span>\n </>\n );\n\n return (\n <div\n className={[\n 'agent-node',\n `depth-${depth}`,\n `status-${node.status}`,\n open ? 'open' : 'closed',\n isLast ? 'last' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {collapsible ? (\n <button\n type=\"button\"\n className={`agent-node-head status-${node.status} collapsible`}\n onClick={(e) => {\n e.stopPropagation();\n setOpen(!open);\n }}\n aria-expanded={open}\n >\n {headContent}\n </button>\n ) : (\n <div className={`agent-node-head status-${node.status}`}>\n {headContent}\n </div>\n )}\n {open && (\n <>\n {node.summary && (\n <div className=\"agent-node-summary\">{node.summary}</div>\n )}\n {hasChildren && (\n <div className=\"agent-node-children\">\n {node.children!.map((child, i) => (\n <AgentNode\n key={child.id}\n node={child}\n depth={depth + 1}\n collapsible={false}\n isLast={i === node.children!.length - 1}\n />\n ))}\n </div>\n )}\n </>\n )}\n </div>\n );\n}","// src/components/chat/AgentTree.tsx — vertical chain of session cards connected by\n// backbone+L-stub connectors. Two modes:\n//\n// full tree (variant=\"full\") — renders the root card and all its children.\n// Used inside the thread head when the active session has sub-agents.\n//\n// children-only (variant=\"rail\" via SubAgentList) — renders only the children\n// of the root; the rail row above already shows the root card, so\n// re-rendering it would duplicate. Children hang directly off the\n// rail row via standard backbone + L-stub connectors.\n//\n// FIX #1 — the parent (ChatRail) passes `open=false` by default for a\n// freshly-clicked session so the tree is collapsed on first click; the\n// user can open it via the chevron in the row.\n\nimport { Fragment } from 'react';\nimport { AgentNode, type AgentTreeNode } from './AgentNode';\n\ninterface FullTreeProps {\n tree: { root: AgentTreeNode };\n variant?: 'full';\n open?: boolean;\n}\n\ninterface ChildrenOnlyProps {\n children: AgentTreeNode[];\n variant: 'rail' | 'thread';\n open?: boolean;\n}\n\nfunction isFullTree(props: FullTreeProps | ChildrenOnlyProps): props is FullTreeProps {\n return (props as FullTreeProps).tree !== undefined;\n}\n\nexport function AgentTree(props: FullTreeProps | ChildrenOnlyProps) {\n const open = props.open ?? true;\n\n if (isFullTree(props)) {\n return (\n <div className={`agent-tree variant-${props.variant ?? 'full'}`}>\n <AgentNode node={props.tree.root} depth={0} open={open} />\n </div>\n );\n }\n\n // Children-only path (used by SubAgentList hanging off the rail row).\n const list = props.children ?? [];\n return (\n <div className={`agent-tree variant-${props.variant} agent-tree-children-only`}>\n <div className=\"agent-tree-children-body\">\n {list.map((child, i) => (\n <Fragment key={child.id}>\n <AgentNode\n node={child}\n depth={0}\n collapsible={false}\n open={open}\n isLast={i === list.length - 1}\n />\n </Fragment>\n ))}\n </div>\n </div>\n );\n}\n\n/* ── SubAgentList — convenience wrapper used by the ChatRail to render\n the children of a session's tree directly under the active row. ── */\nexport function SubAgentList({\n children,\n variant = 'rail',\n open = true,\n}: {\n children: AgentTreeNode[];\n variant?: 'rail' | 'thread';\n open?: boolean;\n}) {\n if (!open) return null;\n return <AgentTree variant={variant} open={open} children={children} />;\n}","// src/components/chat/ChatRail.tsx — redesigned session rail (v3.22).\n//\n// Replaces the original SessionList. Layout follows the design HTML:\n// - sessions grouped by recency (Today / Yesterday / This week / Earlier)\n// - each row carries: status dot, title (with pin star), time + unread\n// badge, 3-dot menu trigger (hover-visible, top-right), and (when\n// active + has children) a collapse chevron (vertical-center,\n// right: 28px — to the LEFT of the 3-dot trigger so they never\n// overlap — see chat.css for the exact positioning).\n// - per-row 3-dot popover menu with three modes: main (rename/delete),\n// rename (inline input), confirm-delete (inline confirmation).\n// - active row hangs the agent orchestration tree below it (collapsed\n// by default on first click per FIX #1 — the user opens it via the\n// chevron).\n//\n// Props match the original SessionList so it can be swapped into\n// Chat.tsx without any further wiring. The new props are optional and\n// augment the rail with state + tree + menu behavior when supplied.\n\nimport { Fragment, useMemo, useRef, useState } from 'react';\nimport { Plus, ExternalLink } from 'lucide-react';\nimport type { ChatSession } from '../../lib/types';\nimport { EmptyState } from './EmptyState';\nimport { SessionRowMenu, type SessionMenuMode } from './SessionRowMenu';\nimport { SubAgentList } from './AgentTree';\nimport type { AgentTreeNode } from './AgentNode';\n\n/* ------------------------------------------------------------------ *\n * Display-augmented session shape. The data coming from the API is\n * a bare `ChatSession`; the rail overlays optional display fields.\n * ------------------------------------------------------------------ */\nexport type SessionState = 'idle' | 'streaming' | 'awaiting';\n\nexport interface DisplaySession extends ChatSession {\n state?: SessionState;\n unread?: number;\n pinned?: boolean;\n /** HH:MM display string; defaults derived from mtime */\n time?: string;\n /** Agent name shown in the row subtitle / status dot */\n agent?: string;\n /** Sub-agent tree for this session (root may have children). */\n tree?: { root: AgentTreeNode };\n}\n\ninterface Props {\n sessions: DisplaySession[];\n opencodeSessions?: DisplaySession[];\n activeSessionId: string;\n activeOpencodeSessionId: string | null;\n activeProject: { name: string } | null;\n creating: boolean;\n onCreateSession: () => void;\n onSelectSession: (id: string) => void;\n onSelectOpencodeSession: (s: DisplaySession) => void;\n /** Optional: rename / delete handlers. When omitted, those buttons\n * in the menu fall back to no-op + toast hint. */\n onRenameSession?: (id: string, title: string) => void;\n onDeleteSession?: (id: string) => void;\n /** Optional: group predicate. By default groups by day buckets. */\n groupBy?: (sessions: DisplaySession[]) => Record<string, DisplaySession[]>;\n}\n\nconst DEFAULT_GROUPS = ['Today', 'Yesterday', 'This week', 'Earlier'];\n\nfunction isSameDay(a: Date, b: Date) {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\nfunction dayDiff(a: Date, b: Date) {\n const ms = a.getTime() - b.getTime();\n return Math.floor(ms / (1000 * 60 * 60 * 24));\n}\n\nfunction defaultGroupBy(sessions: DisplaySession[]): Record<string, DisplaySession[]> {\n const now = new Date();\n const yesterday = new Date(now);\n yesterday.setDate(yesterday.getDate() - 1);\n const weekAgo = new Date(now);\n weekAgo.setDate(weekAgo.getDate() - 7);\n\n const groups: Record<string, DisplaySession[]> = {\n Today: [],\n Yesterday: [],\n 'This week': [],\n Earlier: [],\n };\n\n for (const s of sessions) {\n const d = new Date(Number(s.mtime) || Date.now());\n if (isSameDay(d, now)) groups.Today.push(s);\n else if (isSameDay(d, yesterday)) groups.Yesterday.push(s);\n else if (dayDiff(now, d) < 7) groups['This week'].push(s);\n else groups.Earlier.push(s);\n }\n return groups;\n}\n\nfunction formatTime(mtime: number): string {\n const d = new Date(Number(mtime) || Date.now());\n return d.toLocaleTimeString(undefined, {\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n });\n}\n\nfunction SessionStateIndicator({\n state,\n agent,\n}: {\n state: SessionState;\n agent?: string;\n}) {\n if (state === 'streaming') {\n return (\n <span\n className=\"session-state session-state-streaming\"\n title={`${agent || 'Odin'} is typing…`}\n />\n );\n }\n if (state === 'awaiting') {\n return (\n <span\n className=\"session-state session-state-awaiting\"\n title=\"Awaiting your reply\"\n aria-hidden\n />\n );\n }\n if (state === 'idle') {\n return <span className=\"session-state session-state-idle\" aria-hidden />;\n }\n return null;\n}\n\nexport function ChatRail({\n sessions,\n opencodeSessions = [],\n activeSessionId,\n activeOpencodeSessionId,\n activeProject,\n creating,\n onCreateSession,\n onSelectSession,\n onSelectOpencodeSession,\n onRenameSession,\n onDeleteSession,\n groupBy,\n}: Props) {\n const allSessions = useMemo<DisplaySession[]>(\n () => [...sessions, ...opencodeSessions],\n [sessions, opencodeSessions],\n );\n const sorted = useMemo(\n () => [...allSessions].sort((a, b) => Number(b.mtime ?? 0) - Number(a.mtime ?? 0)),\n [allSessions],\n );\n\n const grouped = useMemo(\n () => (groupBy ? groupBy(sorted) : defaultGroupBy(sorted)),\n [groupBy, sorted],\n );\n\n // FIX #1 — collapse-by-default for the active session's sub-agent\n // tree. State is per-session-id so toggling one session doesn't\n // reset the others.\n const [openTree, setOpenTree] = useState<Record<string, boolean>>({});\n const isTreeOpen = (id: string) => openTree[id] === true;\n\n // Per-row menu state (which session's menu is open + which mode).\n const [openMenuId, setOpenMenuId] = useState<string | null>(null);\n const [menuMode, setMenuMode] = useState<SessionMenuMode>('main');\n const [renameDraft, setRenameDraft] = useState('');\n const [menuAnchor, setMenuAnchor] = useState<{ id: string; rect: DOMRect } | null>(null);\n const rowRefs = useRef<Record<string, HTMLDivElement | null>>({});\n\n const openMenuFor = (id: string, mode: SessionMenuMode = 'main') => {\n const row = rowRefs.current[id];\n if (!row) return;\n const target =\n mode === 'main'\n ? row\n : row.querySelector<HTMLElement>('.chat-rail-item-menu-trigger') ?? row;\n setMenuAnchor({ id, rect: target.getBoundingClientRect() });\n setOpenMenuId(id);\n setMenuMode(mode);\n if (mode === 'rename') {\n const s = [...sessions, ...opencodeSessions].find((x) => x.id === id);\n setRenameDraft(s?.title ?? s?.id ?? '');\n }\n };\n const closeMenu = () => {\n setOpenMenuId(null);\n setMenuMode('main');\n setRenameDraft('');\n setMenuAnchor(null);\n };\n\n const handleSelect = (s: DisplaySession) => {\n if (s.source === 'opencode') {\n onSelectOpencodeSession(s);\n return;\n }\n onSelectSession(s.id);\n };\n\n const handleConfirmRename = () => {\n if (!menuAnchor) return;\n const sid = menuAnchor.id;\n const next = renameDraft.trim();\n if (!next) {\n closeMenu();\n return;\n }\n onRenameSession?.(sid, next);\n closeMenu();\n };\n\n const handleConfirmDelete = () => {\n if (!menuAnchor) return;\n onDeleteSession?.(menuAnchor.id);\n closeMenu();\n };\n\n const orderedGroups: Array<[string, DisplaySession[]]> = groupBy\n ? Object.entries(grouped)\n : DEFAULT_GROUPS.filter((g) => grouped[g]?.length).map(\n (g) => [g, grouped[g]] as [string, DisplaySession[]],\n );\n\n return (\n <aside className=\"chat-rail\">\n <div className=\"chat-rail-head\">\n <button\n type=\"button\"\n className=\"chat-new-btn\"\n onClick={onCreateSession}\n disabled={creating || !activeProject}\n title={activeProject ? 'Create new session' : 'Pick a project first'}\n aria-label=\"Create new session\"\n >\n <Plus size={14} aria-hidden />\n <span>{creating ? 'Creating…' : 'New session'}</span>\n </button>\n </div>\n\n {sorted.length === 0 ? (\n <div className=\"chat-sessions-empty\">\n <EmptyState\n icon={<Plus size={20} aria-hidden />}\n title={activeProject ? 'No sessions yet' : 'No project'}\n message={\n activeProject\n ? 'Create your first session to start chatting.'\n : 'Pick a project in Overview to scope chat sessions.'\n }\n />\n </div>\n ) : (\n <div className=\"chat-rail-list\">\n {orderedGroups.map(([group, items]) => (\n <div key={group} className=\"chat-rail-group\">\n <div className=\"chat-rail-group-label\">{group}</div>\n {items.map((s) => {\n const isOpencode = s.source === 'opencode';\n const isActive = isOpencode\n ? activeOpencodeSessionId === s.id\n : activeSessionId === s.id;\n const tree = s.tree;\n const hasChildren = !!(tree?.root?.children && tree.root.children.length > 0);\n const treeOpen = isTreeOpen(s.id);\n return (\n <Fragment key={isOpencode ? `oc-${s.id}` : s.id}>\n <div\n ref={(el) => {\n rowRefs.current[s.id] = el;\n }}\n role=\"button\"\n tabIndex={0}\n className={`chat-rail-item state-${s.state ?? 'idle'}${isActive ? ' active' : ''}`}\n onClick={() => handleSelect(s)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelect(s);\n }\n }}\n aria-current={isActive ? 'true' : undefined}\n >\n <SessionStateIndicator state={s.state ?? 'idle'} agent={s.agent} />\n <div className=\"chat-rail-item-title\">\n {s.pinned && (\n <span className=\"chat-rail-pin\" aria-hidden>\n ★\n </span>\n )}\n {isOpencode && (\n <ExternalLink\n size={11}\n style={{ color: 'var(--text-muted)', flexShrink: 0 }}\n aria-hidden\n />\n )}\n <span className=\"chat-ellipsis\">{s.title || s.id}</span>\n </div>\n <div className=\"chat-rail-item-meta\">\n <span className=\"chat-rail-item-meta-time\">\n {s.time ?? formatTime(s.mtime)}\n </span>\n {(s.unread ?? 0) > 0 && (\n <span className=\"chat-rail-badge\">{s.unread}</span>\n )}\n </div>\n <button\n type=\"button\"\n className={`chat-rail-item-menu-trigger${openMenuId === s.id ? ' open' : ''}`}\n aria-label={`Session options for ${s.title || s.id}`}\n aria-haspopup=\"menu\"\n aria-expanded={openMenuId === s.id}\n onClick={(e) => {\n e.stopPropagation();\n if (openMenuId === s.id) closeMenu();\n else openMenuFor(s.id, 'main');\n }}\n >\n <svg viewBox=\"0 0 14 14\" aria-hidden>\n <circle cx=\"3\" cy=\"7\" r=\"1.2\" fill=\"currentColor\" />\n <circle cx=\"7\" cy=\"7\" r=\"1.2\" fill=\"currentColor\" />\n <circle cx=\"11\" cy=\"7\" r=\"1.2\" fill=\"currentColor\" />\n </svg>\n </button>\n {isActive && hasChildren && (\n <button\n type=\"button\"\n className={`chat-rail-tree-chevron${treeOpen ? ' open' : ''}`}\n aria-label={treeOpen ? 'Collapse sub-agents' : 'Expand sub-agents'}\n aria-expanded={treeOpen}\n onClick={(e) => {\n e.stopPropagation();\n setOpenTree((cur) => ({ ...cur, [s.id]: !cur[s.id] }));\n }}\n >\n <svg viewBox=\"0 0 10 10\" aria-hidden>\n <polyline points=\"3,1.5 7,5 3,8.5\" />\n </svg>\n </button>\n )}\n </div>\n {isActive && hasChildren && treeOpen && tree?.root?.children && (\n <SubAgentList children={tree.root.children} variant=\"rail\" open />\n )}\n </Fragment>\n );\n })}\n </div>\n ))}\n </div>\n )}\n\n {openMenuId && menuAnchor && (\n <SessionRowMenu\n session={{\n id: menuAnchor.id,\n title:\n [...sessions, ...opencodeSessions].find((x) => x.id === menuAnchor.id)\n ?.title ?? menuAnchor.id,\n }}\n mode={menuMode}\n anchor={menuAnchor}\n renameDraft={renameDraft}\n setRenameDraft={setRenameDraft}\n onEdit={() => openMenuFor(openMenuId, 'rename')}\n onDeleteRequest={() => openMenuFor(openMenuId, 'confirm-delete')}\n onConfirmDelete={handleConfirmDelete}\n onConfirmRename={handleConfirmRename}\n onClose={closeMenu}\n />\n )}\n </aside>\n );\n}","// src/components/chat/ChatComposer.tsx — bottom composer pill (v4.2.5).\n//\n// v4.2.5 — small refinement: the pill's border picks up the\n// activeSource color (opencode → accent border; bizar → neutral),\n// so the user has visual confirmation that their next message will\n// land in the right backend.\n\nimport { useState } from 'react';\nimport { Composer } from './Composer';\n\ninterface Props {\n agent: string;\n setAgent: (a: string) => void;\n model: string;\n setModel: (m: string) => void;\n text: string;\n setText: (t: string) => void;\n sending: boolean;\n onSend: () => void;\n attachments: string[];\n setAttachments: (a: string[] | ((prev: string[]) => string[])) => void;\n suggestions: Array<{ cmd: string; desc: string }>;\n onPickSuggestion: (cmd: string) => void;\n agents: Array<{ name: string }>;\n onAttach: () => void;\n /** Which stream will receive the next message. */\n activeSource?: 'bizar' | 'opencode' | null;\n /** Backward-compat — used to be page-level panel toggles. Ignored. */\n sessionsOpen?: boolean;\n /** Backward-compat — see sessionsOpen. */\n infoOpen?: boolean;\n}\n\nexport function ChatComposer(props: Props) {\n const { text, sending, onSend, activeSource } = props;\n const [takingOff, setTakingOff] = useState(false);\n\n const handleSend = () => {\n if (!text.trim() || sending) return;\n setTakingOff(true);\n onSend();\n window.setTimeout(() => setTakingOff(false), 320);\n };\n\n return (\n <div\n className={`chat-composer-wrap chat-composer-source-${activeSource ?? 'none'}`}\n >\n <div className={`chat-composer-pill${takingOff ? ' takeoff' : ''}`}>\n <Composer {...props} onSend={handleSend} />\n </div>\n <div className=\"chat-composer-hint chat-muted\">\n <span>\n <kbd>⏎</kbd> send\n </span>\n <span>\n <kbd>⇧⏎</kbd> newline\n </span>\n <span>\n <kbd>/</kbd> commands\n </span>\n {activeSource === 'opencode' && (\n <span className=\"chat-composer-source-hint\">→ opencode</span>\n )}\n {activeSource === 'bizar' && (\n <span className=\"chat-composer-source-hint\">→ bizar chat</span>\n )}\n {sending && <span className=\"chat-composer-source-hint\">sending…</span>}\n </div>\n </div>\n );\n}\n","// src/components/chat/ChatInfoPanel.tsx — right info panel (v4.2.5).\n//\n// v4.2.5 — overhauled: shows session metadata (id, agent, model,\n// provider, message count), the current `activeSource`, the model\n// in use, a section for usage/cost placeholders (filled in by the\n// MiniMax usage module when present), and rename / delete / export\n// actions wired to the parent.\n//\n// v5.0.0 — bug #4 fix: the panel now renders a structured error\n// section when the opencode session load fails. The chat-thread\n// header (rendered by Chat.tsx) also shows the error inline; the\n// info-panel error makes it impossible to miss when the right\n// sidebar is in view, and exposes the server's `suggestion` and a\n// Retry button so the operator can act without scrolling.\n\nimport { useEffect, useState } from 'react';\nimport {\n AlertTriangle,\n MessageSquare,\n Bot,\n Server,\n Terminal,\n Pencil,\n Trash2,\n Download,\n CircleDollarSign,\n RotateCw,\n} from 'lucide-react';\nimport type { ChatMessage } from '../../lib/types';\n\ninterface Props {\n sessionId: string;\n messages: ChatMessage[];\n pinned: Set<number>;\n agent: string;\n model: string;\n agents: Array<{ name: string; model?: string; mode?: string }>;\n mcps: Array<{ id: string; command?: string; enabled?: boolean }>;\n allCommands: Array<{ cmd: string; desc: string; mod?: string }>;\n /** Which stream is currently displayed. */\n activeSource?: 'bizar' | 'opencode' | null;\n /** Optional rename/delete/export handlers wired by Chat.tsx. */\n onRename?: () => void;\n onDelete?: () => void;\n onExport?: () => void;\n /** Per-action busy flags — disable buttons while pending. */\n busy?: { rename?: boolean; delete?: boolean };\n /**\n * v5.0.0 — bug #4: structured error envelope from `loadOpencodeSession`.\n * When present, the panel renders an error section above the Session\n * section so the operator can see what went wrong without scrolling.\n */\n error?: {\n code: string;\n message: string;\n suggestion?: string | null;\n canRetry?: boolean;\n } | null;\n /**\n * v5.0.0 — bug #4: retry handler invoked when the operator clicks\n * the Retry button on the error section. Wired to\n * `chat.retryOpencodeSession` by Chat.tsx.\n */\n onRetry?: () => void;\n}\n\ninterface UsageRow {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n costUsd: number;\n}\n\nfunction formatNumber(n: number): string {\n return n.toLocaleString();\n}\n\n/** Map a model id like \"opencode/deepseek-v4-flash-free\" → \"opencode\". */\nfunction providerFromModel(model: string): string {\n if (!model) return '';\n if (!model.includes('/')) return '';\n return model.split('/')[0];\n}\n\n/** Map a model id to a cost (USD/M-token) — placeholder rates; the\n * MiniMax usage module supplies real numbers where available. */\nfunction approxCostPer1M(model: string): number {\n if (!model) return 0;\n const m = model.toLowerCase();\n if (m.includes('opus')) return 15;\n if (m.includes('sonnet')) return 3;\n if (m.includes('haiku')) return 0.8;\n if (m.includes('gpt-4o')) return 5;\n if (m.includes('gpt-4')) return 10;\n if (m.includes('deepseek')) return 0.27;\n if (m.includes('minimax')) return 0.3;\n if (m.includes('llama-3.3-70b')) return 0.59;\n return 1;\n}\n\nexport function ChatInfoPanel({\n sessionId,\n messages,\n pinned,\n agent,\n model,\n agents,\n mcps,\n allCommands,\n activeSource = 'bizar',\n onRename,\n onDelete,\n onExport,\n busy,\n error,\n onRetry,\n}: Props) {\n // Best-effort: pull usage summary from the MiniMax usage endpoint\n // when the session is opencode. Falls back silently if the module\n // isn't installed yet.\n const [usage, setUsage] = useState<UsageRow | null>(null);\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const res = await fetch('/api/usage?range=24h', {\n headers: { Accept: 'application/json' },\n });\n if (!res.ok) return;\n const body = (await res.json()) as UsageRow;\n if (!cancelled) setUsage(body);\n } catch {\n /* ignore — usage is non-essential */\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [sessionId]);\n\n const msgCount = messages?.length ?? 0;\n const pinnedCount = pinned?.size ?? 0;\n\n // Estimate tokens / cost from message length when no real usage\n // data is available. Real numbers come from the MiniMax module.\n const totalChars = messages.reduce(\n (n, m) => n + ((m.content || m.message || '') as string).length,\n 0,\n );\n const approxTokens = Math.round(totalChars / 4);\n const rate = approxCostPer1M(model);\n const approxCostUsd = (approxTokens / 1_000_000) * rate;\n const tokensUsed = usage?.totalTokens ?? approxTokens;\n const costUsd = usage?.costUsd ?? approxCostUsd;\n const tokensTotal = 128_000;\n const provider = providerFromModel(model);\n\n return (\n <aside className=\"chat-info\">\n {error && (\n <div\n className=\"chat-info-section chat-info-error\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n <h4>\n <AlertTriangle\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n Couldn't load session\n </h4>\n <p className=\"chat-info-value chat-ellipsis\" title={error.message}>\n {error.message}\n </p>\n <div className=\"chat-info-mono\">\n code · {error.code}\n </div>\n {error.suggestion ? (\n <p className=\"chat-info-suggestion\">{error.suggestion}</p>\n ) : null}\n {error.canRetry !== false && onRetry ? (\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-sm chat-info-retry\"\n onClick={onRetry}\n title=\"Retry loading the session\"\n >\n <RotateCw size={12} aria-hidden /> Retry\n </button>\n ) : null}\n </div>\n )}\n\n <div className=\"chat-info-section\">\n <div className=\"chat-info-section-head\">\n <h4>\n <MessageSquare\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n Session\n </h4>\n <span\n className={`chat-source-badge chat-source-${activeSource ?? 'none'}`}\n style={{ marginLeft: 'auto' }}\n >\n {activeSource === 'opencode' ? 'opencode' : 'bizar chat'}\n </span>\n </div>\n <div className=\"chat-info-mono chat-ellipsis\" title={sessionId}>\n {sessionId || 'Live'}\n </div>\n <div className=\"chat-info-mono\">\n {formatNumber(msgCount)} message{msgCount === 1 ? '' : 's'}\n {pinnedCount > 0 && ` · ${pinnedCount} pinned`}\n </div>\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <Bot size={11} style={{ marginRight: 4, verticalAlign: -1 }} aria-hidden />{' '}\n Agent\n </h4>\n <div className=\"chat-info-value\">{agent || '—'}</div>\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <Server size={11} style={{ marginRight: 4, verticalAlign: -1 }} aria-hidden />{' '}\n Model\n </h4>\n <div className=\"chat-mono chat-ellipsis\" title={model}>\n {model || '—'}\n </div>\n {provider && (\n <div className=\"chat-info-mono\">provider · {provider}</div>\n )}\n </div>\n\n <div className=\"chat-info-section\">\n <h4>Tokens</h4>\n <div className=\"chat-mono\">\n {formatNumber(tokensUsed)} / {formatNumber(tokensTotal)}\n </div>\n <div className=\"chat-info-bar\" aria-hidden>\n <div\n className=\"chat-info-bar-fill\"\n style={{\n width: `${Math.min(100, (tokensUsed / Math.max(1, tokensTotal)) * 100)}%`,\n }}\n />\n </div>\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <CircleDollarSign\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n Cost\n </h4>\n <div className=\"chat-mono\">${costUsd.toFixed(4)}</div>\n {!usage && (\n <div className=\"chat-info-mono\">approx · live from MiniMax</div>\n )}\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <Bot\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n Attached agents\n </h4>\n {agents?.length ? (\n <div className=\"chat-info-agents\">\n {agents.map((a) => (\n <span key={a.name} className=\"chat-info-agent\">\n {a.name}\n </span>\n ))}\n </div>\n ) : (\n <div className=\"chat-info-mono\">None attached</div>\n )}\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <Server\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n MCPs\n </h4>\n {mcps?.length ? (\n <div className=\"chat-info-agents\">\n {mcps.map((m) => (\n <span key={m.id} className=\"chat-info-agent\">\n {m.id}\n </span>\n ))}\n </div>\n ) : (\n <div className=\"chat-info-mono\">No MCPs configured</div>\n )}\n </div>\n\n <div className=\"chat-info-section\">\n <h4>\n <Terminal\n size={11}\n style={{ marginRight: 4, verticalAlign: -1 }}\n aria-hidden\n />{' '}\n Slash commands\n </h4>\n <div className=\"chat-info-mono\">{allCommands?.length ?? 0} available</div>\n </div>\n\n {(onRename || onDelete || onExport) && (\n <div className=\"chat-info-section\">\n <h4>Actions</h4>\n <div className=\"chat-info-actions\">\n {onRename && (\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-sm\"\n onClick={onRename}\n disabled={busy?.rename}\n title=\"Rename session\"\n >\n <Pencil size={12} aria-hidden /> Rename\n </button>\n )}\n {onExport && (\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-sm\"\n onClick={onExport}\n title=\"Export transcript\"\n >\n <Download size={12} aria-hidden /> Export\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-sm btn-danger\"\n onClick={onDelete}\n disabled={busy?.delete}\n title=\"Delete session\"\n >\n <Trash2 size={12} aria-hidden /> Delete\n </button>\n )}\n </div>\n </div>\n )}\n </aside>\n );\n}\n","// src/components/chat/JumpToLatest.tsx — floating pill above the composer.\n//\n// Two visual variants:\n// - streaming (current session is being replied to): pulsing indigo\n// border + 3-dot bounce + green \"live\" badge\n// - idle: neutral pill + down-arrow icon + \"N new\" badge\n//\n// Hidden entirely when the user is already at the bottom of the thread\n// (controlled by the parent's `stickToBottom` flag).\n\nimport { ArrowDown } from 'lucide-react';\n\ninterface Props {\n streaming: boolean;\n newMessageCount: number;\n onClick: () => void;\n /** Optional label override (e.g. \"Odin is replying\"). */\n streamingLabel?: string;\n}\n\nexport function JumpToLatest({\n streaming,\n newMessageCount,\n onClick,\n streamingLabel = 'Odin is replying',\n}: Props) {\n return (\n <button\n type=\"button\"\n className={`jump-to-latest${streaming ? ' is-streaming' : ''}`}\n onClick={onClick}\n aria-label=\"Jump to latest message\"\n title=\"Jump to latest (⌘/Ctrl+End)\"\n >\n {streaming ? (\n <>\n <span className=\"jump-dots\" aria-hidden>\n <span />\n <span />\n <span />\n </span>\n <span>{streamingLabel}</span>\n {newMessageCount > 0 && (\n <span className=\"jump-badge jump-badge-live\">live</span>\n )}\n </>\n ) : (\n <>\n <ArrowDown size={14} aria-hidden />\n <span>Jump to latest</span>\n {newMessageCount > 0 && (\n <span className=\"jump-badge\">{newMessageCount} new</span>\n )}\n </>\n )}\n </button>\n );\n}","// src/views/Chat.tsx — desktop chat view (v4.2.5 design).\n//\n// v4.2.5 — chat overhaul:\n// * 3-column grid preserved (rail / thread / info).\n// * Composer goes through `chat.onSend`, which transparently routes\n// to the right backend endpoint based on `activeSource`:\n// - opencode session active → POST /api/opencode-sessions/:id/send\n// - otherwise → POST /api/chat\n// * \"New session\" button calls `chat.onCreateSession` which tries\n// POST /api/opencode-sessions/new first (so the new session is a\n// fully-fledged opencode session, scoped to the active worktree),\n// falling back to the local jsonl store when the opencode plugin\n// is offline.\n// * Top-of-thread badge shows the active source (\"opencode\" or\n// \"bizar chat\") so the user always knows where messages are going.\n// * Info panel gets session metadata + rename/delete actions.\n//\n// The page-level grid and CSS classes are unchanged so the rail/info\n// widths in the .chat-page grid continue to apply.\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { Trash2, Pencil } from 'lucide-react';\nimport { ChatTopBar } from '../components/chat/ChatTopBar';\nimport { ChatRail } from '../components/chat/ChatRail';\nimport { ChatThread } from '../components/chat/ChatThread';\nimport { ChatComposer } from '../components/chat/ChatComposer';\nimport { ChatInfoPanel } from '../components/chat/ChatInfoPanel';\nimport { JumpToLatest } from '../components/chat/JumpToLatest';\nimport { useChat } from '../components/chat/useChat';\nimport { useSlashCommands } from '../components/chat/useSlashCommands';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { Button } from '../components/Button';\nimport type { Snapshot, Settings } from '../lib/types';\n\ninterface Props {\n snapshot: Snapshot;\n settings: Settings;\n setActiveTab?: (id: string) => void;\n refreshSnapshot?: () => Promise<void>;\n initialTaskId?: string | null;\n onClearTaskId?: () => void;\n}\n\nexport function Chat({\n snapshot,\n settings,\n setActiveTab,\n initialTaskId,\n onClearTaskId,\n}: Props) {\n const toast = useToast();\n const modal = useModal();\n\n const chat = useChat(snapshot, settings, initialTaskId ?? '');\n // Wire toast + modal surfaces to useChat so async ops can surface\n // feedback without each view passing handlers down.\n useEffect(() => {\n chat.setToast({\n error: (msg: string) => toast.error(msg),\n success: (msg: string) => toast.success(msg),\n info: (msg: string) => toast.info(msg),\n warning: (msg: string) => toast.warning(msg),\n });\n }, [chat, toast]);\n\n // ── Composer state (local) ───────────────────────────────────────────────\n const [text, setText] = useState('');\n const [agent, setAgent] = useState(settings.defaultAgent || 'odin');\n const [model, setModel] = useState(settings.defaultModel || '');\n const [attachments, setAttachments] = useState<string[]>([]);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // ── Slash commands ───────────────────────────────────────────────────────\n const { allCommands, suggestions, setQuery } = useSlashCommands(snapshot);\n\n useEffect(() => {\n setQuery(text);\n }, [text, setQuery]);\n\n // ── File attach ──────────────────────────────────────────────────────────\n const onAttach = () => fileInputRef.current?.click();\n const onFiles = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files) return;\n const next: string[] = [];\n for (let i = 0; i < files.length; i++) next.push(files[i].name);\n setAttachments((cur) => {\n const newNames = next.filter((n) => !cur.includes(n));\n return [...cur, ...newNames];\n });\n if (fileInputRef.current) fileInputRef.current.value = '';\n };\n\n // ── Send ─────────────────────────────────────────────────────────────────\n const handleSend = async () => {\n const msg = text.trim();\n if (!msg) return;\n setText('');\n setQuery('');\n const result = await chat.onSend(msg, agent, model, attachments);\n if (result.ok) chat.jumpToLatest();\n };\n\n // ── Create session ───────────────────────────────────────────────────────\n const handleCreateSession = async () => {\n if (chat.busy.create) return;\n await chat.onCreateSession();\n };\n\n // ── Delete message (via modal) ───────────────────────────────────────────\n const handleDelete = (idx: number) => {\n modal.open({\n title: 'Delete message?',\n children: <p style={{ margin: 0 }}>This action cannot be undone.</p>,\n footer: (\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => modal.close()}>\n Cancel\n </Button>\n <Button\n variant=\"danger\"\n size=\"sm\"\n onClick={() => {\n modal.close();\n chat.deleteMessage(idx);\n }}\n >\n Delete\n </Button>\n </div>\n ),\n });\n };\n\n // ── Rename session (info panel action) ───────────────────────────────────\n const handleRename = (id: string, currentTitle: string) => {\n let next = '';\n modal.open({\n title: 'Rename session',\n children: (\n <input\n id=\"rename-session-input\"\n autoFocus\n defaultValue={currentTitle}\n aria-label=\"Session title\"\n onChange={(e) => {\n next = e.target.value;\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n modal.close();\n chat.renameSession(id, next).then((ok) => {\n if (ok) {\n toast.success('Renamed.');\n }\n });\n }\n }}\n style={{\n width: '100%',\n padding: '8px 10px',\n background: 'var(--bg)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n color: 'var(--text)',\n font: '13px/1.4 var(--font-sans)',\n marginTop: 6,\n }}\n />\n ),\n footer: (\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => modal.close()}>\n Cancel\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => {\n modal.close();\n chat.renameSession(id, next);\n }}\n >\n Save\n </Button>\n </div>\n ),\n });\n };\n\n // ── Delete session (info panel action) ───────────────────────────────────\n const handleDeleteSession = (id: string, title: string) => {\n modal.open({\n title: 'Delete session?',\n children: (\n <p style={{ margin: 0 }}>\n Delete <strong>{title}</strong>? Messages on the opencode serve\n will be removed. This cannot be undone.\n </p>\n ),\n footer: (\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => modal.close()}>\n Cancel\n </Button>\n <Button\n variant=\"danger\"\n size=\"sm\"\n onClick={async () => {\n modal.close();\n await chat.deleteSession(id);\n }}\n >\n Delete\n </Button>\n </div>\n ),\n });\n };\n\n // ── Export transcript ────────────────────────────────────────────────────\n const handleExport = () => {\n const sessionId =\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId\n : chat.sessionId;\n if (!sessionId) return;\n const msgs =\n chat.activeSource === 'opencode'\n ? chat.opencodeMessages\n : chat.bizarMessages;\n const text = msgs\n .map((m) => {\n const ts = m.ts ?? '';\n const who = (m.role || 'unknown').toUpperCase();\n const c = m.content || m.message || '';\n return `[${ts}] ${who}: ${c}`;\n })\n .join('\\n\\n');\n const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `${sessionId}.txt`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n };\n\n // ── Derived: sessions with display state overlaid ────────────────────────\n const displaySessions = useMemo(\n () => chat.sessions.map((s) => chat.getSessionDisplay(s)),\n [chat.sessions, chat.getSessionDisplay],\n );\n const displayOpencodeSessions = useMemo(\n () => chat.opencodeSessions.map((s) => chat.getSessionDisplay(s)),\n [chat.opencodeSessions, chat.getSessionDisplay],\n );\n\n // ── Current session for the thread head subtitle ────────────────────────\n const activeSessionDisplay = useMemo(() => {\n const id =\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId ?? ''\n : chat.sessionId;\n if (!id) return null;\n return (\n displaySessions.find((s) => s.id === id) ??\n displayOpencodeSessions.find((s) => s.id === id) ??\n null\n );\n }, [\n chat.activeSource,\n chat.activeOpencodeSessionId,\n chat.sessionId,\n displaySessions,\n displayOpencodeSessions,\n ]);\n\n const threadSubtitle = (() => {\n const base = `${agent || 'Odin'} · ${snapshot.activeProject?.name ?? 'no project'}`;\n const state = activeSessionDisplay?.state ?? 'idle';\n if (state === 'streaming') return `Replying · ${base}`;\n if (state === 'awaiting') return `Your turn · ${base}`;\n return `${base} · idle`;\n })();\n\n // The badge in the thread head: \"opencode\" or \"bizar chat\".\n const sourceLabel =\n chat.activeSource === 'opencode' ? 'opencode' : 'bizar chat';\n\n return (\n <div className=\"chat-shell\">\n <ChatTopBar\n activeProject={snapshot.activeProject}\n sessionCount={chat.sessions.length}\n sessionsOpen={true}\n infoOpen={true}\n onToggleSessions={() => {}}\n onToggleInfo={() => {}}\n onOpenOverview={() => setActiveTab?.('overview')}\n />\n <div className=\"chat-page\">\n {/* ── rail ──────────────────────────────────────────────────────── */}\n <ChatRail\n sessions={displaySessions}\n opencodeSessions={displayOpencodeSessions}\n activeSessionId={chat.sessionId}\n activeOpencodeSessionId={chat.activeOpencodeSessionId}\n activeProject={snapshot.activeProject}\n creating={chat.busy.create}\n onCreateSession={handleCreateSession}\n onSelectSession={chat.selectBizarSession}\n onSelectOpencodeSession={(s) => chat.loadOpencodeSession(s.id)}\n onRenameSession={handleRename}\n onDeleteSession={(id) => {\n const s = chat.sessions.find((s) => s.id === id) ?? chat.opencodeSessions.find((s) => s.id === id);\n handleDeleteSession(id, s?.title ?? '');\n }}\n />\n\n {/* ── thread ───────────────────────────────────────────────────── */}\n <section className=\"chat-thread-section\">\n <div className=\"chat-thread-head\">\n <div>\n <div className=\"chat-thread-title-row\">\n <div className=\"chat-thread-title\">\n {activeSessionDisplay?.title ?? chat.sessionId ?? 'New chat'}\n </div>\n <span\n className={`chat-source-badge chat-source-${\n chat.activeSource ?? 'none'\n }`}\n title={\n chat.activeSource === 'opencode'\n ? 'Messages go to the opencode serve child'\n : 'Messages go to the local chat store'\n }\n >\n {sourceLabel}\n </span>\n </div>\n <div\n className={`chat-thread-sub chat-muted state-${\n activeSessionDisplay?.state ?? 'idle'\n }`}\n >\n <span className=\"chat-thread-dot\" />\n {threadSubtitle}\n </div>\n {chat.opencodeError && (\n <div className=\"chat-thread-error\" role=\"alert\">\n <p className=\"chat-error-message\">{chat.opencodeError}</p>\n {chat.opencodeSuggestion && (\n <p className=\"chat-error-suggestion\">{chat.opencodeSuggestion}</p>\n )}\n {chat.activeOpencodeSessionId && (\n <button\n className=\"btn btn-sm\"\n type=\"button\"\n onClick={() =>\n chat.loadOpencodeSession(chat.activeOpencodeSessionId!)\n }\n >\n Retry\n </button>\n )}\n </div>\n )}\n </div>\n <div className=\"chat-thread-actions\">\n {activeSessionDisplay && (\n <button\n className=\"btn btn-ghost\"\n title=\"Rename session\"\n type=\"button\"\n disabled={chat.busy.rename}\n onClick={() =>\n handleRename(\n activeSessionDisplay.id,\n activeSessionDisplay.title ?? '',\n )\n }\n >\n <Pencil size={12} aria-hidden />{' '}\n <span className=\"mono\">rename</span>\n </button>\n )}\n {activeSessionDisplay && (\n <button\n className=\"btn btn-ghost btn-danger\"\n title=\"Delete session\"\n type=\"button\"\n disabled={chat.busy.delete}\n onClick={() =>\n handleDeleteSession(\n activeSessionDisplay.id,\n activeSessionDisplay.title ?? activeSessionDisplay.id,\n )\n }\n >\n <Trash2 size={12} aria-hidden />{' '}\n <span className=\"mono\">delete</span>\n </button>\n )}\n <button\n className=\"btn btn-ghost\"\n title=\"Export transcript\"\n type=\"button\"\n onClick={handleExport}\n >\n <span className=\"mono\">export</span>\n </button>\n </div>\n </div>\n\n <div\n className=\"chat-thread-scroll\"\n ref={chat.listRef}\n onScroll={chat.handleScroll}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n aria-label=\"Chat message thread\"\n >\n <ChatThread\n messages={\n chat.activeSource === 'opencode'\n ? chat.opencodeMessages\n : chat.bizarMessages\n }\n loading={chat.loading}\n activeProject={snapshot.activeProject}\n sessionId={\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId ?? chat.sessionId\n : chat.sessionId\n }\n pinned={chat.pinned}\n activeSource={chat.activeSource}\n onPickSuggestion={(t) => setText(t)}\n onCopy={(m) =>\n chat.copyMessage(m as Parameters<typeof chat.copyMessage>[0])\n }\n onDelete={handleDelete}\n onTogglePin={chat.togglePin}\n onRegenerate={chat.onRegenerate}\n />\n </div>\n\n {!chat.stickToBottom && (\n <JumpToLatest\n streaming={activeSessionDisplay?.state === 'streaming'}\n newMessageCount={chat.newMessageCount}\n onClick={chat.jumpToLatest}\n />\n )}\n\n <ChatComposer\n agent={agent}\n setAgent={setAgent}\n model={model}\n setModel={setModel}\n text={text}\n setText={setText}\n sending={chat.sending}\n activeSource={chat.activeSource}\n onSend={handleSend}\n attachments={attachments}\n setAttachments={setAttachments}\n suggestions={suggestions}\n onPickSuggestion={(cmd) => setText(`${cmd.split(' ')[0]} `)}\n agents={snapshot.agents || []}\n onAttach={onAttach}\n />\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n style={{ display: 'none' }}\n onChange={onFiles}\n aria-label=\"Attach files to message\"\n tabIndex={-1}\n />\n </section>\n\n {/* ── info panel ──────────────────────────────────────────────── */}\n <ChatInfoPanel\n sessionId={\n chat.activeSource === 'opencode'\n ? chat.activeOpencodeSessionId ?? chat.sessionId\n : chat.sessionId\n }\n messages={\n chat.activeSource === 'opencode'\n ? chat.opencodeMessages\n : chat.bizarMessages\n }\n pinned={chat.pinned}\n agent={agent}\n model={model}\n agents={snapshot.agents || []}\n mcps={snapshot.mcps || []}\n allCommands={allCommands}\n activeSource={chat.activeSource}\n onRename={() => {\n if (activeSessionDisplay) {\n handleRename(\n activeSessionDisplay.id,\n activeSessionDisplay.title ?? '',\n );\n }\n }}\n onDelete={() => {\n if (activeSessionDisplay) {\n handleDeleteSession(\n activeSessionDisplay.id,\n activeSessionDisplay.title ?? activeSessionDisplay.id,\n );\n }\n }}\n onExport={handleExport}\n busy={chat.busy}\n />\n </div>\n </div>\n );\n}\n","// src/components/StatusBadge.tsx — small colored pill.\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../lib/utils';\n\n/**\n * v6.0.0 — Doctor variants. 'ok' / 'warn' / 'fail' map onto\n * 'success' / 'warning' / 'error' respectively so existing CSS\n * rules cover the Doctor page without a new palette entry. The\n * `kind` union is widened (additive only) so every existing caller\n * keeps type-checking against the same set.\n */\nexport type StatusKind =\n | 'success'\n | 'warning'\n | 'error'\n | 'info'\n | 'accent'\n | 'neutral'\n | 'ok'\n | 'warn'\n | 'fail';\n\nexport type StatusBadgeProps = {\n kind?: StatusKind;\n children: ReactNode;\n className?: string;\n dot?: boolean;\n};\n\n/**\n * Map a doctor-style status to the underlying badge kind. Done at\n * render time so callers don't have to translate; the CSS class is\n * always one of `badge-success | badge-warning | badge-error | …`.\n */\nfunction normalizeKind(kind: StatusKind): Exclude<StatusKind, 'ok' | 'warn' | 'fail'> {\n if (kind === 'ok') return 'success';\n if (kind === 'warn') return 'warning';\n if (kind === 'fail') return 'error';\n return kind;\n}\n\nexport function StatusBadge({\n kind = 'neutral',\n children,\n className,\n dot = false,\n}: StatusBadgeProps) {\n const normalized = normalizeKind(kind);\n return (\n <span className={cn('badge', `badge-${normalized}`, className)} title={`status: ${kind}`}>\n {dot && <span className=\"badge-dot\" />}\n {children}\n </span>\n );\n}\n","// src/views/Agents.tsx — v3.1.0 agents with tags, categories, real-time status.\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Bot,\n Plus,\n RefreshCw,\n Pencil,\n Trash2,\n Play,\n Save,\n X,\n RotateCw,\n Activity,\n Tag as TagIcon,\n Folder,\n CheckCircle2,\n Clock,\n AlertTriangle,\n Circle,\n ChevronDown,\n ChevronRight,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card, CardTitle } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { useModal } from '../components/Modal';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport { cn, formatRelative, truncate } from '../lib/utils';\nimport type { Agent, Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst TOOL_OPTIONS = ['bash', 'read', 'edit', 'write', 'webfetch', 'websearch', 'task', 'glob', 'grep'];\nconst MODELS = [\n 'anthropic/claude-3-5-sonnet',\n 'anthropic/claude-3-5-haiku',\n 'openai/gpt-4o',\n 'openai/gpt-4o-mini',\n 'openrouter/minimax/minimax-m3',\n 'openrouter/minimax/minimax-m2.7',\n];\n\nconst CATEGORIES = [\n { id: 'reasoning', label: 'Reasoning', color: 'var(--accent)' },\n { id: 'code', label: 'Code', color: 'var(--info)' },\n { id: 'design', label: 'Design', color: 'var(--success)' },\n { id: 'planning', label: 'Planning', color: 'var(--warning)' },\n { id: 'gitops', label: 'GitOps', color: 'var(--error)' },\n { id: 'analysis', label: 'Analysis', color: 'var(--text-dim)' },\n];\n\nfunction categoryColor(cat: string | undefined): string {\n return CATEGORIES.find((c) => c.id === cat)?.color || 'var(--text-dim)';\n}\n\nfunction StatusDot({ status, isStuck }: { status?: string; isStuck?: boolean }) {\n const color =\n isStuck ? 'var(--error)'\n : status === 'working' ? 'var(--info)'\n : status === 'error' ? 'var(--error)'\n : 'var(--text-dim)';\n return <span className=\"agent-status-dot\" style={{ background: color }} />;\n}\n\nfunction StatusPill({ agent }: { agent: Agent }) {\n if (agent.isStuck) {\n return <StatusBadge kind=\"error\" dot>stuck</StatusBadge>;\n }\n const status = agent.status || 'idle';\n if (status === 'working') return <StatusBadge kind=\"info\" dot>working</StatusBadge>;\n if (status === 'error') return <StatusBadge kind=\"error\" dot>error</StatusBadge>;\n return <StatusBadge kind=\"neutral\" dot>idle</StatusBadge>;\n}\n\nexport function Agents({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const modal = useModal();\n const [agents, setAgents] = useState<Agent[]>(snapshot.agents || []);\n const [loading, setLoading] = useState(!snapshot.agents);\n const [categoryFilter, setCategoryFilter] = useState<string>('');\n const [search, setSearch] = useState('');\n\n useEffect(() => {\n setAgents(snapshot.agents || []);\n setLoading(!snapshot.agents);\n }, [snapshot.agents]);\n\n const reload = async () => {\n try {\n const d = await api.get<{ agents: Agent[] }>('/agents');\n setAgents(d.agents || []);\n } catch (err) {\n toast.error(`Agents load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n const sorted = useMemo(() => {\n let out = [...agents];\n if (categoryFilter) {\n out = out.filter((a) => categoryFilter === '__none__' ? !(a.category || '') : (a.category || '') === categoryFilter);\n }\n if (search) {\n const q = search.toLowerCase();\n out = out.filter(\n (a) =>\n a.name.toLowerCase().includes(q) ||\n (a.description || '').toLowerCase().includes(q) ||\n (a.tags || []).some((t) => t.toLowerCase().includes(q)),\n );\n }\n return out.sort((a, b) => a.name.localeCompare(b.name));\n }, [agents, categoryFilter, search]);\n\n const allTags = useMemo(() => {\n const set = new Set<string>();\n for (const a of agents) for (const t of a.tags || []) set.add(t);\n return Array.from(set).sort();\n }, [agents]);\n\n const onCreate = () => {\n let nameEl: HTMLInputElement | null = null;\n let descEl: HTMLInputElement | null = null;\n let modelEl: HTMLSelectElement | null = null;\n let modeEl: HTMLSelectElement | null = null;\n let colorEl: HTMLInputElement | null = null;\n let promptEl: HTMLTextAreaElement | null = null;\n let toolsContainer: HTMLDivElement | null = null;\n let tagsEl: HTMLInputElement | null = null;\n let categoryEl: HTMLSelectElement | null = null;\n\n modal.open({\n title: 'New agent',\n width: 640,\n children: (\n <div className=\"agent-form\">\n <label className=\"field-label\" htmlFor=\"agent-new-name\">Name (a-z, 0-9, dashes)</label>\n <input\n id=\"agent-new-name\"\n ref={(el) => (nameEl = el)}\n className=\"input\"\n type=\"text\"\n placeholder=\"my-agent\"\n autoFocus\n />\n <label className=\"field-label\" htmlFor=\"agent-new-desc\">Description</label>\n <input\n id=\"agent-new-desc\"\n ref={(el) => { descEl = el; }}\n className=\"input\"\n type=\"text\"\n placeholder=\"What does this agent do?\"\n />\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"agent-new-model\">Model</label>\n <select id=\"agent-new-model\" ref={(el) => (modelEl = el)} className=\"select\" defaultValue=\"\">\n <option value=\"\">(provider default)</option>\n {MODELS.map((m) => (\n <option key={m} value={m}>{m}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"agent-new-mode\">Mode</label>\n <select id=\"agent-new-mode\" ref={(el) => (modeEl = el)} className=\"select\" defaultValue=\"subagent\">\n <option value=\"primary\">primary</option>\n <option value=\"subagent\">subagent</option>\n <option value=\"all\">all</option>\n </select>\n </div>\n <div className=\"task-form-field\" style={{ flex: '0 0 80px' }}>\n <label className=\"field-label\" htmlFor=\"agent-new-color\">Color</label>\n <input id=\"agent-new-color\" ref={(el) => (colorEl = el)} className=\"input\" type=\"color\" defaultValue=\"#8b5cf6\" />\n </div>\n </div>\n <div className=\"task-form-row\">\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"agent-new-category\">Category</label>\n <select id=\"agent-new-category\" ref={(el) => (categoryEl = el)} className=\"select\" defaultValue=\"\">\n <option value=\"\">(none)</option>\n {CATEGORIES.map((c) => (\n <option key={c.id} value={c.id}>{c.label}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\" style={{ flex: 2 }}>\n <label className=\"field-label\" htmlFor=\"agent-new-tags\">Tags (comma-separated)</label>\n <input id=\"agent-new-tags\" ref={(el) => (tagsEl = el)} className=\"input\" type=\"text\" placeholder=\"reasoning, code, planning\" />\n </div>\n </div>\n <fieldset>\n <legend className=\"field-label\" style={{ padding: 0 }}>Tools</legend>\n <div ref={(el) => (toolsContainer = el)} className=\"agent-tools\">\n {TOOL_OPTIONS.map((t) => (\n <label key={t} className=\"checkbox-row\">\n <input type=\"checkbox\" value={t} aria-label={t} />\n <span>{t}</span>\n </label>\n ))}\n </div>\n </fieldset>\n <label className=\"field-label\" htmlFor=\"agent-new-prompt\">System prompt</label>\n <textarea\n id=\"agent-new-prompt\"\n ref={(el) => (promptEl = el)}\n className=\"textarea\"\n rows={6}\n placeholder=\"You are a...\"\n />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n const name = (nameEl?.value || '').trim();\n if (!/^[a-z0-9][a-z0-9-]{0,63}$/i.test(name)) {\n toast.warning('Invalid name (a-z, 0-9, dashes).');\n return;\n }\n const tools: string[] = [];\n if (toolsContainer) {\n toolsContainer.querySelectorAll<HTMLInputElement>('input[type=\"checkbox\"]:checked').forEach((cb) => {\n tools.push(cb.value);\n });\n }\n const tags = (tagsEl?.value || '').split(',').map((t) => t.trim()).filter(Boolean);\n try {\n const created = await api.post<Agent>('/agents', {\n name,\n description: (descEl?.value || '').trim(),\n model: modelEl?.value || '',\n mode: modeEl?.value || 'subagent',\n color: colorEl?.value || '',\n tools,\n tags,\n category: categoryEl?.value || '',\n prompt: promptEl?.value || '',\n });\n setAgents((cur) => [...cur, created]);\n toast.success('Agent created.');\n modal.close();\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Create failed: ${(err as Error).message}`);\n }\n }}\n >\n <Save size={12} /> Create\n </Button>\n </div>\n ),\n });\n };\n\n const onEdit = async (a: Agent) => {\n let descEl: HTMLInputElement | null = null;\n let modelEl: HTMLSelectElement | null = null;\n let modeEl: HTMLSelectElement | null = null;\n let colorEl: HTMLInputElement | null = null;\n let promptEl: HTMLTextAreaElement | null = null;\n let toolsContainer: HTMLDivElement | null = null;\n let tagsEl: HTMLInputElement | null = null;\n let categoryEl: HTMLSelectElement | null = null;\n try {\n const full = await api.get<Agent>(`/agents/${encodeURIComponent(a.name)}`);\n modal.open({\n title: `Edit ${a.name}`,\n width: 640,\n children: (\n <div className=\"agent-form\">\n <div className=\"muted\">\n File: <code>{full.path}</code>\n </div>\n <label className=\"field-label\" htmlFor=\"agent-edit-desc\">Description</label>\n <input\n id=\"agent-edit-desc\"\n ref={(el) => { descEl = el; }}\n className=\"input\"\n type=\"text\"\n defaultValue={full.description}\n />\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"agent-edit-model\">Model</label>\n <select id=\"agent-edit-model\" ref={(el) => (modelEl = el)} className=\"select\" defaultValue={full.model}>\n <option value=\"\">(provider default)</option>\n {MODELS.map((m) => (\n <option key={m} value={m}>{m}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"agent-edit-mode\">Mode</label>\n <select id=\"agent-edit-mode\" ref={(el) => (modeEl = el)} className=\"select\" defaultValue={full.mode || 'subagent'}>\n <option value=\"primary\">primary</option>\n <option value=\"subagent\">subagent</option>\n <option value=\"all\">all</option>\n </select>\n </div>\n <div className=\"task-form-field\" style={{ flex: '0 0 80px' }}>\n <label className=\"field-label\" htmlFor=\"agent-edit-color\">Color</label>\n <input id=\"agent-edit-color\" ref={(el) => (colorEl = el)} className=\"input\" type=\"color\" defaultValue={full.color || '#8b5cf6'} />\n </div>\n </div>\n <div className=\"task-form-row\">\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"agent-edit-category\">Category</label>\n <select id=\"agent-edit-category\" ref={(el) => (categoryEl = el)} className=\"select\" defaultValue={full.category || ''}>\n <option value=\"\">(none)</option>\n {CATEGORIES.map((c) => (\n <option key={c.id} value={c.id}>{c.label}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\" style={{ flex: 2 }}>\n <label className=\"field-label\" htmlFor=\"agent-edit-tags\">Tags (comma-separated)</label>\n <input\n id=\"agent-edit-tags\"\n ref={(el) => (tagsEl = el)}\n className=\"input\"\n type=\"text\"\n defaultValue={(full.tags || []).join(', ')}\n />\n </div>\n </div>\n <fieldset>\n <legend className=\"field-label\" style={{ padding: 0 }}>Tools</legend>\n <div ref={(el) => (toolsContainer = el)} className=\"agent-tools\">\n {TOOL_OPTIONS.map((t) => (\n <label key={t} className=\"checkbox-row\">\n <input type=\"checkbox\" value={t} aria-label={t} defaultChecked={full.tools?.includes(t)} />\n <span>{t}</span>\n </label>\n ))}\n </div>\n </fieldset>\n <label className=\"field-label\" htmlFor=\"agent-edit-prompt\">System prompt</label>\n <textarea\n id=\"agent-edit-prompt\"\n ref={(el) => (promptEl = el)}\n className=\"textarea\"\n rows={8}\n defaultValue={full.prompt || ''}\n />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n const tools: string[] = [];\n if (toolsContainer) {\n toolsContainer.querySelectorAll<HTMLInputElement>('input[type=\"checkbox\"]:checked').forEach((cb) => {\n tools.push(cb.value);\n });\n }\n const tags = (tagsEl?.value || '').split(',').map((t) => t.trim()).filter(Boolean);\n try {\n const updated = await api.put<Agent>(\n `/agents/${encodeURIComponent(a.name)}`,\n {\n description: (descEl?.value || '').trim(),\n model: modelEl?.value || '',\n mode: modeEl?.value || 'subagent',\n color: colorEl?.value || '',\n tools,\n tags,\n category: categoryEl?.value || '',\n prompt: promptEl?.value || '',\n },\n );\n setAgents((cur) => cur.map((x) => (x.name === a.name ? updated : x)));\n toast.success('Agent saved.');\n modal.close();\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n }}\n >\n <Save size={12} /> Save\n </Button>\n </div>\n ),\n });\n } catch (err) {\n toast.error(`Load failed: ${(err as Error).message}`);\n }\n };\n\n const onDelete = async (a: Agent) => {\n if (!confirm(`Delete agent \"${a.name}\"? This removes ${a.path}.`)) return;\n try {\n await api.del(`/agents/${encodeURIComponent(a.name)}`);\n setAgents((cur) => cur.filter((x) => x.name !== a.name));\n toast.success('Agent deleted.');\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const onInvoke = async (a: Agent) => {\n let promptEl: HTMLTextAreaElement | null = null;\n modal.open({\n title: `Invoke ${a.name}`,\n children: (\n <div className=\"invoke-form\">\n <p className=\"muted invoke-form-meta mono\">{a.model || '—'} · {a.path}</p>\n <p className=\"invoke-form-desc\">{a.description}</p>\n <label className=\"field-label\" htmlFor=\"invoke-prompt\">Prompt</label>\n <textarea\n ref={(el) => (promptEl = el)}\n id=\"invoke-prompt\"\n className=\"textarea\"\n rows={5}\n placeholder=\"What should this agent do?\"\n autoFocus\n />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n const prompt = (promptEl?.value || '').trim();\n if (!prompt) {\n toast.warning('Prompt is required.');\n return;\n }\n try {\n await api.post(`/agents/${encodeURIComponent(a.name)}/invoke`, { prompt });\n toast.success(`Invoked ${a.name}.`);\n modal.close();\n } catch (err) {\n toast.error(`Invoke failed: ${(err as Error).message}`);\n }\n }}\n >\n <Play size={14} /> Invoke\n </Button>\n </div>\n ),\n });\n };\n\n const onRestart = async (a: Agent) => {\n try {\n const updated = await api.post<Agent>(`/agents/${encodeURIComponent(a.name)}/restart`);\n setAgents((cur) => cur.map((x) => (x.name === a.name ? updated : x)));\n toast.success(`${a.name} restarted.`);\n } catch (err) {\n toast.error(`Restart failed: ${(err as Error).message}`);\n }\n };\n\n const onSetStatus = async (a: Agent, status: 'idle' | 'working' | 'error') => {\n try {\n const updated = await api.post<Agent>(`/agents/${encodeURIComponent(a.name)}/status`, { status });\n setAgents((cur) => cur.map((x) => (x.name === a.name ? updated : x)));\n } catch (err) {\n toast.error(`Status update failed: ${(err as Error).message}`);\n }\n };\n\n return (\n <div className=\"view view-agents\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Bot size={18} /> Agents ({sorted.length})\n </h2>\n <p className=\"view-subtitle\">\n The Norse pantheon — click <kbd>Edit</kbd> to modify or <kbd>Invoke</kbd> to dispatch.\n </p>\n </div>\n <div className=\"view-actions\">\n <div className=\"search-input\">\n <label htmlFor=\"agents-search\" className=\"sr-only\">Search agents</label>\n <input\n id=\"agents-search\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Search…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label=\"Search agents\"\n />\n </div>\n <label htmlFor=\"agents-category-filter\" className=\"sr-only\">Filter by category</label>\n <select\n id=\"agents-category-filter\"\n className=\"select select-sm\"\n value={categoryFilter}\n onChange={(e) => setCategoryFilter(e.target.value)}\n >\n <option value=\"\">All categories</option>\n {CATEGORIES.map((c) => (\n <option key={c.id} value={c.id}>{c.label}</option>\n ))}\n <option value=\"__none__\">(no category)</option>\n </select>\n <Button variant=\"secondary\" size=\"sm\" onClick={reload}>\n <RefreshCw size={14} /> Refresh\n </Button>\n <Button variant=\"primary\" size=\"sm\" onClick={onCreate}>\n <Plus size={14} /> New agent\n </Button>\n </div>\n </header>\n\n {allTags.length > 0 && (\n <div className=\"agent-tags-row\">\n <TagIcon size={12} />\n {allTags.map((t) => (\n <span key={t} className=\"tag\">{t}</span>\n ))}\n </div>\n )}\n\n {loading ? (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n ) : sorted.length === 0 ? (\n <EmptyState\n icon={<Bot size={32} />}\n title=\"No agents found\"\n message=\"Run bizar in the terminal to install Bizar.\"\n />\n ) : (\n <div className=\"agent-grid\">\n {sorted.map((a) => (\n <AgentCard\n key={a.name}\n agent={a}\n onInvoke={() => onInvoke(a)}\n onEdit={() => onEdit(a)}\n onDelete={() => onDelete(a)}\n onRestart={() => onRestart(a)}\n onSetStatus={(s) => onSetStatus(a, s)}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction AgentCard({\n agent,\n onInvoke,\n onEdit,\n onDelete,\n onRestart,\n onSetStatus,\n}: {\n agent: Agent;\n onInvoke: () => void;\n onEdit: () => void;\n onDelete: () => void;\n onRestart: () => void;\n onSetStatus: (s: 'idle' | 'working' | 'error') => void;\n}) {\n const [expanded, setExpanded] = useState(false);\n const catColor = categoryColor(agent.category);\n const isWorking = (agent.status === 'working' || !!agent.currentTaskId) && !agent.isStuck;\n return (\n <Card\n variant=\"elevated\"\n interactive\n className={cn(\n 'agent-card',\n isWorking && 'is-working',\n agent.isStuck && 'is-stuck',\n )}\n >\n <div className=\"agent-card-head\">\n <div className=\"agent-card-name\">\n <StatusDot status={agent.status} isStuck={agent.isStuck} />\n {agent.name}\n </div>\n <div className=\"agent-card-badges\">\n {agent.category && (\n <span\n className=\"agent-card-category\"\n style={{ background: `color-mix(in srgb, ${catColor} 18%, transparent)`, color: catColor }}\n >\n {agent.category}\n </span>\n )}\n <StatusPill agent={agent} />\n </div>\n </div>\n <p className=\"agent-card-desc\">{truncate(agent.description, 200)}</p>\n <div className=\"agent-card-meta\">\n <span className=\"mono\" title={agent.model || ''}>\n {agent.model || '—'}\n </span>\n <span className=\"tabular-nums muted\">{formatRelative(agent.mtime)}</span>\n </div>\n {agent.tags && agent.tags.length > 0 && (\n <div className=\"agent-card-tags\">\n {agent.tags.map((t) => (\n <span key={t} className=\"agent-card-tag\">{t}</span>\n ))}\n </div>\n )}\n {(isWorking || agent.lastTask) && (\n <div className=\"agent-card-activity\">\n {agent.currentTaskId && (\n <div className=\"agent-card-row\">\n <Activity size={12} />\n <span className=\"muted\">Working on</span>\n <code className=\"mono\">{agent.currentTaskId}</code>\n </div>\n )}\n {agent.lastTask && !agent.currentTaskId && (\n <div className=\"agent-card-row\">\n <CheckCircle2 size={12} />\n <span className=\"muted\">Last</span>\n <code className=\"mono\">{agent.lastTask.id}</code>\n <span className=\"muted tabular-nums\">{formatRelative(agent.lastTask.finishedAt)}</span>\n </div>\n )}\n {agent.tasksTotal != null && agent.tasksTotal > 0 && (\n <div className=\"agent-card-row\">\n <Circle size={12} />\n <span className=\"muted\">Success rate</span>\n <span className=\"tabular-nums\">{Math.round((agent.successRate || 0) * 100)}%</span>\n <span className=\"muted tabular-nums\">({agent.tasksSucceeded}/{agent.tasksTotal})</span>\n </div>\n )}\n </div>\n )}\n {agent.lastError && (\n <div className=\"agent-card-error\">\n <AlertTriangle size={12} />\n <span className=\"muted\">Last error: {agent.lastError.message}</span>\n </div>\n )}\n <div className=\"agent-card-actions\">\n <Button variant=\"primary\" size=\"sm\" onClick={onInvoke}>\n <Play size={12} /> Invoke\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onEdit}>\n <Pencil size={12} /> Edit\n </Button>\n {(agent.isStuck || agent.status === 'working' || agent.status === 'error') && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onRestart} title=\"Reset agent status\">\n <RotateCw size={12} /> Restart\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" onClick={onDelete}>\n <Trash2 size={12} />\n </Button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label={expanded ? 'Collapse' : 'Expand'}\n onClick={() => setExpanded((v) => !v)}\n style={{ marginLeft: 'auto' }}\n >\n {expanded ? <ChevronDown size={12} /> : <ChevronRight size={12} />}\n </button>\n </div>\n {expanded && (\n <div className=\"agent-card-expanded\">\n <div className=\"agent-card-status-actions\">\n <span className=\"muted text-sm\">Set status:</span>\n <Button\n variant={agent.status === 'idle' ? 'primary' : 'ghost'}\n size=\"sm\"\n onClick={() => onSetStatus('idle')}\n >\n Idle\n </Button>\n <Button\n variant={agent.status === 'working' ? 'primary' : 'ghost'}\n size=\"sm\"\n onClick={() => onSetStatus('working')}\n >\n Working\n </Button>\n <Button\n variant={agent.status === 'error' ? 'primary' : 'ghost'}\n size=\"sm\"\n onClick={() => onSetStatus('error')}\n >\n Error\n </Button>\n </div>\n <div className=\"agent-card-meta\">\n <Folder size={11} />\n <code className=\"mono agent-card-path\">{agent.path}</code>\n </div>\n </div>\n )}\n </Card>\n );\n}\n","// Glyphs block vocabulary — renders MDX blocks from plan.mdx\n\nimport { useMemo, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport {\n AlertTriangle,\n Check,\n CheckCircle2,\n ChevronDown,\n Diamond,\n FileCode2,\n Info,\n Minus,\n StickyNote,\n XCircle,\n} from 'lucide-react';\nimport { cn } from '../../lib/utils';\n\nexport interface RichTextProps {\n id: string;\n children: string;\n}\n\nexport function RichText({ id, children }: RichTextProps) {\n return (\n <div\n id={id}\n data-block-id={id}\n className={cn('glyph-richtext')}\n style={proseStyle}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{children}</ReactMarkdown>\n </div>\n );\n}\n\nexport interface CalloutProps {\n id: string;\n tone?: 'info' | 'warn' | 'success' | 'danger';\n children: string;\n}\n\nconst CALLOUT_TONE: Record<NonNullable<CalloutProps['tone']>, {\n bg: string; border: string; fg: string; icon: typeof Info; label: string;\n}> = {\n info: { bg: 'var(--info-soft, rgba(96, 165, 250, 0.12))', border: 'var(--info)', fg: 'var(--info)', icon: Info, label: 'Note' },\n warn: { bg: 'var(--warning-soft, rgba(251, 191, 36, 0.15))', border: 'var(--warning)', fg: 'var(--warning)', icon: AlertTriangle, label: 'Warning' },\n success: { bg: 'var(--success-soft, rgba(52, 211, 153, 0.15))', border: 'var(--success)', fg: 'var(--success)', icon: CheckCircle2, label: 'Success' },\n danger: { bg: 'var(--error-soft, rgba(248, 113, 113, 0.12))', border: 'var(--error)', fg: 'var(--error)', icon: XCircle, label: 'Danger' },\n};\n\nexport function Callout({ id, tone = 'info', children }: CalloutProps) {\n const t = CALLOUT_TONE[tone];\n const Icon = t.icon;\n return (\n <div\n id={id}\n data-block-id={id}\n className={cn('glyph-callout', `glyph-callout-${tone}`)}\n style={{\n display: 'flex',\n gap: 12,\n padding: '12px 16px',\n margin: '12px 0',\n borderLeft: `3px solid ${t.border}`,\n background: t.bg,\n borderRadius: 8,\n color: 'var(--text)',\n }}\n role={tone === 'danger' || tone === 'warn' ? 'alert' : undefined}\n >\n <div style={{ flexShrink: 0, color: t.fg, paddingTop: 2 }}>\n <Icon size={18} />\n </div>\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontWeight: 600, fontSize: 13, color: t.fg, marginBottom: 4 }}>\n {t.label}\n </div>\n <div className=\"glyph-richtext\" style={{ ...proseStyle, fontSize: 14 }}>\n <ReactMarkdown remarkPlugins={[remarkGfm]}>{children}</ReactMarkdown>\n </div>\n </div>\n </div>\n );\n}\n\nexport interface ChecklistItem {\n id: string;\n label: string;\n checked: boolean;\n}\nexport interface ChecklistProps {\n id: string;\n items: ChecklistItem[];\n}\n\nexport function Checklist({ id, items }: ChecklistProps) {\n return (\n <ul\n id={id}\n data-block-id={id}\n className=\"glyph-checklist\"\n style={{\n listStyle: 'none',\n padding: 0,\n margin: '12px 0',\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n }}\n >\n {items.map((item) => (\n <li\n key={item.id}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 10,\n padding: '6px 10px',\n borderRadius: 6,\n background: 'var(--bg-elev)',\n border: '1px solid var(--border)',\n fontSize: 14,\n }}\n >\n <span\n aria-hidden\n style={{\n flexShrink: 0,\n marginTop: 1,\n width: 16,\n height: 16,\n borderRadius: 4,\n border: `1.5px solid ${item.checked ? 'var(--success)' : 'var(--border-strong)'}`,\n background: item.checked ? 'var(--success)' : 'transparent',\n color: 'var(--bg)',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n {item.checked ? <Check size={12} strokeWidth={3} /> : null}\n </span>\n <span style={{\n color: item.checked ? 'var(--text-dim)' : 'var(--text)',\n textDecoration: item.checked ? 'line-through' : 'none',\n wordBreak: 'break-word',\n }}>\n {item.label}\n </span>\n </li>\n ))}\n </ul>\n );\n}\n\nexport interface TableProps {\n id: string;\n columns: string[];\n rows: string[][];\n}\n\nexport function Table({ id, columns, rows }: TableProps) {\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-table-wrap\"\n style={{\n margin: '12px 0',\n border: '1px solid var(--border)',\n borderRadius: 8,\n overflow: 'auto',\n background: 'var(--bg-elev)',\n }}\n >\n <table\n style={{\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: 13,\n }}\n >\n <thead>\n <tr>\n {columns.map((c, i) => (\n <th\n key={i}\n style={{\n textAlign: 'left',\n padding: '8px 12px',\n borderBottom: '1px solid var(--border-strong)',\n background: 'var(--bg)',\n color: 'var(--text-dim)',\n fontWeight: 600,\n fontSize: 12,\n textTransform: 'uppercase',\n letterSpacing: 0.3,\n whiteSpace: 'nowrap',\n }}\n >\n {c}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, ri) => (\n <tr key={ri} style={{ borderTop: ri === 0 ? 'none' : '1px solid var(--border)' }}>\n {row.map((cell, ci) => (\n <td\n key={ci}\n style={{\n padding: '8px 12px',\n color: 'var(--text)',\n verticalAlign: 'top',\n wordBreak: 'break-word',\n }}\n >\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport interface CodeTab {\n id: string;\n label: string;\n language: string;\n code: string;\n caption?: string;\n}\nexport interface CodeTabsProps {\n id: string;\n tabs: CodeTab[];\n}\n\nexport function CodeTabs({ id, tabs }: CodeTabsProps) {\n const [activeId, setActiveId] = useState<string>(tabs[0]?.id ?? '');\n const active = useMemo(\n () => tabs.find((t) => t.id === activeId) ?? tabs[0],\n [tabs, activeId],\n );\n\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-codetabs\"\n style={{\n margin: '12px 0',\n border: '1px solid var(--border)',\n borderRadius: 8,\n overflow: 'hidden',\n background: 'var(--bg-elev)',\n }}\n >\n <div\n role=\"tablist\"\n style={{\n display: 'flex',\n gap: 2,\n padding: 4,\n background: 'var(--bg)',\n borderBottom: '1px solid var(--border)',\n overflowX: 'auto',\n }}\n >\n {tabs.map((t) => {\n const selected = t.id === active?.id;\n return (\n <button\n key={t.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n onClick={() => setActiveId(t.id)}\n style={{\n padding: '6px 12px',\n fontSize: 12,\n fontFamily: 'var(--font-mono)',\n borderRadius: 6,\n border: 'none',\n cursor: 'pointer',\n background: selected ? 'var(--bg-elev)' : 'transparent',\n color: selected ? 'var(--text-strong)' : 'var(--text-dim)',\n boxShadow: selected ? '0 0 0 1px var(--border)' : 'none',\n whiteSpace: 'nowrap',\n }}\n >\n <span>{t.label}</span>\n {t.language && (\n <span style={{ marginLeft: 6, color: 'var(--text-dim)', fontSize: 11 }}>\n {t.language}\n </span>\n )}\n </button>\n );\n })}\n </div>\n {active && (\n <>\n <pre\n style={{\n margin: 0,\n padding: 14,\n overflowX: 'auto',\n fontFamily: 'var(--font-mono)',\n fontSize: 12.5,\n lineHeight: 1.55,\n color: 'var(--text)',\n background: 'var(--bg-elev)',\n }}\n >\n <code>{active.code}</code>\n </pre>\n {active.caption && (\n <div\n style={{\n padding: '8px 14px',\n borderTop: '1px solid var(--border)',\n fontSize: 12,\n color: 'var(--text-dim)',\n background: 'var(--bg)',\n }}\n >\n {active.caption}\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport interface DecisionOption {\n id: string;\n label: string;\n detail: string;\n recommended?: boolean;\n}\nexport interface DecisionProps {\n id: string;\n title?: string;\n question?: string;\n options: DecisionOption[];\n}\n\nexport function Decision({ id, title, question, options }: DecisionProps) {\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-decision\"\n style={{\n margin: '16px 0',\n padding: 16,\n border: '1px solid var(--border)',\n borderRadius: 10,\n background: 'var(--bg-elev)',\n }}\n >\n {title && (\n <h3 style={{ margin: 0, marginBottom: 4, fontSize: 15, fontWeight: 600, color: 'var(--text-strong)' }}>\n {title}\n </h3>\n )}\n {question && (\n <p style={{ margin: 0, marginBottom: 12, fontSize: 13, color: 'var(--text-dim)' }}>\n {question}\n </p>\n )}\n <div style={{ display: 'grid', gap: 10, gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))' }}>\n {options.map((opt) => {\n const isRec = !!opt.recommended;\n return (\n <div\n key={opt.id}\n style={{\n position: 'relative',\n padding: 12,\n borderRadius: 8,\n border: isRec ? '2px solid var(--success)' : '1px solid var(--border)',\n background: isRec ? 'var(--success-soft)' : 'var(--bg)',\n }}\n >\n {isRec && (\n <span\n style={{\n position: 'absolute',\n top: -10,\n right: 10,\n padding: '2px 8px',\n fontSize: 11,\n fontWeight: 600,\n color: 'var(--bg)',\n background: 'var(--success)',\n borderRadius: 999,\n }}\n >\n Recommended\n </span>\n )}\n <div style={{ fontWeight: 600, fontSize: 14, color: 'var(--text-strong)', marginBottom: 4 }}>\n {opt.label}\n </div>\n <div style={{ fontSize: 13, color: 'var(--text)' }}>\n {opt.detail}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nexport interface OpenQuestion {\n id: string;\n label: string;\n kind: 'choice' | 'text' | 'multi';\n options?: string[];\n}\nexport interface OpenQuestionsProps {\n id: string;\n questions: OpenQuestion[];\n}\n\nexport function OpenQuestions({ id, questions }: OpenQuestionsProps) {\n const [answers, setAnswers] = useState<Record<string, string | string[]>>({});\n\n function setAnswer(qid: string, value: string | string[]) {\n setAnswers((prev) => ({ ...prev, [qid]: value }));\n }\n\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-openquestions\"\n style={{\n margin: '16px 0',\n padding: 16,\n border: '1px solid var(--border)',\n borderRadius: 10,\n background: 'var(--bg-elev)',\n display: 'flex',\n flexDirection: 'column',\n gap: 14,\n }}\n >\n <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-strong)' }}>\n Open questions\n </div>\n {questions.map((q) => (\n <div key={q.id} style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n <label\n htmlFor={`oq-${q.id}`}\n style={{ fontSize: 13, color: 'var(--text)', fontWeight: 500 }}\n >\n {q.label}\n </label>\n {q.kind === 'choice' && (\n <select\n id={`oq-${q.id}`}\n value={(answers[q.id] as string) ?? ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n style={inputStyle}\n >\n <option value=\"\">— select —</option>\n {(q.options ?? []).map((opt) => (\n <option key={opt} value={opt}>{opt}</option>\n ))}\n </select>\n )}\n {q.kind === 'text' && (\n <input\n id={`oq-${q.id}`}\n type=\"text\"\n value={(answers[q.id] as string) ?? ''}\n onChange={(e) => setAnswer(q.id, e.target.value)}\n style={inputStyle}\n />\n )}\n {q.kind === 'multi' && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>\n {(q.options ?? []).map((opt) => {\n const current = (answers[q.id] as string[]) ?? [];\n const checked = current.includes(opt);\n return (\n <label\n key={opt}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n fontSize: 13,\n color: 'var(--text)',\n cursor: 'pointer',\n }}\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={() => {\n const next = checked\n ? current.filter((o) => o !== opt)\n : [...current, opt];\n setAnswer(q.id, next);\n }}\n />\n <span>{opt}</span>\n </label>\n );\n })}\n </div>\n )}\n </div>\n ))}\n </div>\n );\n}\n\nconst inputStyle: React.CSSProperties = {\n padding: '6px 10px',\n fontSize: 13,\n borderRadius: 6,\n border: '1px solid var(--border-strong)',\n background: 'var(--bg)',\n color: 'var(--text)',\n fontFamily: 'inherit',\n};\n\nexport interface FileTreeEntry {\n path: string;\n change: 'added' | 'modified' | 'removed' | 'renamed';\n note?: string;\n}\nexport interface FileTreeProps {\n id: string;\n title?: string;\n entries: FileTreeEntry[];\n}\n\nconst FILE_CHANGE: Record<FileTreeEntry['change'], { bg: string; fg: string; label: string }> = {\n added: { bg: 'var(--success-soft)', fg: 'var(--success)', label: 'A' },\n modified: { bg: 'var(--info-soft, rgba(96, 165, 250, 0.12))', fg: 'var(--info)', label: 'M' },\n removed: { bg: 'var(--error-soft)', fg: 'var(--error)', label: 'D' },\n renamed: { bg: 'rgba(139, 92, 246, 0.15)', fg: 'var(--accent)', label: 'R' },\n};\n\nexport function FileTree({ id, title, entries }: FileTreeProps) {\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-filetree\"\n style={{\n margin: '12px 0',\n padding: title ? 14 : 8,\n border: '1px solid var(--border)',\n borderRadius: 8,\n background: 'var(--bg-elev)',\n }}\n >\n {title && (\n <div\n style={{\n fontSize: 12,\n fontWeight: 600,\n color: 'var(--text-dim)',\n textTransform: 'uppercase',\n letterSpacing: 0.4,\n marginBottom: 8,\n }}\n >\n {title}\n </div>\n )}\n <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 2 }}>\n {entries.map((e) => {\n const t = FILE_CHANGE[e.change];\n return (\n <li\n key={e.path}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '5px 8px',\n borderRadius: 5,\n fontSize: 13,\n }}\n >\n <span\n aria-label={e.change}\n title={e.change}\n style={{\n flexShrink: 0,\n width: 22,\n height: 18,\n borderRadius: 4,\n background: t.bg,\n color: t.fg,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 10,\n fontWeight: 700,\n fontFamily: 'var(--font-mono)',\n }}\n >\n {t.label}\n </span>\n <span\n style={{\n fontFamily: 'var(--font-mono)',\n color: 'var(--text)',\n wordBreak: 'break-all',\n flex: 1,\n }}\n >\n {e.path}\n </span>\n {e.note && (\n <span style={{ fontSize: 12, color: 'var(--text-dim)' }}>\n {e.note}\n </span>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\nexport interface DiffProps {\n id: string;\n filename?: string;\n language?: string;\n mode?: 'split' | 'unified';\n before: string;\n after: string;\n}\n\nexport function Diff({ id, filename, language, mode = 'unified', before, after }: DiffProps) {\n const beforeLines = before.split('\\n');\n const afterLines = after.split('\\n');\n\n const header = (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '6px 12px',\n background: 'var(--bg)',\n borderBottom: '1px solid var(--border)',\n fontSize: 12,\n color: 'var(--text-dim)',\n fontFamily: 'var(--font-mono)',\n }}\n >\n <FileCode2 size={14} />\n <span style={{ color: 'var(--text)' }}>{filename ?? 'diff'}</span>\n {language && <span>· {language}</span>}\n <span style={{ marginLeft: 'auto', textTransform: 'uppercase', letterSpacing: 0.3 }}>\n {mode}\n </span>\n </div>\n );\n\n const codeStyle: React.CSSProperties = {\n margin: 0,\n padding: 0,\n fontFamily: 'var(--font-mono)',\n fontSize: 12.5,\n lineHeight: 1.55,\n color: 'var(--text)',\n background: 'var(--bg-elev)',\n };\n\n const lineRow = (sign: string, content: string, kind: 'del' | 'add' | 'ctx') => {\n const colors: Record<typeof kind, string> = {\n del: 'var(--error-soft)',\n add: 'var(--success-soft)',\n ctx: 'transparent',\n };\n const signColor: Record<typeof kind, string> = {\n del: 'var(--error)',\n add: 'var(--success)',\n ctx: 'var(--text-dim)',\n };\n return (\n <div\n style={{\n display: 'flex',\n padding: '0 12px',\n background: colors[kind],\n }}\n >\n <span style={{ width: 18, color: signColor[kind], userSelect: 'none', flexShrink: 0 }}>{sign}</span>\n <span style={{ whiteSpace: 'pre', flex: 1, overflowX: 'auto' }}>{content || ' '}</span>\n </div>\n );\n };\n\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-diff\"\n style={{\n margin: '12px 0',\n border: '1px solid var(--border)',\n borderRadius: 8,\n overflow: 'hidden',\n background: 'var(--bg-elev)',\n }}\n >\n {header}\n {mode === 'unified' ? (\n <pre style={codeStyle}>\n {beforeLines.map((l, i) => (\n <div key={`b${i}`}>{lineRow('-', l, 'del')}</div>\n ))}\n {afterLines.map((l, i) => (\n <div key={`a${i}`}>{lineRow('+', l, 'add')}</div>\n ))}\n </pre>\n ) : (\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>\n <pre style={{ ...codeStyle, borderRight: '1px solid var(--border)' }}>\n {beforeLines.map((l, i) => (\n <div key={i}>{lineRow('-', l, 'del')}</div>\n ))}\n </pre>\n <pre style={codeStyle}>\n {afterLines.map((l, i) => (\n <div key={i}>{lineRow('+', l, 'add')}</div>\n ))}\n </pre>\n </div>\n )}\n </div>\n );\n}\n\nexport interface StatProps {\n id: string;\n label: string;\n value: string | number;\n trend?: 'up' | 'down' | 'flat';\n hint?: string;\n}\n\nconst TREND_STYLE: Record<NonNullable<StatProps['trend']>, { fg: string; Icon: typeof Minus; label: string }> = {\n up: { fg: 'var(--success)', Icon: ChevronDown, label: 'trending up' },\n down: { fg: 'var(--error)', Icon: ChevronDown, label: 'trending down' },\n flat: { fg: 'var(--text-dim)', Icon: Minus, label: 'flat' },\n};\n\nexport function Stat({ id, label, value, trend, hint }: StatProps) {\n const t = trend ? TREND_STYLE[trend] : null;\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-stat\"\n style={{\n padding: 14,\n border: '1px solid var(--border)',\n borderRadius: 10,\n background: 'var(--bg-elev)',\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n minWidth: 140,\n }}\n >\n <div style={{ fontSize: 12, color: 'var(--text-dim)', textTransform: 'uppercase', letterSpacing: 0.4 }}>\n {label}\n </div>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>\n <span style={{ fontSize: 24, fontWeight: 700, color: 'var(--text-strong)' }}>\n {value}\n </span>\n {t && (\n <span\n aria-label={t.label}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n color: t.fg,\n transform: t.Icon === ChevronDown && trend === 'up' ? 'rotate(180deg)' : undefined,\n }}\n >\n <t.Icon size={14} />\n </span>\n )}\n </div>\n {hint && (\n <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>\n {hint}\n </div>\n )}\n </div>\n );\n}\n\nexport interface WorkflowStep {\n id: string;\n label: string;\n type: 'task' | 'decision' | 'note';\n}\nexport interface WorkflowConnection {\n from: string;\n to: string;\n label?: string;\n}\nexport interface WorkflowProps {\n id: string;\n steps: WorkflowStep[];\n connections?: WorkflowConnection[];\n}\n\nconst STEP_COLORS: Record<WorkflowStep['type'], { stroke: string; fill: string; fg: string }> = {\n task: { stroke: 'var(--info)', fill: 'var(--bg-elev)', fg: 'var(--text)' },\n decision: { stroke: 'var(--warning)', fill: 'var(--bg-elev)', fg: 'var(--text)' },\n note: { stroke: 'var(--border-strong)', fill: 'var(--bg)', fg: 'var(--text-dim)' },\n};\n\nconst BOX_W = 160;\nconst BOX_H = 56;\nconst GAP_X = 60;\nconst GAP_Y = 80;\n\nexport function Workflow({ id, steps, connections = [] }: WorkflowProps) {\n if (steps.length === 0) {\n return (\n <div id={id} data-block-id={id} className=\"glyph-workflow\">\n <Empty id={id} />\n </div>\n );\n }\n\n const byId = new Map(steps.map((s) => [s.id, s] as const));\n const layout = layoutSteps(steps);\n\n const cols = Math.max(...layout.map((p) => p.col)) + 1;\n const rows = Math.max(...layout.map((p) => p.row)) + 1;\n const width = cols * (BOX_W + GAP_X) + GAP_X;\n const height = rows * (BOX_H + GAP_Y) + GAP_Y;\n\n function nodeCenter(stepId: string): { x: number; y: number } | null {\n const step = byId.get(stepId);\n if (!step) return null;\n const pos = layout.find((p) => p.id === stepId);\n if (!pos) return null;\n return {\n x: GAP_X + pos.col * (BOX_W + GAP_X) + BOX_W / 2,\n y: GAP_Y + pos.row * (BOX_H + GAP_Y) + BOX_H / 2,\n };\n }\n\n return (\n <div\n id={id}\n data-block-id={id}\n className=\"glyph-workflow\"\n style={{\n margin: '12px 0',\n padding: 12,\n border: '1px solid var(--border)',\n borderRadius: 10,\n background: 'var(--bg-elev)',\n overflow: 'auto',\n }}\n >\n <svg\n role=\"img\"\n aria-label=\"Workflow diagram\"\n width={width}\n height={height}\n style={{ display: 'block', maxWidth: '100%' }}\n >\n <defs>\n <marker\n id={`arrow-${id}`}\n viewBox=\"0 0 10 10\"\n refX=\"9\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n >\n <path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--text-dim)\" />\n </marker>\n </defs>\n\n {connections.map((c, i) => {\n const from = nodeCenter(c.from);\n const to = nodeCenter(c.to);\n if (!from || !to) return null;\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const fromX = dx >= 0 ? from.x + BOX_W / 2 : from.x - BOX_W / 2;\n const toX = dx >= 0 ? to.x - BOX_W / 2 : to.x + BOX_W / 2;\n const fromY = dy >= 0 ? from.y + BOX_H / 2 : from.y - BOX_H / 2;\n const toY = dy >= 0 ? to.y - BOX_H / 2 : to.y + BOX_H / 2;\n const midX = (fromX + toX) / 2;\n const midY = (fromY + toY) / 2;\n return (\n <g key={i}>\n <line\n x1={fromX}\n y1={fromY}\n x2={toX}\n y2={toY}\n stroke=\"var(--text-dim)\"\n strokeWidth={1.5}\n markerEnd={`url(#arrow-${id})`}\n />\n {c.label && (\n <text\n x={midX}\n y={midY - 4}\n fontSize={10}\n fill=\"var(--text-dim)\"\n textAnchor=\"middle\"\n fontFamily=\"var(--font-mono)\"\n >\n {c.label}\n </text>\n )}\n </g>\n );\n })}\n\n {steps.map((s) => {\n const pos = layout.find((p) => p.id === s.id);\n if (!pos) return null;\n const x = GAP_X + pos.col * (BOX_W + GAP_X);\n const y = GAP_Y + pos.row * (BOX_H + GAP_Y);\n const c = STEP_COLORS[s.type];\n if (s.type === 'decision') {\n const cx = x + BOX_W / 2;\n const cy = y + BOX_H / 2;\n const points = [\n [cx, y],\n [x + BOX_W, cy],\n [cx, y + BOX_H],\n [x, cy],\n ]\n .map((p) => p.join(','))\n .join(' ');\n return (\n <g key={s.id}>\n <polygon\n points={points}\n fill={c.fill}\n stroke={c.stroke}\n strokeWidth={2}\n />\n <foreignObject x={x + 8} y={cy - 14} width={BOX_W - 16} height={28}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n fontSize: 12,\n color: c.fg,\n textAlign: 'center',\n lineHeight: 1.2,\n fontStyle: 'italic',\n height: '100%',\n }}\n >\n <Diamond size={11} />\n {s.label}\n </div>\n </foreignObject>\n </g>\n );\n }\n const isNote = s.type === 'note';\n return (\n <g key={s.id}>\n <rect\n x={x}\n y={y}\n width={BOX_W}\n height={BOX_H}\n rx={8}\n fill={c.fill}\n stroke={c.stroke}\n strokeWidth={isNote ? 1 : 2}\n strokeDasharray={isNote ? '4 3' : undefined}\n />\n <foreignObject x={x + 6} y={y + 6} width={BOX_W - 12} height={BOX_H - 12}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 6,\n fontSize: 12,\n color: c.fg,\n textAlign: 'center',\n lineHeight: 1.25,\n fontStyle: isNote ? 'italic' : 'normal',\n height: '100%',\n }}\n >\n {isNote && <StickyNote size={11} />}\n {s.label}\n </div>\n </foreignObject>\n </g>\n );\n })}\n </svg>\n </div>\n );\n}\n\nfunction Empty({ id }: { id: string }) {\n return (\n <div\n id={id}\n style={{\n padding: 20,\n textAlign: 'center',\n color: 'var(--text-dim)',\n fontSize: 13,\n }}\n >\n No workflow steps.\n </div>\n );\n}\n\ntype LayoutPos = { id: string; col: number; row: number };\n\nfunction layoutSteps(steps: WorkflowStep[]): LayoutPos[] {\n if (steps.length === 0) return [];\n return steps.map((s, i) => ({ id: s.id, col: i, row: 0 }));\n}\n\nconst proseStyle: React.CSSProperties = {\n fontSize: 14,\n lineHeight: 1.6,\n color: 'var(--text)',\n};\n\n// ─── Mockup ─────────────────────────────────────────────────────────────────\n\nexport interface MockupProps {\n id: string;\n title?: string;\n x?: number;\n y?: number;\n w?: number;\n h?: number;\n html: string;\n}\n\nexport function Mockup({ id, title, x, y, w, h, html }: MockupProps) {\n return (\n <figure\n id={id}\n data-block-id={id}\n className=\"glyph-mockup\"\n style={{ width: w, minHeight: h }}\n >\n {title && <figcaption className=\"glyph-mockup-title\">{title}</figcaption>}\n <div className=\"glyph-mockup-frame\">\n <div className=\"glyph-mockup-chrome\">\n <span />\n <span />\n <span />\n </div>\n <div\n className=\"glyph-mockup-body\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n </div>\n </figure>\n );\n}\n","/**\n * GlyphRenderer.tsx — Renders a compiled glyph (from /api/artifacts/:slug/render)\n * with comment pin overlay + right-click to add comments.\n *\n * Uses the agent-native.com \"Visual Plans\" workflow (v3.22.0):\n * - Compiled glyph structure: { frontmatter, blocks: [{id, type, data, childrenMarkdown?}], errors }\n * - Each block renders via the components from ./components\n * - Comment pins from comments.json overlay on top, positioned absolutely\n * - Right-click anywhere → context menu with \"Add comment\" option\n * - Blocks are grouped into sections by id (overview, implementation, …)\n *\n * Layout (v3.22.0 — agent-native /visual-plan inspired, dark dashboard styling):\n * .glyph-canvas ← outer, dotted background\n * .glyph-toolbar-floating ← sticky top-right pill (Send to agent, share, …)\n * .glyph-canvas-content ← centered blocks area\n * .glyph-section ← section card with optional heading\n * .glyph-section-heading ← \"Overview\" / \"Implementation plan\" / …\n * .glyph-section-blocks ← block stack inside the section\n *\n * v3.22.0 — section grouping + floating toolbar rewrite (kept all prior pin/ctx-menu logic).\n */\n\nimport React, { useEffect, useMemo, useState, useRef } from 'react';\nimport {\n MapPin,\n MessageSquare,\n Send,\n Share2,\n Undo2,\n Redo2,\n MoreHorizontal,\n Maximize2,\n X,\n} from 'lucide-react';\nimport { api } from '../../lib/api';\nimport { useToast } from '../../components/Toast';\nimport {\n RichText,\n Callout,\n Checklist,\n Table,\n CodeTabs,\n Decision,\n OpenQuestions,\n FileTree,\n Diff,\n Stat,\n Workflow,\n Mockup,\n} from './components';\n\n// ---------------------------------------------------------------------------\n// BlockErrorBoundary — v4.4.8\n//\n// A single broken block (e.g. a FileTree whose `data.entries` ended up\n// not being an array because the parser silently produced a phantom\n// bareword entry) used to throw inside React, which propagated up and\n// blanked the whole canvas. The boundary catches throws per-block and\n// renders an inline error card instead. The boundary also exposes its\n// errors via a callback so we can surface them in the top-of-page\n// \"render errors\" banner.\n// ---------------------------------------------------------------------------\n\ninterface BlockErrorBoundaryProps {\n blockId: string;\n blockType: string;\n children: React.ReactNode;\n onError: (blockId: string, blockType: string, err: Error, info: React.ErrorInfo) => void;\n}\n\ninterface BlockErrorBoundaryState {\n err: Error | null;\n}\n\nclass BlockErrorBoundary extends React.Component<BlockErrorBoundaryProps, BlockErrorBoundaryState> {\n state: BlockErrorBoundaryState = { err: null };\n static getDerivedStateFromError(err: Error): BlockErrorBoundaryState {\n return { err };\n }\n componentDidCatch(err: Error, info: React.ErrorInfo): void {\n try {\n this.props.onError(this.props.blockId, this.props.blockType, err, info);\n } catch {\n /* ignore — the boundary itself must not throw */\n }\n }\n render(): React.ReactNode {\n if (this.state.err) {\n return (\n <div\n className=\"glyph-block-error\"\n role=\"alert\"\n style={{\n border: '1px solid var(--error, #f85149)',\n background: 'rgba(248, 81, 73, 0.06)',\n borderRadius: 8,\n padding: '12px 14px',\n margin: '12px 0',\n color: 'var(--text)',\n fontFamily: 'var(--font-mono, ui-monospace, monospace)',\n fontSize: 12,\n lineHeight: 1.55,\n }}\n >\n <strong style={{ color: 'var(--error, #f85149)', fontFamily: 'var(--font-sans, system-ui, sans-serif)', display: 'block', marginBottom: 4 }}>\n {this.props.blockType} block crashed\n </strong>\n <div style={{ color: 'var(--text-muted)', marginBottom: 6 }}>\n block id: <code>{this.props.blockId}</code>\n </div>\n <pre style={{ margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-word', color: 'var(--text)' }}>\n {this.state.err.message}\n </pre>\n </div>\n );\n }\n return this.props.children;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Block validation — v4.4.8\n//\n// Before handing block data to the component switch, verify that the\n// shape matches the prop contract. Returns `{ ok: true }` when the\n// block can be rendered, or `{ ok: false, error }` when a field is\n// missing or wrong type. The renderer uses the error to skip the\n// component and surface an inline message instead of throwing.\n// ---------------------------------------------------------------------------\n\nfunction validateBlock(b: Block): { ok: true } | { ok: false; error: string } {\n const data = (b.data ?? {}) as Record<string, unknown>;\n switch (b.type) {\n case 'RichText':\n return { ok: true };\n case 'Callout':\n return { ok: true };\n case 'Checklist':\n if (!Array.isArray(data.items)) return { ok: false, error: 'Checklist requires data.items to be an array' };\n return { ok: true };\n case 'Table':\n if (!Array.isArray(data.columns)) return { ok: false, error: 'Table requires data.columns to be an array' };\n if (!Array.isArray(data.rows)) return { ok: false, error: 'Table requires data.rows to be an array' };\n if (data.rows.length > 0 && !Array.isArray(data.rows[0])) return { ok: false, error: 'Table.data.rows[0] must be an array (cell array)' };\n return { ok: true };\n case 'CodeTabs':\n if (!Array.isArray(data.tabs)) return { ok: false, error: 'CodeTabs requires data.tabs to be an array' };\n return { ok: true };\n case 'Decision':\n if (!Array.isArray(data.options)) return { ok: false, error: 'Decision requires data.options to be an array' };\n return { ok: true };\n case 'OpenQuestions':\n if (!Array.isArray(data.questions)) return { ok: false, error: 'OpenQuestions requires data.questions to be an array' };\n return { ok: true };\n case 'FileTree':\n if (!Array.isArray(data.entries)) return { ok: false, error: 'FileTree requires data.entries to be an array' };\n // v4.4.8 — also catch the phantom bareword entry the parser used\n // to emit (the v3-to-v4-consolidation glyph crash). An entry that\n // is not an object means the parser miscounted braces.\n for (const e of data.entries) {\n if (e === null || typeof e !== 'object' || Array.isArray(e)) {\n return { ok: false, error: `FileTree contains a malformed entry: ${JSON.stringify(e)}` };\n }\n }\n return { ok: true };\n case 'Diff':\n if (typeof data.before !== 'string') return { ok: false, error: 'Diff requires data.before to be a string' };\n if (typeof data.after !== 'string') return { ok: false, error: 'Diff requires data.after to be a string' };\n return { ok: true };\n case 'Stat':\n if (data.label === undefined || data.label === null) return { ok: false, error: 'Stat requires data.label' };\n if (data.value === undefined || data.value === null) return { ok: false, error: 'Stat requires data.value' };\n return { ok: true };\n case 'Workflow':\n if (!Array.isArray(data.steps)) return { ok: false, error: 'Workflow requires data.steps to be an array' };\n return { ok: true };\n case 'Mockup':\n if (typeof data.html !== 'string') return { ok: false, error: 'Mockup requires data.html to be a string' };\n return { ok: true };\n case 'Diagram':\n if (typeof data.dataHtml !== 'string') return { ok: false, error: 'Diagram requires data.dataHtml to be a string' };\n return { ok: true };\n default:\n return { ok: false, error: `Unknown block type: ${(b as { type: string }).type}` };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Types — match the server compiler output\n// ---------------------------------------------------------------------------\n\ntype Block =\n | { id: string; type: 'RichText'; data: Record<string, unknown>; childrenMarkdown?: string }\n | { id: string; type: 'Callout'; data: { tone?: 'info' | 'warn' | 'success' | 'danger' }; childrenMarkdown?: string }\n | { id: string; type: 'Checklist'; data: { items: { id: string; label: string; checked: boolean }[] } }\n | { id: string; type: 'Table'; data: { columns: string[]; rows: string[][] } }\n | { id: string; type: 'CodeTabs'; data: { tabs: { id: string; label: string; language: string; code: string; caption?: string }[] } }\n | { id: string; type: 'Decision'; data: { title?: string; question?: string; options: { id: string; label: string; detail: string; recommended?: boolean }[] } }\n | { id: string; type: 'OpenQuestions'; data: { questions: { id: string; label: string; kind: 'choice' | 'text' | 'multi'; options?: string[] }[] } }\n | { id: string; type: 'FileTree'; data: { title?: string; entries: { path: string; change: 'added' | 'modified' | 'removed' | 'renamed'; note?: string }[] } }\n | { id: string; type: 'Diff'; data: { filename?: string; language?: string; mode?: 'split' | 'unified'; before: string; after: string } }\n | { id: string; type: 'Stat'; data: { label: string; value: string | number; trend?: 'up' | 'down' | 'flat'; hint?: string } }\n | { id: string; type: 'Workflow'; data: { steps: { id: string; label: string; type: 'task' | 'decision' | 'note' }[]; connections?: { from: string; to: string; label?: string }[] } }\n | { id: string; type: 'Mockup'; data: { title?: string; x?: number; y?: number; w?: number; h?: number; html: string } }\n | { id: string; type: 'Diagram'; data: { title?: string; dataHtml: string; dataCss?: string } };\n\ninterface CompiledGlyph {\n slug: string;\n frontmatter: Record<string, unknown>;\n blocks: Block[];\n errors: Array<{ line?: number; message: string }>;\n compiledAt: string;\n}\n\ninterface CommentPin {\n id: string;\n elementId?: string | null;\n x: number;\n y: number;\n text: string;\n author?: string;\n created?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Section grouping — block ids → section headings\n// ---------------------------------------------------------------------------\n\nconst SECTION_MAP: Record<string, string> = {\n overview: 'Overview',\n implementation: 'Implementation plan',\n 'implementation-plan': 'Implementation plan',\n questions: 'Open questions',\n 'open-questions': 'Open questions',\n 'open-questions-for-you': 'Open questions',\n comments: 'Comments',\n handoff: 'Handoff',\n};\n\ninterface Section {\n heading: string | null;\n blocks: Block[];\n}\n\nfunction groupBlocksIntoSections(blocks: Block[]): Section[] {\n const sections: Section[] = [];\n let current: Section = { heading: null, blocks: [] };\n\n for (const b of blocks) {\n const heading = SECTION_MAP[b.id] ?? null;\n if (heading) {\n // Push any unheading prelude into a no-heading section so we don't lose it\n if (current.blocks.length > 0 || current.heading !== null) {\n sections.push(current);\n }\n current = { heading, blocks: [b] };\n } else {\n current.blocks.push(b);\n }\n }\n if (current.blocks.length > 0 || current.heading !== null) {\n sections.push(current);\n }\n return sections;\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\ninterface Props {\n slug: string;\n onClose?: () => void;\n /** Called after a comment is added so the parent can refresh. */\n onCommentAdded?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function GlyphRenderer({ slug, onClose, onCommentAdded }: Props) {\n const toast = useToast();\n const [compiled, setCompiled] = useState<CompiledGlyph | null>(null);\n const [comments, setComments] = useState<CommentPin[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n /** Error caught during the loading phase — shown inline so the user knows why. */\n const [loadError, setLoadError] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [fullscreen, setFullscreen] = useState(false);\n\n // Context-menu state\n const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number; worldX: number; worldY: number } | null>(null);\n const [addingComment, setAddingComment] = useState<{ worldX: number; worldY: number } | null>(null);\n const [commentDraft, setCommentDraft] = useState('');\n\n // Active pin (expanded thread view)\n const [activePin, setActivePin] = useState<string | null>(null);\n\n // v4.4.8 — Per-block render errors caught by BlockErrorBoundary. The\n // boundary calls onError(err) which pushes into this array. We render\n // the array at the top of the canvas in a prominent red banner so the\n // user isn't left staring at a blank screen wondering what happened.\n const [blockErrors, setBlockErrors] = useState<\n Array<{ blockId: string; blockType: string; message: string }>\n >([]);\n const reportBlockError = React.useCallback(\n (blockId: string, blockType: string, err: Error) => {\n setBlockErrors((prev) => {\n // dedupe by blockId so the same block crashing twice doesn't\n // duplicate the entry\n if (prev.some((e) => e.blockId === blockId)) return prev;\n return [...prev, { blockId, blockType, message: err.message || String(err) }];\n });\n },\n [],\n );\n\n const canvasRef = useRef<HTMLDivElement>(null);\n\n // Section grouping — memoized so we don't re-walk the block array on every render\n const sections = useMemo(\n () => (compiled ? groupBlocksIntoSections(compiled.blocks) : []),\n [compiled],\n );\n\n // Load compiled glyph + comments\n useEffect(() => {\n let cancelled = false;\n const TIMEOUT_MS = 5000;\n\n (async () => {\n setLoading(true);\n setError(null);\n try {\n // Race the API calls against a 5-second timeout so the user\n // sees an error rather than a perpetual spinner if the server\n // hangs or the network drops.\n const timeoutPromise = new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Request timed out after 5s')), TIMEOUT_MS)\n );\n\n const [renderData, artifactData] = await Promise.race([\n Promise.all([\n api.get<CompiledGlyph>(`/artifacts/${encodeURIComponent(slug)}/render`),\n api.get<{ comments?: CommentPin[]; commentsJson?: { comments?: CommentPin[] } }>(\n `/artifacts/${encodeURIComponent(slug)}`\n ),\n ]),\n timeoutPromise,\n ]) as [CompiledGlyph, { comments?: CommentPin[]; commentsJson?: { comments?: CommentPin[] } }];\n\n if (cancelled) return;\n setCompiled(renderData);\n const fromFile = (artifactData as any)?.comments ?? [];\n setComments(Array.isArray(fromFile) ? fromFile : []);\n } catch (err) {\n if (!cancelled) {\n const msg = (err as Error).message;\n setError(msg);\n setLoadError(msg);\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [slug]);\n\n // Right-click context menu\n function onContainerContextMenu(e: React.MouseEvent) {\n if (!canvasRef.current) return;\n e.preventDefault();\n const rect = canvasRef.current.getBoundingClientRect();\n setCtxMenu({\n x: e.clientX,\n y: e.clientY,\n worldX: e.clientX - rect.left,\n worldY: e.clientY - rect.top,\n });\n }\n\n async function submitComment() {\n if (!addingComment || !commentDraft.trim()) return;\n try {\n const created = await api.post<{ id?: string }>(\n `/artifacts/${encodeURIComponent(slug)}/comments`,\n {\n x: addingComment.worldX,\n y: addingComment.worldY,\n text: commentDraft.trim(),\n author: 'drb0rk',\n }\n );\n setComments((prev) => [\n ...prev,\n {\n id: created.id ?? `cmt_${Date.now()}`,\n x: addingComment.worldX,\n y: addingComment.worldY,\n text: commentDraft.trim(),\n author: 'drb0rk',\n created: new Date().toISOString(),\n },\n ]);\n setAddingComment(null);\n setCommentDraft('');\n setCtxMenu(null);\n onCommentAdded?.();\n toast.success('Comment added');\n } catch (err) {\n toast.error(`Failed to add comment: ${(err as Error).message}`);\n }\n }\n\n // \"Send to agent\" — collects free-placed comments and any answers to\n // OpenQuestions, writes `feedback.md` on disk, and marks the artifact\n // `status: review` so the agent picks it up.\n async function submitFeedback() {\n if (submitting) return;\n setSubmitting(true);\n try {\n const result = await api.post<{ ok: boolean; commentCount?: number; questionCount?: number }>(\n `/artifacts/${encodeURIComponent(slug)}/submit`,\n { answers: [], submitter: 'drb0rk' },\n );\n if (result?.ok) {\n toast.success('Sent to agent — feedback.md written, status=review');\n onCommentAdded?.();\n } else {\n toast.error('Submit failed: server did not return ok=true');\n }\n } catch (err) {\n toast.error(`Submit failed: ${(err as Error).message}`);\n } finally {\n setSubmitting(false);\n }\n }\n\n function toggleFullscreen() {\n setFullscreen((v) => !v);\n }\n\n // Render a single block — wrapped in a BlockErrorBoundary so a single\n// broken block (e.g. wrong data shape from a parser bug) shows an inline\n// error card instead of blanking the whole canvas.\n const renderBlock = (b: Block) => {\n const id = b.id;\n const data = (b.data ?? {}) as Record<string, unknown>;\n // Validate data shape BEFORE handing to the component switch. A\n // validation failure shows an inline error card immediately, no\n // need for the boundary to catch it.\n const validation = validateBlock(b);\n if (!validation.ok) {\n return (\n <div\n key={id}\n id={id}\n className=\"glyph-block-error\"\n role=\"alert\"\n style={{\n border: '1px solid var(--error, #f85149)',\n background: 'rgba(248, 81, 73, 0.06)',\n borderRadius: 8,\n padding: '12px 14px',\n margin: '12px 0',\n color: 'var(--text)',\n fontFamily: 'var(--font-mono, ui-monospace, monospace)',\n fontSize: 12,\n lineHeight: 1.55,\n }}\n >\n <strong style={{ color: 'var(--error, #f85149)', fontFamily: 'var(--font-sans, system-ui, sans-serif)', display: 'block', marginBottom: 4 }}>\n {b.type} block invalid\n </strong>\n <div style={{ color: 'var(--text-muted)', marginBottom: 6 }}>\n block id: <code>{id}</code>\n </div>\n <pre style={{ margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>{validation.error}</pre>\n </div>\n );\n }\n // Wrap the actual render in an error boundary so even runtime\n // errors (bad component props, undefined data, etc.) don't crash\n // the whole canvas.\n return (\n <BlockErrorBoundary key={id} blockId={id} blockType={b.type} onError={reportBlockError}>\n {renderBlockInner(b, id, data)}\n </BlockErrorBoundary>\n );\n };\n\n // Inner renderer — split out so the outer renderBlock can validate +\n // wrap in an error boundary without nesting the switch in the JSX tree.\n const renderBlockInner = (b: Block, id: string, data: Record<string, unknown>) => {\n switch (b.type) {\n case 'RichText':\n return <RichText key={id} id={id}>{b.childrenMarkdown ?? ''}</RichText>;\n case 'Callout':\n return (\n <Callout key={id} id={id} tone={(data.tone as 'info' | 'warn' | 'success' | 'danger' | undefined) ?? 'info'}>\n {b.childrenMarkdown ?? ''}\n </Callout>\n );\n case 'Checklist':\n return (\n <Checklist key={id} id={id} items={(data.items as any) ?? []} />\n );\n case 'Table':\n return (\n <Table key={id} id={id} columns={(data.columns as string[]) ?? []} rows={(data.rows as string[][]) ?? []} />\n );\n case 'CodeTabs':\n return (\n <CodeTabs key={id} id={id} tabs={(data.tabs as any) ?? []} />\n );\n case 'Decision':\n return (\n <Decision\n key={id}\n id={id}\n title={data.title as string | undefined}\n question={data.question as string | undefined}\n options={(data.options as any) ?? []}\n />\n );\n case 'OpenQuestions':\n return (\n <OpenQuestions\n key={id}\n id={id}\n questions={(data.questions as any) ?? []}\n />\n );\n case 'FileTree':\n return (\n <FileTree\n key={id}\n id={id}\n title={data.title as string | undefined}\n entries={(data.entries as any) ?? []}\n />\n );\n case 'Diff':\n return (\n <Diff\n key={id}\n id={id}\n filename={data.filename as string | undefined}\n language={data.language as string | undefined}\n mode={(data.mode as 'split' | 'unified' | undefined) ?? 'unified'}\n before={(data.before as string) ?? ''}\n after={(data.after as string) ?? ''}\n />\n );\n case 'Stat':\n return (\n <Stat\n key={id}\n id={id}\n label={(data.label as string) ?? ''}\n value={data.value as string | number}\n trend={data.trend as 'up' | 'down' | 'flat' | undefined}\n hint={data.hint as string | undefined}\n />\n );\n case 'Workflow':\n return (\n <Workflow\n key={id}\n id={id}\n steps={(data.steps as any) ?? []}\n connections={data.connections as any}\n />\n );\n case 'Mockup':\n return (\n <Mockup\n key={id}\n id={id}\n title={data.title as string | undefined}\n x={data.x as number | undefined}\n y={data.y as number | undefined}\n w={data.w as number | undefined}\n h={data.h as number | undefined}\n html={(data.html as string) ?? ''}\n />\n );\n case 'Diagram':\n return (\n <div key={id} id={id} className=\"glyph-block-placeholder\">\n <em>[Diagram] {id}</em>\n </div>\n );\n }\n };\n\n if (loading) {\n return (\n <div className=\"glyph-renderer glyph-renderer--loading\">\n {loadError ? (\n <>\n <strong>Failed to load glyph.</strong>\n <pre>{loadError}</pre>\n </>\n ) : (\n <>\n <Spinner /> Loading glyph…\n </>\n )}\n </div>\n );\n }\n\n if (error || !compiled) {\n return (\n <div className=\"glyph-renderer glyph-renderer--error\">\n <strong>Failed to load glyph.</strong>\n <pre>{error ?? 'unknown error'}</pre>\n </div>\n );\n }\n\n const title = (compiled.frontmatter?.title as string) ?? slug;\n const status = (compiled.frontmatter?.status as string) ?? 'draft';\n const commentCount = comments.length;\n\n return (\n <div\n className={`glyph-canvas ${fullscreen ? 'glyph-canvas--fullscreen' : ''}`}\n ref={canvasRef}\n onContextMenu={onContainerContextMenu}\n >\n {/* Floating toolbar (sticky top-right pill) */}\n <div className=\"glyph-toolbar-floating\">\n <button\n className=\"glyph-btn glyph-btn--primary glyph-btn--send\"\n onClick={submitFeedback}\n disabled={submitting}\n title=\"Send comments + question answers to the agent — writes feedback.md, status=review\"\n >\n <Send size={14} />\n <span>Send to agent</span>\n <span className=\"glyph-btn-badge\">{commentCount}</span>\n </button>\n\n <span className=\"glyph-toolbar-divider\" />\n\n <button\n className=\"glyph-icon-btn\"\n title=\"Share\"\n onClick={() => {\n if (typeof window !== 'undefined' && navigator.clipboard) {\n navigator.clipboard.writeText(window.location.href).catch(() => {});\n toast.success('Link copied');\n }\n }}\n >\n <Share2 size={15} />\n </button>\n <button className=\"glyph-icon-btn\" title=\"Undo\" disabled>\n <Undo2 size={15} />\n </button>\n <button className=\"glyph-icon-btn\" title=\"Redo\" disabled>\n <Redo2 size={15} />\n </button>\n <button\n className=\"glyph-icon-btn\"\n title={fullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onClick={toggleFullscreen}\n >\n <Maximize2 size={15} />\n </button>\n <button className=\"glyph-icon-btn\" title=\"More\">\n <MoreHorizontal size={15} />\n </button>\n <span className=\"glyph-toolbar-divider\" />\n <button\n className=\"glyph-icon-btn\"\n title=\"Comment count\"\n aria-label=\"Comment count\"\n >\n <MessageSquare size={15} />\n <span className=\"glyph-icon-btn-count\">{commentCount}</span>\n </button>\n {onClose && (\n <button\n className=\"glyph-icon-btn glyph-icon-btn--close\"\n title=\"Close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n <X size={15} />\n </button>\n )}\n </div>\n\n {/* Canvas content — centered column of section cards */}\n <div className=\"glyph-canvas-content\">\n {/* Title strip (inside canvas, above sections) */}\n <header className=\"glyph-canvas-title\">\n <h1 className=\"glyph-title\">{title}</h1>\n <div className=\"glyph-meta\">\n <span className={`glyph-status glyph-status--${status}`}>{status}</span>\n <span className=\"glyph-slug\">{slug}</span>\n </div>\n </header>\n\n {/* v4.4.8 — Render errors banner. Two layers:\n 1. Compiler warnings from the MDX parser (e.g. unknown\n tag, unclosed block). Lightweight, yellow border.\n 2. Block render errors caught by BlockErrorBoundary. These\n are the \"one block crashed but the rest still rendered\"\n cases. Red border, prominent, listed first so the user\n sees them before scrolling. */}\n {(blockErrors.length > 0 || compiled.errors?.length > 0) && (\n <div\n className=\"glyph-render-errors\"\n role=\"alert\"\n style={{\n border: '1px solid var(--error, #f85149)',\n background: 'rgba(248, 81, 73, 0.08)',\n borderRadius: 8,\n padding: '12px 16px',\n margin: '0 0 16px 0',\n color: 'var(--text)',\n }}\n >\n <strong style={{ color: 'var(--error, #f85149)', display: 'block', marginBottom: 8 }}>\n {blockErrors.length > 0\n ? `${blockErrors.length} block${blockErrors.length === 1 ? '' : 's'} failed to render`\n : 'Compiler warnings'}\n </strong>\n <ul style={{ margin: 0, paddingLeft: 20, fontFamily: 'var(--font-mono, ui-monospace, monospace)', fontSize: 12, lineHeight: 1.6 }}>\n {blockErrors.map((e, i) => (\n <li key={`be-${i}`}>\n <strong>{e.blockType}</strong> (<code>{e.blockId}</code>): {e.message}\n </li>\n ))}\n {compiled.errors?.map((e, i) => (\n <li key={`ce-${i}`}>\n {e.line ? `line ${e.line}: ` : ''}{e.message}\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {/* Sections */}\n <div className=\"glyph-sections\">\n {sections.map((section, i) => (\n <section\n key={`sec-${i}-${section.heading ?? 'ungrouped'}`}\n className={`glyph-section ${section.heading ? 'glyph-section--headed' : 'glyph-section--plain'}`}\n >\n {section.heading && (\n <h2 className=\"glyph-section-heading\">{section.heading}</h2>\n )}\n <div className=\"glyph-section-blocks\">\n {section.blocks.map(renderBlock)}\n </div>\n </section>\n ))}\n </div>\n </div>\n\n {/* Comment pin overlay */}\n {comments.map((c) => (\n <button\n key={c.id}\n className={`glyph-pin ${activePin === c.id ? 'glyph-pin--active' : ''}`}\n style={{ left: c.x, top: c.y }}\n onClick={(e) => {\n e.stopPropagation();\n setActivePin(activePin === c.id ? null : c.id);\n }}\n title={c.text}\n >\n <MapPin size={14} />\n {activePin === c.id && (\n <div className=\"glyph-pin-thread\">\n <div className=\"glyph-pin-text\">{c.text}</div>\n <div className=\"glyph-pin-meta\">\n {c.author ?? 'anonymous'} · {c.created ? new Date(c.created).toLocaleString() : ''}\n </div>\n </div>\n )}\n </button>\n ))}\n\n {/* Context menu (right-click) */}\n {ctxMenu && (\n <div\n className=\"glyph-ctx-menu\"\n style={{ left: ctxMenu.x, top: ctxMenu.y }}\n onClick={(e) => e.stopPropagation()}\n >\n <button\n className=\"glyph-ctx-item\"\n onClick={() => {\n setAddingComment({ worldX: ctxMenu.worldX, worldY: ctxMenu.worldY });\n setCtxMenu(null);\n }}\n >\n <MapPin size={14} /> Add comment here\n </button>\n </div>\n )}\n\n {/* Add-comment modal */}\n {addingComment && (\n <div className=\"glyph-modal-overlay\" onClick={() => setAddingComment(null)}>\n <div className=\"glyph-modal\" onClick={(e) => e.stopPropagation()}>\n <h3>Add comment at ({Math.round(addingComment.worldX)}, {Math.round(addingComment.worldY)})</h3>\n <textarea\n autoFocus\n value={commentDraft}\n onChange={(e) => setCommentDraft(e.target.value)}\n placeholder=\"What should the agent know about this area?\"\n rows={4}\n className=\"glyph-modal-textarea\"\n />\n <div className=\"glyph-modal-actions\">\n <button className=\"glyph-btn glyph-btn--ghost\" onClick={() => setAddingComment(null)}>\n Cancel\n </button>\n <button className=\"glyph-btn glyph-btn--primary\" onClick={submitComment} disabled={!commentDraft.trim()}>\n Add comment\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// Tiny inline spinner (no extra dep)\nfunction Spinner() {\n return <span className=\"glyph-spinner\" aria-label=\"loading\">…</span>;\n}","// src/views/Artifacts.tsx — v3.1.0 artifact editor with fullscreen canvas + floating controls.\nimport React from 'react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { GlyphRenderer } from './glyphs/GlyphRenderer';\nimport {\n ArrowLeft,\n Map as MapIcon,\n Plus,\n RefreshCw,\n Settings as SettingsIcon,\n MessageCircle,\n MessageSquare,\n Maximize2,\n Minimize2,\n X,\n Trash2,\n Pencil,\n Link2,\n Send,\n Check,\n Circle,\n StopCircle,\n AlertCircle,\n HelpCircle,\n CheckSquare,\n StickyNote,\n ChevronRight,\n Search,\n Activity,\n Filter,\n Archive,\n ArchiveRestore,\n Copy,\n ArrowUp,\n ArrowDown,\n Layers,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { CanvasContextMenu, type ContextMenuState } from '../components/CanvasContextMenu';\nimport { api } from '../lib/api';\nimport { cn, formatRelative, truncate } from '../lib/utils';\nimport type {\n Canvas,\n CanvasComment,\n CanvasConnection,\n CanvasElement,\n Artifact,\n Settings,\n Snapshot,\n} from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst ELEMENT_TYPES = [\n { id: 'task', label: 'Task', color: 'var(--info)', Icon: CheckSquare },\n { id: 'note', label: 'Note', color: 'var(--text-dim)', Icon: StickyNote },\n { id: 'decision', label: 'Decision', color: 'var(--accent)', Icon: Check },\n { id: 'question', label: 'Question', color: 'var(--warning)', Icon: HelpCircle },\n];\n\nconst PLAN_STATUSES = ['draft', 'approved', 'in-progress', 'done', 'rejected', 'archived'];\n\nfunction planStatusKind(status: string): 'success' | 'info' | 'error' | 'accent' | 'neutral' | 'warning' {\n switch (status) {\n case 'approved':\n case 'done':\n return 'success';\n case 'in-progress':\n case 'doing':\n return 'info';\n case 'rejected':\n return 'error';\n case 'archived':\n return 'warning';\n case 'draft':\n default:\n return 'neutral';\n }\n}\n\nfunction elementColor(type: string): string {\n return ELEMENT_TYPES.find((t) => t.id === type)?.color || 'var(--text-dim)';\n}\n\nfunction ElementIcon({ type, size = 12 }: { type: string; size?: number }) {\n const def = ELEMENT_TYPES.find((t) => t.id === type) || ELEMENT_TYPES[1];\n const Icon = def.Icon;\n return <Icon size={size} style={{ color: def.color }} />;\n}\n\n// ── List view ──────────────────────────────────────────────────────────\n\nexport function Artifacts({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const [artifacts, setPlans] = useState<Artifact[]>(snapshot.artifacts || []);\n const [loading, setLoading] = useState(!snapshot.artifacts);\n const [activeSlug, setActiveSlug] = useState<string | null>(null);\n const [filter, setFilter] = useState('');\n const [showArchived, setShowArchived] = useState(false);\n\n useEffect(() => {\n if (snapshot.artifacts) {\n setPlans(snapshot.artifacts);\n setLoading(false);\n }\n }, [snapshot.artifacts]);\n\n const reload = async () => {\n try {\n const d = await api.get<{ artifacts: Artifact[] }>('/artifacts');\n setPlans(d.artifacts || []);\n setLoading(false);\n } catch (err) {\n toast.error(`Artifacts load failed: ${(err as Error).message}`);\n setLoading(false);\n }\n };\n\n const filtered = useMemo(() => {\n let out = artifacts;\n if (filter) {\n const q = filter.toLowerCase();\n out = out.filter(\n (p) =>\n (p.slug || '').toLowerCase().includes(q) ||\n (p.title || '').toLowerCase().includes(q),\n );\n }\n if (!showArchived) {\n out = out.filter((p) => p.status !== 'archived');\n }\n return out;\n }, [artifacts, filter, showArchived]);\n\n const onCreate = async (slug: string, title?: string) => {\n try {\n const artifact = await api.post<{ slug: string }>('/artifacts', { slug, title });\n toast.success(`Artifact \"${artifact.slug}\" created.`);\n setActiveSlug(artifact.slug);\n await reload();\n } catch (err) {\n toast.error(`Create failed: ${(err as Error).message}`);\n }\n };\n\n const onDelete = async (slug: string) => {\n if (!confirm(`Delete artifact \"${slug}\"? This removes the directory permanently.`)) return;\n try {\n await api.del(`/artifacts/${encodeURIComponent(slug)}`);\n toast.success('Artifact deleted.');\n if (activeSlug === slug) setActiveSlug(null);\n await reload();\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n if (activeSlug) {\n // v3.21.0 — Use the new GlyphRenderer (agent-native-style MDX renderer)\n // instead of the hand-rolled PlanEditor canvas. Toggle available via the\n // \"Use MDX\" button in the header (TODO: surface this once stable).\n return (\n <div className=\"artifact-glyph-overlay\">\n <div className=\"artifact-glyph-toolbar\">\n <Button variant=\"ghost\" onClick={() => { setActiveSlug(null); reload(); }}>\n <ArrowLeft size={14} /> Back to artifacts\n </Button>\n </div>\n <GlyphRenderer\n slug={activeSlug}\n onClose={() => { setActiveSlug(null); reload(); }}\n onCommentAdded={() => reload()}\n />\n </div>\n );\n }\n\n return (\n <div className=\"view view-artifacts\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <MapIcon size={18} /> Glyphs ({artifacts.length})\n </h2>\n <p className=\"view-subtitle\">\n Visual artifacts with elements, connections, and threaded comments.\n </p>\n </div>\n <div className=\"view-actions\">\n <div className=\"search-input\">\n <Search size={14} aria-hidden />\n <label htmlFor=\"artifacts-search\" className=\"sr-only\">Search artifacts</label>\n <input\n id=\"artifacts-search\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Search…\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n aria-label=\"Search artifacts\"\n />\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setShowArchived((v) => !v)}\n title={showArchived ? 'Hide archived' : 'Show archived'}\n >\n {showArchived ? <ArchiveRestore size={14} /> : <Archive size={14} />}\n {showArchived ? 'Hide archived' : 'Show archived'}\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={reload}>\n <RefreshCw size={14} /> Refresh\n </Button>\n </div>\n </header>\n\n <NewPlanCard onCreate={onCreate} />\n\n {loading ? (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n </div>\n ) : filtered.length === 0 ? (\n <EmptyState\n icon={<MapIcon size={32} />}\n title={showArchived ? 'No artifacts' : 'No artifacts yet'}\n message={\n showArchived\n ? 'No artifacts match your filter (try Show archived off).'\n : 'Create one above to get started.'\n }\n />\n ) : (\n <div className=\"artifacts-grid\">\n {filtered.map((p) => (\n <PlanCard\n key={p.slug}\n artifact={p}\n onOpen={() => setActiveSlug(p.slug)}\n onDelete={() => onDelete(p.slug)}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction NewPlanCard({ onCreate }: { onCreate: (slug: string, title?: string) => void }) {\n const [slug, setSlug] = useState('');\n const [title, setTitle] = useState('');\n return (\n <Card className=\"new-artifact\">\n <CardTitle>\n <Plus size={14} /> New artifact\n </CardTitle>\n <CardMeta>Slug must be lowercase, may contain hyphens, 1–64 chars.</CardMeta>\n <form\n className=\"new-artifact-form\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!slug.trim()) return;\n onCreate(slug.trim(), title.trim() || undefined);\n setSlug('');\n setTitle('');\n }}\n >\n <label htmlFor=\"new-artifact-slug\" className=\"sr-only\">Artifact slug</label>\n <input\n id=\"new-artifact-slug\"\n className=\"input\"\n type=\"text\"\n placeholder=\"slug (e.g. dashboard-v3.1)\"\n pattern=\"[a-z0-9][a-z0-9-]{0,63}\"\n required\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n aria-label=\"Artifact slug\"\n />\n <label htmlFor=\"new-artifact-title\" className=\"sr-only\">Artifact title</label>\n <input\n id=\"new-artifact-title\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Title (optional)\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n <Button variant=\"primary\" type=\"submit\">\n Create\n </Button>\n </form>\n </Card>\n );\n}\n\nfunction PlanCard({\n artifact,\n onOpen,\n onDelete,\n}: {\n artifact: Artifact;\n onOpen: () => void;\n onDelete: () => void;\n}) {\n const kind = planStatusKind(artifact.status || 'draft');\n return (\n <Card\n variant=\"elevated\"\n interactive\n className=\"artifact-card\"\n onClick={onOpen}\n >\n <div className=\"artifact-card-head\">\n <div className=\"artifact-card-title\">{artifact.title || artifact.slug}</div>\n <StatusBadge kind={kind}>{artifact.status || 'draft'}</StatusBadge>\n </div>\n <div className=\"artifact-card-slug mono\">{artifact.slug} · {artifact.source}</div>\n <div className=\"artifact-card-meta\">\n {artifact.elementCount != null && <span>{artifact.elementCount} elements</span>}\n {artifact.commentCount != null && <span> · {artifact.commentCount} comments</span>}\n <span> · edited {formatRelative(artifact.mtime)}</span>\n </div>\n <div className=\"artifact-card-actions\">\n <Button variant=\"primary\" size=\"sm\" onClick={(e) => { e.stopPropagation(); onOpen(); }}>\n Open\n <ChevronRight size={12} />\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={(e) => { e.stopPropagation(); onDelete(); }}>\n <Trash2 size={12} /> Delete\n </Button>\n </div>\n </Card>\n );\n}\n\n// ── Artifact editor (fullscreen) ──────────────────────────────────────────\n\nfunction PlanEditor({\n slug,\n onBack,\n onDelete,\n}: {\n slug: string;\n onBack: () => void;\n onDelete: () => void;\n}) {\n const toast = useToast();\n const modal = useModal();\n const [canvas, setCanvas] = useState<Canvas | null>(null);\n const [meta, setMeta] = useState<{ title: string; status: string; tags: string[]; description?: string } | null>(null);\n const [loading, setLoading] = useState(true);\n const [selectedElId, setSelectedElId] = useState<string | null>(null);\n const [fullscreen, setFullscreen] = useState(false);\n const [showComments, setShowComments] = useState(true);\n const [contextMenu, setContextMenu] = useState<ContextMenuState>(null);\n const [contextMenuWorldPos, setContextMenuWorldPos] = useState<{ x: number; y: number } | null>(null);\n // v3.7.0 — Element-specific right-click context menu\n const [elementContextMenu, setElementContextMenu] = useState<ContextMenuState>(null);\n\n const moveElementLocally = (id: string, x: number, y: number) => {\n setCanvas((cur) => {\n if (!cur) return cur;\n return {\n ...cur,\n elements: cur.elements.map((el) => (el.id === id ? { ...el, x, y } : el)),\n };\n });\n };\n\n const reload = async () => {\n setLoading(true);\n try {\n const artifact = await api.get<{ meta: { title: string; status: string; tags: string[]; description?: string }; canvas: Canvas }>(\n `/artifacts/${encodeURIComponent(slug)}`,\n );\n setCanvas(artifact.canvas);\n setMeta(artifact.meta);\n } catch (err) {\n toast.error(`Could not load artifact: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setSelectedElId(null);\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [slug]);\n\n // Issue 3 fix — wire fullscreen state to browser Fullscreen API\n useEffect(() => {\n if (!fullscreen) {\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n }\n return;\n }\n // Sync state when user exits via ESC key — before entering, so we don't\n // double-set on the way in\n const onFullscreenChange = () => {\n if (!document.fullscreenElement) setFullscreen(false);\n };\n document.addEventListener('fullscreenchange', onFullscreenChange);\n // Attempt to enter fullscreen (fails silently if unsupported or blocked)\n document.documentElement.requestFullscreen().catch(() => {});\n return () => {\n document.removeEventListener('fullscreenchange', onFullscreenChange);\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fullscreen]);\n\n const totalComments = canvas?.comments.length ?? 0;\n\n const addElement = async (body: { type: string; title: string; content: string; x: number; y: number }, position?: { x: number; y: number }) => {\n try {\n const payload = position ? { ...body, x: position.x, y: position.y } : body;\n await api.post(`/artifacts/${encodeURIComponent(slug)}/elements`, payload);\n await reload();\n toast.success('Element added.');\n } catch (err) {\n toast.error(`Add element failed: ${(err as Error).message}`);\n }\n };\n\n const updateElement = async (id: string, body: Partial<CanvasElement>) => {\n try {\n await api.put(`/artifacts/${encodeURIComponent(slug)}/elements/${encodeURIComponent(id)}`, body);\n await reload();\n } catch (err) {\n toast.error(`Update failed: ${(err as Error).message}`);\n }\n };\n\n const deleteElement = async (id: string) => {\n try {\n await api.del(`/artifacts/${encodeURIComponent(slug)}/elements/${encodeURIComponent(id)}`);\n if (selectedElId === id) setSelectedElId(null);\n await reload();\n toast.success('Element deleted.');\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n // v3.7.0 — Duplicate an element with a small position offset\n const duplicateElement = async (id: string) => {\n const el = canvas?.elements.find((e) => e.id === id);\n if (!el) return;\n try {\n await api.post(`/artifacts/${encodeURIComponent(slug)}/elements`, {\n type: el.type,\n title: el.title ? `${el.title} (copy)` : 'Untitled',\n content: el.content || '',\n x: (el.x || 0) + 24,\n y: (el.y || 0) + 24,\n });\n await reload();\n toast.success('Element duplicated.');\n } catch (err) {\n toast.error(`Duplicate failed: ${(err as Error).message}`);\n }\n };\n\n // v3.7.0 — Change element type\n const changeElementType = async (id: string, newType: string) => {\n try {\n await api.put(`/artifacts/${encodeURIComponent(slug)}/elements/${encodeURIComponent(id)}`, { type: newType });\n await reload();\n toast.success(`Type changed to ${newType}.`);\n } catch (err) {\n toast.error(`Change type failed: ${(err as Error).message}`);\n }\n };\n\n const addConnection = async (from: string, to: string, label?: string) => {\n try {\n await api.post(`/artifacts/${encodeURIComponent(slug)}/connections`, { from, to, label });\n await reload();\n toast.success('Connection added.');\n } catch (err) {\n toast.error(`Connection failed: ${(err as Error).message}`);\n }\n };\n\n const deleteConnection = async (id: string) => {\n try {\n await api.del(`/artifacts/${encodeURIComponent(slug)}/connections/${encodeURIComponent(id)}`);\n await reload();\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const addComment = async (text: string, elementId: string | null, worldPos?: { x: number; y: number }) => {\n try {\n const path = elementId\n ? `/artifacts/${encodeURIComponent(slug)}/elements/${encodeURIComponent(elementId)}/comments`\n : `/artifacts/${encodeURIComponent(slug)}/comments`;\n const body: { text: string; elementId: string | null; x?: number; y?: number } = { text, elementId };\n if (worldPos) { body.x = worldPos.x; body.y = worldPos.y; }\n await api.post(path, body);\n await reload();\n toast.success('Comment added.');\n } catch (err) {\n toast.error(`Comment failed: ${(err as Error).message}`);\n }\n };\n\n const deleteComment = async (cid: string) => {\n try {\n await api.del(`/artifacts/${encodeURIComponent(slug)}/comments/${encodeURIComponent(cid)}`);\n await reload();\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const updatePositions = async (positions: { id: string; x: number; y: number }[]) => {\n try {\n await api.put(`/artifacts/${encodeURIComponent(slug)}/position`, { positions });\n } catch (err) {\n // non-fatal\n console.warn('Position update failed', err);\n }\n };\n\n const onConfigure = () => {\n if (!meta) return;\n let titleEl: HTMLInputElement | null = null;\n let descEl: HTMLTextAreaElement | null = null;\n let tagsEl: HTMLInputElement | null = null;\n let statusEl: HTMLSelectElement | null = null;\n modal.open({\n title: 'Configure artifact',\n width: 560,\n children: (\n <div className=\"artifact-config-form\">\n <label className=\"field-label\" htmlFor=\"artifact-cfg-title\">Title</label>\n <input id=\"artifact-cfg-title\" ref={(el) => { titleEl = el; }} className=\"input\" type=\"text\" defaultValue={meta.title} />\n <label className=\"field-label\" htmlFor=\"artifact-cfg-desc\">Description (markdown)</label>\n <textarea id=\"artifact-cfg-desc\" ref={(el) => { descEl = el; }} className=\"textarea\" rows={3} defaultValue={meta.description || ''} />\n <label className=\"field-label\" htmlFor=\"artifact-cfg-tags\">Tags (comma-separated)</label>\n <input id=\"artifact-cfg-tags\" ref={(el) => { tagsEl = el; }} className=\"input\" type=\"text\" defaultValue={(meta.tags || []).join(', ')} />\n <label className=\"field-label\" htmlFor=\"artifact-cfg-status\">Status</label>\n <select id=\"artifact-cfg-status\" ref={(el) => { statusEl = el; }} className=\"select\" defaultValue={meta.status}>\n {PLAN_STATUSES.map((s) => (\n <option key={s} value={s}>{s}</option>\n ))}\n </select>\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n try {\n const tags = (tagsEl?.value || '').split(',').map((t) => t.trim()).filter(Boolean);\n await api.put(`/artifacts/${encodeURIComponent(slug)}`, {\n title: (titleEl?.value || '').trim() || meta.title,\n description: descEl?.value || '',\n tags,\n status: statusEl?.value || meta.status,\n });\n await reload();\n toast.success('Artifact updated.');\n modal.close();\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n }}\n >\n Save\n </Button>\n </div>\n ),\n });\n };\n\n const onAddElement = (worldPos?: { x: number; y: number }) => {\n let typeEl: HTMLSelectElement | null = null;\n let titleEl: HTMLInputElement | null = null;\n let contentEl: HTMLTextAreaElement | null = null;\n modal.open({\n title: 'Add element',\n width: 520,\n children: (\n <div className=\"artifact-element-form\">\n <label className=\"field-label\" htmlFor=\"artifact-elem-type\">Type</label>\n <select id=\"artifact-elem-type\" ref={(el) => { typeEl = el; }} className=\"select\" defaultValue=\"task\">\n {ELEMENT_TYPES.map((t) => (\n <option key={t.id} value={t.id}>{t.label}</option>\n ))}\n </select>\n <label className=\"field-label\" htmlFor=\"artifact-elem-title\">Title</label>\n <input id=\"artifact-elem-title\" ref={(el) => { titleEl = el; }} className=\"input\" type=\"text\" placeholder=\"Element title\" autoFocus />\n <label className=\"field-label\" htmlFor=\"artifact-elem-content\">Content (markdown)</label>\n <textarea id=\"artifact-elem-content\" ref={(el) => { contentEl = el; }} className=\"textarea\" rows={4} placeholder=\"Description…\" />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (worldPos) {\n await addElement({\n type: typeEl?.value || 'note',\n title: (titleEl?.value || 'Untitled').trim(),\n content: contentEl?.value || '',\n x: worldPos.x,\n y: worldPos.y,\n });\n } else {\n const maxX = (canvas?.elements || []).reduce((acc, el) => Math.max(acc, el.x || 0), 0);\n const maxY = (canvas?.elements || []).reduce((acc, el) => Math.max(acc, el.y || 0), 0);\n await addElement({\n type: typeEl?.value || 'note',\n title: (titleEl?.value || 'Untitled').trim(),\n content: contentEl?.value || '',\n x: 80 + Math.min(maxX + 40, 200),\n y: 80 + Math.min(maxY + 40, 200),\n });\n }\n modal.close();\n }}\n >\n <Plus size={12} /> Add\n </Button>\n </div>\n ),\n });\n };\n\n const onCanvasComment = (worldPos?: { x: number; y: number }) => {\n let textEl: HTMLTextAreaElement | null = null;\n modal.open({\n title: 'Add canvas comment',\n width: 480,\n children: (\n <div>\n <label className=\"field-label\" htmlFor=\"canvas-comment\">Comment</label>\n <textarea id=\"canvas-comment\" ref={(el) => { textEl = el; }} className=\"textarea\" rows={4} placeholder=\"Comment for the whole artifact…\" autoFocus />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async (e) => {\n e.preventDefault();\n e.stopPropagation();\n const text = (textEl?.value || '').trim();\n if (!text) return;\n await addComment(text, null, worldPos);\n modal.close();\n }}\n >\n <Send size={12} /> Post\n </Button>\n </div>\n ),\n });\n };\n\n if (loading || !canvas || !meta) {\n return (\n <div className=\"view view-artifacts view-artifacts-fullscreen\">\n <PlanEditorHeader\n slug={slug}\n meta={meta || { title: slug, status: 'draft', tags: [] }}\n counts={{ elements: 0, comments: 0 }}\n onBack={onBack}\n onConfigure={() => undefined}\n onAddElement={() => undefined}\n onCanvasComment={() => undefined}\n onRefresh={reload}\n onDelete={onDelete}\n fullscreen={fullscreen}\n setFullscreen={setFullscreen}\n />\n <div className=\"view-loading\" style={{ flex: 1 }}>\n <Spinner size=\"lg\" />\n <p>Loading canvas…</p>\n </div>\n </div>\n );\n }\n\n const visibleComments = selectedElId\n ? canvas.comments.filter((c) => c.elementId === selectedElId)\n : canvas.comments;\n\n return (\n <div className={cn('view view-artifacts view-artifacts-fullscreen', !fullscreen && 'view-artifacts-embedded')}>\n {!fullscreen && (\n <PlanEditorHeader\n slug={slug}\n meta={meta}\n counts={{ elements: canvas.elements.length, comments: totalComments }}\n onBack={onBack}\n onConfigure={onConfigure}\n onAddElement={onAddElement}\n onCanvasComment={onCanvasComment}\n onRefresh={reload}\n onDelete={onDelete}\n fullscreen={fullscreen}\n setFullscreen={setFullscreen}\n />\n )}\n\n <div className=\"artifacts-body\">\n {/* Canvas wrapper with floating controls */}\n <div className=\"artifact-canvas-wrapper\">\n {fullscreen && (\n <div className=\"artifact-canvas-floating-controls\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onBack} title=\"Back to artifacts list\">\n <ArrowLeft size={14} /> Back\n </Button>\n <h3>{meta?.title || slug}</h3>\n {meta && <StatusBadge kind={planStatusKind(meta.status)}>{meta.status}</StatusBadge>}\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onAddElement()}>\n <Plus size={14} /> Element\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onCanvasComment()}>\n <MessageCircle size={14} /> Comment\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onConfigure} title=\"Configure artifact\" aria-label=\"Configure artifact\">\n <SettingsIcon size={14} />\n </Button>\n </div>\n )}\n\n <CanvasViewport\n canvas={canvas}\n selectedElId={selectedElId}\n onSelect={setSelectedElId}\n onMoveElement={moveElementLocally}\n onMoveEnd={updatePositions}\n onDeleteElement={deleteElement}\n onConnect={(from, to) => addConnection(from, to)}\n onDeleteConnection={deleteConnection}\n onEditElement={(el) => editElementInline(modal, slug, el, updateElement, toast)}\n onContextMenu={(e, worldPos) => {\n e.preventDefault();\n setElementContextMenu(null);\n setContextMenuWorldPos(worldPos);\n setContextMenu({\n x: e.clientX,\n y: e.clientY,\n items: [\n { label: 'Add element', icon: Plus, onClick: () => onAddElement(worldPos) },\n { label: 'Add comment', icon: MessageSquare, onClick: () => onCanvasComment(worldPos) },\n { type: 'separator' },\n { label: 'Configure artifact', icon: SettingsIcon, onClick: onConfigure },\n { label: 'Delete artifact', icon: Trash2, onClick: onDelete },\n ],\n });\n }}\n onElementContextMenu={(e, elementId, _worldPos) => {\n const el = canvas?.elements.find((x) => x.id === elementId);\n if (!el) return;\n setContextMenu(null);\n setElementContextMenu({\n x: e.clientX,\n y: e.clientY,\n items: [\n { label: 'Edit', icon: Pencil, onClick: () => { editElementInline(modal, slug, el, updateElement, toast); } },\n { label: 'Duplicate', icon: Copy, onClick: () => duplicateElement(elementId) },\n { type: 'separator' },\n { label: 'Change type', icon: Layers, onClick: () => {\n // Cycle through types: task -> note -> decision -> question -> task\n const types = ['task', 'note', 'decision', 'question'];\n const currentIdx = types.indexOf(el.type);\n const nextType = types[(currentIdx + 1) % types.length];\n changeElementType(elementId, nextType);\n }},\n { type: 'separator' },\n { label: `Delete`, icon: Trash2, onClick: () => { if (confirm(`Delete \"${el.title || el.type}\"?`)) deleteElement(elementId); } },\n ],\n });\n }}\n />\n\n {/* Canvas-level context menu */}\n <CanvasContextMenu menu={contextMenu} onClose={() => setContextMenu(null)} />\n {/* Element-level context menu */}\n <CanvasContextMenu menu={elementContextMenu} onClose={() => setElementContextMenu(null)} />\n </div>\n\n {showComments && (\n <CommentsPanel\n slug={slug}\n comments={visibleComments}\n selectedElId={selectedElId}\n onAdd={(text) => addComment(text, selectedElId)}\n onDelete={deleteComment}\n onClose={() => {\n setShowComments(false);\n setSelectedElId(null);\n }}\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction PlanEditorHeader({\n slug,\n meta,\n counts,\n onBack,\n onConfigure,\n onAddElement,\n onCanvasComment,\n onRefresh,\n onDelete,\n fullscreen,\n setFullscreen,\n}: {\n slug: string;\n meta: { title: string; status: string; tags: string[] };\n counts: { elements: number; comments: number };\n onBack: () => void;\n onConfigure: () => void;\n onAddElement: () => void;\n onCanvasComment: () => void;\n onRefresh: () => void;\n onDelete: () => void;\n fullscreen: boolean;\n setFullscreen: (v: boolean) => void;\n}) {\n const kind = planStatusKind(meta.status);\n return (\n <header className=\"artifacts-editor-bar\">\n <div className=\"artifacts-editor-bar-left\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onBack} title=\"Back to artifacts list\">\n <ArrowLeft size={14} /> Back\n </Button>\n <div className=\"artifacts-editor-meta\">\n <span className=\"artifacts-editor-title\">{meta.title || slug}</span>\n <span className=\"artifacts-editor-slug mono\">{slug}</span>\n <StatusBadge kind={kind}>{meta.status}</StatusBadge>\n </div>\n </div>\n <div className=\"artifacts-editor-bar-right\">\n <span className=\"muted text-sm\">\n {counts.elements} element{counts.elements === 1 ? '' : 's'} · {counts.comments} comment{counts.comments === 1 ? '' : 's'}\n </span>\n <Button variant=\"secondary\" size=\"sm\" onClick={onAddElement}>\n <Plus size={14} /> Element\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onCanvasComment}>\n <MessageCircle size={14} /> Comment\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onConfigure} title=\"Configure artifact\" aria-label=\"Configure artifact\">\n <SettingsIcon size={14} />\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onRefresh} title=\"Refresh canvas\" aria-label=\"Refresh canvas\">\n <RefreshCw size={14} />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setFullscreen(!fullscreen)}\n title={fullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n aria-label={fullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n >\n {fullscreen ? <Minimize2 size={14} /> : <Maximize2 size={14} />}\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onDelete} title=\"Delete artifact\" aria-label=\"Delete artifact\">\n <Trash2 size={14} />\n </Button>\n </div>\n </header>\n );\n}\n\nfunction editElementInline(\n modal: ReturnType<typeof useModal>,\n slug: string,\n el: CanvasElement,\n updateElement: (id: string, body: Partial<CanvasElement>) => Promise<void>,\n toast: ReturnType<typeof useToast>,\n) {\n let typeEl: HTMLSelectElement | null = null;\n let titleEl: HTMLInputElement | null = null;\n let contentEl: HTMLTextAreaElement | null = null;\n let statusEl: HTMLInputElement | null = null;\n modal.open({\n title: `Edit ${el.title || el.type}`,\n width: 520,\n children: (\n <div className=\"artifact-element-form\">\n <label className=\"field-label\" htmlFor=\"elem-edit-type\">Type</label>\n <select id=\"elem-edit-type\" ref={(el2) => { typeEl = el2; }} className=\"select\" defaultValue={el.type}>\n {ELEMENT_TYPES.map((t) => (\n <option key={t.id} value={t.id}>{t.label}</option>\n ))}\n </select>\n <label className=\"field-label\" htmlFor=\"elem-edit-title\">Title</label>\n <input id=\"elem-edit-title\" ref={(el2) => { titleEl = el2; }} className=\"input\" type=\"text\" defaultValue={el.title} />\n <label className=\"field-label\" htmlFor=\"elem-edit-status\">Status</label>\n <input id=\"elem-edit-status\" ref={(el2) => { statusEl = el2; }} className=\"input\" type=\"text\" defaultValue={el.status} placeholder=\"open / done / blocked …\" />\n <label className=\"field-label\" htmlFor=\"elem-edit-content\">Content (markdown)</label>\n <textarea id=\"elem-edit-content\" ref={(el2) => { contentEl = el2; }} className=\"textarea\" rows={5} defaultValue={el.content} />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n try {\n await updateElement(el.id, {\n type: typeEl?.value || el.type,\n title: titleEl?.value ?? el.title,\n content: contentEl?.value ?? el.content,\n status: statusEl?.value || el.status,\n });\n toast.success('Element saved.');\n modal.close();\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n }}\n >\n Save\n </Button>\n </div>\n ),\n });\n}\n\n// ── Canvas viewport ───────────────────────────────────────────────────\n\ntype ViewportProps = {\n canvas: Canvas;\n selectedElId: string | null;\n onSelect: (id: string | null) => void;\n onMoveElement: (id: string, x: number, y: number) => void;\n onMoveEnd: (positions: { id: string; x: number; y: number }[]) => void;\n onDeleteElement: (id: string) => void;\n onConnect: (from: string, to: string) => void;\n onDeleteConnection: (id: string) => void;\n onEditElement: (el: CanvasElement) => void;\n onContextMenu?: (e: React.MouseEvent, worldPos: { x: number; y: number }) => void;\n // v3.7.0 — Element-specific context menu (right-click on an element)\n onElementContextMenu?: (e: React.MouseEvent, elementId: string, worldPos: { x: number; y: number }) => void;\n fitToView?: () => void;\n};\n\nfunction CanvasViewport({\n canvas,\n selectedElId,\n onSelect,\n onMoveElement,\n onMoveEnd,\n onDeleteElement,\n onConnect,\n onDeleteConnection,\n onEditElement,\n onContextMenu,\n onElementContextMenu,\n}: ViewportProps) {\n const rootRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n const elementsRef = useRef(canvas.elements);\n const stateRef = useRef({\n panning: false,\n startX: 0,\n startY: 0,\n ox: canvas.viewport.x || 0,\n oy: canvas.viewport.y || 0,\n scale: canvas.viewport.zoom || 1,\n dragging: null as null | { id: string; offsetX: number; offsetY: number; moved: boolean; origX: number; origY: number },\n connecting: null as null | { fromId: string; x: number; y: number },\n });\n\n useEffect(() => {\n elementsRef.current = canvas.elements;\n }, [canvas.elements]);\n\n useEffect(() => {\n const root = rootRef.current;\n const inner = innerRef.current;\n if (!root || !inner) return undefined;\n const apply = () => {\n const s = stateRef.current;\n inner.style.transform = `translate(${s.ox}px, ${s.oy}px) scale(${s.scale})`;\n };\n apply();\n\n const screenToWorld = (clientX: number, clientY: number) => {\n const rect = inner.getBoundingClientRect();\n const s = stateRef.current;\n // rect.left/rect.top is the *post-transform* top-left; account for scale\n const x = (clientX - rect.left) / s.scale;\n const y = (clientY - rect.top) / s.scale;\n return { x, y };\n };\n\n const onMouseDown = (e: MouseEvent) => {\n if (e.button === 2) return;\n const t = e.target as HTMLElement;\n if (\n t === root ||\n t.classList.contains('canvas-grid-bg') ||\n t.classList.contains('canvas-inner')\n ) {\n stateRef.current.panning = true;\n stateRef.current.startX = e.clientX - stateRef.current.ox;\n stateRef.current.startY = e.clientY - stateRef.current.oy;\n root.style.cursor = 'grabbing';\n return;\n }\n const elCard = t.closest('.canvas-element') as HTMLElement | null;\n if (elCard) {\n const id = elCard.dataset.elementId;\n if (!id) return;\n const headerHit = !!t.closest('.canvas-element-head');\n const handleHit = !!t.closest('.canvas-element-handle');\n if (headerHit || handleHit) {\n const world = screenToWorld(e.clientX, e.clientY);\n const el = elementsRef.current.find((x) => x.id === id);\n if (!el) return;\n stateRef.current.dragging = {\n id,\n offsetX: world.x - (el.x || 0),\n offsetY: world.y - (el.y || 0),\n moved: false,\n origX: el.x || 0,\n origY: el.y || 0,\n };\n onSelect(id);\n e.preventDefault();\n }\n }\n };\n const onMouseMove = (e: MouseEvent) => {\n const s = stateRef.current;\n if (s.panning) {\n s.ox = e.clientX - s.startX;\n s.oy = e.clientY - s.startY;\n apply();\n return;\n }\n if (s.dragging) {\n const world = screenToWorld(e.clientX, e.clientY);\n const newX = Math.max(0, world.x - s.dragging.offsetX);\n const newY = Math.max(0, world.y - s.dragging.offsetY);\n if (!s.dragging.moved) {\n const dx = Math.abs(newX - s.dragging.origX);\n const dy = Math.abs(newY - s.dragging.origY);\n if (dx < 2 && dy < 2) return;\n }\n s.dragging.moved = true;\n onMoveElement(s.dragging.id, newX, newY);\n return;\n }\n if (s.connecting) {\n const inner2 = innerRef.current;\n if (!inner2) return;\n const world = screenToWorld(e.clientX, e.clientY);\n s.connecting.x = world.x;\n s.connecting.y = world.y;\n // Trigger a custom event so the connecting SVG re-renders.\n inner2.dispatchEvent(new CustomEvent('canvas-move', { detail: { x: world.x, y: world.y } }));\n }\n };\n const onMouseUp = () => {\n const s = stateRef.current;\n if (s.panning) {\n s.panning = false;\n root.style.cursor = '';\n }\n if (s.dragging) {\n if (s.dragging.moved) {\n const el = elementsRef.current.find((x) => x.id === s.dragging?.id);\n if (el) {\n onMoveEnd([{ id: el.id, x: el.x || 0, y: el.y || 0 }]);\n }\n }\n s.dragging = null;\n }\n if (s.connecting) {\n s.connecting = null;\n innerRef.current?.dispatchEvent(new CustomEvent('canvas-move', { detail: { x: 0, y: 0 } }));\n }\n };\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n const next = Math.min(\n Math.max(stateRef.current.scale * delta, 0.25),\n 2.5,\n );\n stateRef.current.scale = next;\n apply();\n };\n root.addEventListener('mousedown', onMouseDown);\n window.addEventListener('mousemove', onMouseMove);\n window.addEventListener('mouseup', onMouseUp);\n root.addEventListener('wheel', onWheel, { passive: false });\n return () => {\n root.removeEventListener('mousedown', onMouseDown);\n window.removeEventListener('mousemove', onMouseMove);\n window.removeEventListener('mouseup', onMouseUp);\n root.removeEventListener('wheel', onWheel);\n };\n }, [onMoveElement, onMoveEnd, onSelect]);\n\n const fitToView = () => {\n if (!rootRef.current || canvas.elements.length === 0) {\n stateRef.current.ox = 0;\n stateRef.current.oy = 0;\n stateRef.current.scale = 1;\n const inner = innerRef.current;\n if (inner) {\n inner.style.transform = `translate(0px, 0px) scale(1)`;\n }\n return;\n }\n const bbox = canvas.elements.reduce(\n (acc, el) => {\n const ex = el.x || 0;\n const ey = el.y || 0;\n const ex2 = ex + (el.width || 240);\n const ey2 = ey + (el.height || 120);\n return {\n minX: Math.min(acc.minX, ex),\n minY: Math.min(acc.minY, ey),\n maxX: Math.max(acc.maxX, ex2),\n maxY: Math.max(acc.maxY, ey2),\n };\n },\n { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },\n );\n const pad = 80;\n const root = rootRef.current;\n const w = root.clientWidth - pad * 2;\n const h = root.clientHeight - pad * 2;\n const bw = bbox.maxX - bbox.minX;\n const bh = bbox.maxY - bbox.minY;\n const scale = Math.min(w / Math.max(bw, 1), h / Math.max(bh, 1), 1.5);\n const ox = -bbox.minX * scale + pad;\n const oy = -bbox.minY * scale + pad;\n stateRef.current.ox = ox;\n stateRef.current.oy = oy;\n stateRef.current.scale = scale;\n const inner = innerRef.current;\n if (inner) {\n inner.style.transform = `translate(${ox}px, ${oy}px) scale(${scale})`;\n }\n };\n\n return (\n <div className=\"artifacts-canvas-wrap\">\n <div className=\"canvas-toolbar\">\n <button type=\"button\" className=\"icon-btn\" title=\"Fit to view\" aria-label=\"Fit canvas to view\" onClick={fitToView}>\n <Maximize2 size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n title=\"Reset zoom\"\n aria-label=\"Reset canvas zoom\"\n onClick={() => {\n stateRef.current.ox = 0;\n stateRef.current.oy = 0;\n stateRef.current.scale = 1;\n const inner = innerRef.current;\n if (inner) inner.style.transform = 'translate(0px, 0px) scale(1)';\n }}\n >\n <Circle size={14} />\n </button>\n <span className=\"muted text-sm\" style={{ marginLeft: 'auto' }}>\n Pan: drag empty · Zoom: scroll · Drag element header to move · Double-click to edit · Right-click element for actions\n </span>\n </div>\n <div className=\"canvas-root\" ref={rootRef} onContextMenu={(e) => {\n e.preventDefault();\n const rect = innerRef.current?.getBoundingClientRect();\n const s = stateRef.current;\n if (!rect) return;\n const worldPos = { x: (e.clientX - rect.left) / s.scale, y: (e.clientY - rect.top) / s.scale };\n onContextMenu?.(e, worldPos);\n }}>\n <div className=\"canvas-grid-bg\" />\n <div className=\"canvas-inner\" ref={innerRef}>\n {canvas.elements.length === 0 ? (\n <div className=\"canvas-empty\">\n <EmptyState\n icon={<MapIcon size={32} />}\n title=\"No elements yet\"\n message=\"Add an element from the toolbar above to get started.\"\n />\n </div>\n ) : (\n <>\n <ConnectionsLayer\n canvas={canvas}\n onDeleteConnection={onDeleteConnection}\n />\n {canvas.elements.map((el) => (\n <CanvasElementView\n key={el.id}\n element={el}\n selected={selectedElId === el.id}\n commentCount={canvas.comments.filter((c) => c.elementId === el.id).length}\n onSelect={() => onSelect(el.id)}\n onEdit={() => onEditElement(el)}\n onDelete={() => onDeleteElement(el.id)}\n onContextMenu={onElementContextMenu ? (e) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = innerRef.current?.getBoundingClientRect();\n if (!rect) return;\n const s = stateRef.current;\n const worldPos = { x: (e.clientX - rect.left) / s.scale, y: (e.clientY - rect.top) / s.scale };\n onElementContextMenu(e, el.id, worldPos);\n } : undefined}\n />\n ))}\n </>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction CanvasElementView({\n element,\n selected,\n commentCount,\n onSelect,\n onEdit,\n onDelete,\n onContextMenu,\n}: {\n element: CanvasElement;\n selected: boolean;\n commentCount: number;\n onSelect: () => void;\n onEdit: () => void;\n onDelete: () => void;\n onContextMenu?: (e: React.MouseEvent) => void;\n}) {\n const x = element.x || 0;\n const y = element.y || 0;\n const w = element.width || 240;\n const h = element.height || 120;\n const color = elementColor(element.type);\n return (\n <div\n className={cn('canvas-element', selected && 'canvas-element-selected')}\n data-element-id={element.id}\n style={{\n left: x,\n top: y,\n width: w,\n minHeight: h,\n borderColor: color,\n }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect();\n }}\n onDoubleClick={(e) => {\n e.stopPropagation();\n onEdit();\n }}\n onContextMenu={(e) => {\n if (onContextMenu) {\n e.stopPropagation();\n onContextMenu(e);\n } else {\n e.preventDefault();\n if (confirm(`Delete element \"${element.title || element.type}\"?`)) {\n onDelete();\n }\n }\n }}\n >\n <div className=\"canvas-element-head\" style={{ background: `color-mix(in srgb, ${color} 12%, transparent)` }}>\n <div className=\"canvas-element-type\">\n <ElementIcon type={element.type} size={12} />\n <span style={{ color }}>{element.type}</span>\n </div>\n <div className=\"canvas-element-actions\">\n {commentCount > 0 && (\n <span className=\"canvas-element-badge\" title={`${commentCount} comments`}>\n <MessageCircle size={10} />\n {commentCount}\n </span>\n )}\n <button type=\"button\" className=\"canvas-element-handle\" title=\"Drag to move\" aria-label=\"Drag\">\n ⋮⋮\n </button>\n </div>\n </div>\n <div className=\"canvas-element-title\">{element.title || 'Untitled'}</div>\n {element.content && (\n <div className=\"canvas-element-content\">{truncate(element.content, 240)}</div>\n )}\n {element.status && element.status !== 'open' && (\n <div className=\"canvas-element-status\">\n <StatusBadge kind={element.status === 'done' ? 'success' : element.status === 'blocked' ? 'error' : 'info'}>\n {element.status}\n </StatusBadge>\n </div>\n )}\n </div>\n );\n}\n\nfunction ConnectionsLayer({\n canvas,\n onDeleteConnection,\n}: {\n canvas: Canvas;\n onDeleteConnection: (id: string) => void;\n}) {\n if (canvas.connections.length === 0) return null;\n const els = canvas.elements;\n // Compute bounding box\n const bbox = els.reduce(\n (acc, el) => {\n const ex = el.x || 0;\n const ey = el.y || 0;\n const ex2 = ex + (el.width || 240);\n const ey2 = ey + (el.height || 120);\n return {\n minX: Math.min(acc.minX, ex),\n minY: Math.min(acc.minY, ey),\n maxX: Math.max(acc.maxX, ex2),\n maxY: Math.max(acc.maxY, ey2),\n };\n },\n { minX: 0, minY: 0, maxX: 0, maxY: 0 },\n );\n const pad = 80;\n const w = bbox.maxX - bbox.minX + pad * 2;\n const h = bbox.maxY - bbox.minY + pad * 2;\n const ox = -bbox.minX + pad;\n const oy = -bbox.minY + pad;\n return (\n <svg\n className=\"canvas-connections\"\n width={w}\n height={h}\n style={{ left: bbox.minX - pad, top: bbox.minY - pad }}\n >\n <defs>\n <marker id=\"artifact-arrow\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"6\" markerHeight=\"6\" orient=\"auto-start-reverse\">\n <path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--accent)\" />\n </marker>\n </defs>\n {canvas.connections.map((c) => {\n const from = els.find((e) => e.id === c.from || e.id === c.fromElementId);\n const to = els.find((e) => e.id === c.to || e.id === c.toElementId);\n if (!from || !to) return null;\n const x1 = ox + (from.x || 0) + (from.width || 240) / 2;\n const y1 = oy + (from.y || 0) + (from.height || 120);\n const x2 = ox + (to.x || 0) + (to.width || 240) / 2;\n const y2 = oy + (to.y || 0);\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n return (\n <g key={c.id} className=\"canvas-connection\" onClick={() => onDeleteConnection(c.id)}>\n <line x1={x1} y1={y1} x2={x2} y2={y2} stroke=\"var(--accent)\" strokeWidth={1.5} markerEnd=\"url(#artifact-arrow)\" />\n {c.label && (\n <text x={midX} y={midY} className=\"canvas-connection-label\" textAnchor=\"middle\">\n {c.label}\n </text>\n )}\n </g>\n );\n })}\n </svg>\n );\n}\n\n// ── Comments panel ────────────────────────────────────────────────────\n\nfunction CommentsPanel({\n slug,\n comments,\n selectedElId,\n onAdd,\n onDelete,\n onClose,\n}: {\n slug: string;\n comments: CanvasComment[];\n selectedElId: string | null;\n onAdd: (text: string) => void;\n onDelete: (cid: string) => void;\n onClose: () => void;\n}) {\n const [text, setText] = useState('');\n return (\n <aside className=\"artifacts-comments-panel\">\n <header className=\"artifacts-comments-panel-head\">\n <h3 className=\"card-title\">\n <MessageCircle size={14} />\n {selectedElId ? 'Element comments' : 'Canvas comments'}\n </h3>\n <button type=\"button\" className=\"icon-btn\" onClick={onClose} title=\"Close panel\" aria-label=\"Close\">\n <X size={14} />\n </button>\n </header>\n <div className=\"artifacts-comments-panel-list\">\n {comments.length === 0 ? (\n <p className=\"muted text-sm\" style={{ padding: 'var(--space-4)' }}>\n {selectedElId ? 'No comments on this element yet.' : 'No comments on this artifact yet.'}\n </p>\n ) : (\n comments.map((c) => (\n <div key={c.id} className=\"artifact-comment\">\n <div className=\"artifact-comment-head\">\n <span className=\"artifact-comment-author mono\">{c.author}</span>\n <span className=\"artifact-comment-time tabular-nums muted\">{formatRelative(c.created)}</span>\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n aria-label=\"Delete comment\"\n onClick={() => onDelete(c.id)}\n title=\"Delete\"\n >\n <Trash2 size={10} />\n </button>\n </div>\n <div className=\"artifact-comment-text\">{c.text}</div>\n </div>\n ))\n )}\n </div>\n <form\n className=\"artifacts-comments-panel-form\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!text.trim()) return;\n onAdd(text.trim());\n setText('');\n }}\n >\n <label htmlFor=\"artifacts-comment-input\" className=\"sr-only\">\n {selectedElId ? 'Add a comment to this element' : 'Add a canvas comment'}\n </label>\n <textarea\n id=\"artifacts-comment-input\"\n className=\"textarea\"\n rows={2}\n placeholder={selectedElId ? 'Add a comment to this element…' : 'Add a canvas comment…'}\n value={text}\n onChange={(e) => setText(e.target.value)}\n aria-label={selectedElId ? 'Add a comment to this element' : 'Add a canvas comment'}\n />\n <Button variant=\"primary\" size=\"sm\" type=\"submit\" disabled={!text.trim()}>\n <Send size={12} /> Post\n </Button>\n </form>\n </aside>\n );\n}\n","// src/components/Tag.tsx — pill for tags.\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../lib/utils';\n\nexport type TagProps = {\n children: ReactNode;\n className?: string;\n onRemove?: () => void;\n};\n\nexport function Tag({ children, className, onRemove }: TagProps) {\n return (\n <span className={cn('tag', className)}>\n {children}\n {onRemove && (\n <button\n type=\"button\"\n className=\"tag-remove\"\n aria-label={`Remove ${typeof children === 'string' ? children : 'tag'}`}\n onClick={onRemove}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n","// src/web/components/tasks/BacklogPanel.tsx — v3.22\n// Backlog panel: lists parked tasks, promote individually or all-at-once.\nimport { useEffect, useState } from 'react';\nimport {\n ArrowUp,\n Trash2,\n Sparkles,\n RefreshCw,\n Inbox,\n} from 'lucide-react';\nimport { Button } from '../Button';\nimport { useToast } from '../Toast';\nimport { api } from '../../lib/api';\nimport { formatRelative } from '../../lib/utils';\nimport type { Task, Agent } from '../../lib/types';\n\ntype BacklogItemProps = {\n task: Task;\n agents: Agent[];\n onPromote: (id: string) => void;\n onDelete: (id: string) => void;\n onEdit: (task: Task) => void;\n onRefresh: () => Promise<void>;\n};\n\nfunction BacklogItem({ task, agents, onPromote, onDelete, onEdit, onRefresh }: BacklogItemProps) {\n const toast = useToast();\n\n const handlePromote = async () => {\n try {\n await api.post(`/tasks/${encodeURIComponent(task.id)}/promote`);\n toast.success('Promoted to queued.', 1500);\n onPromote(task.id);\n } catch (err) {\n toast.error(`Promote failed: ${(err as Error).message}`);\n }\n };\n\n const handleDelete = async () => {\n if (!confirm('Delete this task?')) return;\n try {\n await api.del(`/tasks/${encodeURIComponent(task.id)}`);\n toast.success('Deleted.', 1500);\n onDelete(task.id);\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const priorityDot: Record<string, string> = {\n high: 'var(--warning)',\n normal: 'var(--info)',\n low: 'var(--muted)',\n };\n\n return (\n <div className=\"backlog-item\" data-task-id={task.id}>\n <div className=\"backlog-item-head\">\n <span\n className=\"priority-dot\"\n style={{ background: priorityDot[task.priority] || 'var(--info)' }}\n />\n <span className=\"backlog-item-title\">{task.title}</span>\n {task.assignee && (\n <span className=\"backlog-item-badge\">@{task.assignee}</span>\n )}\n {task.tags?.length > 0 && (\n <span className=\"backlog-item-badge\">{task.tags.join(', ')}</span>\n )}\n </div>\n {task.description && (\n <div className=\"backlog-item-desc\">{task.description.slice(0, 120)}</div>\n )}\n <div className=\"backlog-item-footer\">\n <span className=\"muted text-sm tabular-nums\">\n {formatRelative(task.createdAt)}\n </span>\n <div className=\"backlog-item-actions\">\n <button\n type=\"button\"\n className=\"icon-btn\"\n title=\"Promote to queued\"\n onClick={handlePromote}\n >\n <ArrowUp size={13} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n title=\"Edit\"\n onClick={() => onEdit(task)}\n >\n <Sparkles size={13} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n title=\"Delete\"\n onClick={handleDelete}\n >\n <Trash2 size={13} />\n </button>\n </div>\n </div>\n </div>\n );\n}\n\ntype Props = {\n /** Current list of agents for the edit modal. */\n agents: Agent[];\n /** Called after any mutation so the parent can refresh snapshot. */\n onRefresh: () => Promise<void>;\n};\n\nexport function BacklogPanel({ agents, onRefresh }: Props) {\n const toast = useToast();\n const [tasks, setTasks] = useState<Task[]>([]);\n const [loading, setLoading] = useState(false);\n\n const load = async () => {\n try {\n setLoading(true);\n const r = await api.get<{ tasks: Task[] }>('/tasks/backlog');\n setTasks(Array.isArray(r.tasks) ? r.tasks : []);\n } catch (err) {\n toast.error(`Backlog load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => { load(); }, []);\n\n const handlePromote = async (id: string) => {\n setTasks((cur) => cur.filter((t) => t.id !== id));\n await onRefresh();\n };\n\n const handleDelete = async (id: string) => {\n setTasks((cur) => cur.filter((t) => t.id !== id));\n await onRefresh();\n };\n\n const handleEdit = (_task: Task) => {\n // Editing is wired through the parent Tasks view's modal helper.\n // Keep this no-op so the icon click is at least visible; the parent\n // provides the real edit affordance via the kanban.\n };\n\n const handlePromoteAll = async () => {\n if (tasks.length === 0) return;\n try {\n const r = await api.post<{ affected: { id: string; ok: boolean }[] }>('/tasks/promote-batch', {\n ids: tasks.map((t) => t.id),\n });\n const ok = r.affected?.filter((a) => a.ok).length ?? 0;\n toast.success(`Promoted ${ok} task(s).`, 2000);\n setTasks([]);\n await onRefresh();\n } catch (err) {\n toast.error(`Promote all failed: ${(err as Error).message}`);\n }\n };\n\n return (\n <div className=\"backlog-panel\">\n <div className=\"backlog-panel-header\">\n <span className=\"backlog-panel-title\">\n <Inbox size={15} />\n Backlog ({tasks.length})\n </span>\n <div className=\"backlog-panel-header-actions\">\n {tasks.length > 0 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={handlePromoteAll} title=\"Promote all to queued\">\n <ArrowUp size={12} /> Promote all\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" onClick={load} title=\"Refresh backlog\" aria-label=\"Refresh backlog\">\n <RefreshCw size={12} className={loading ? 'animate-spin' : ''} />\n </Button>\n </div>\n </div>\n\n {loading ? (\n <div className=\"backlog-empty\">Loading…</div>\n ) : tasks.length === 0 ? (\n <div className=\"backlog-empty\">\n <Inbox size={28} />\n <span>Backlog is empty.</span>\n </div>\n ) : (\n <div className=\"backlog-list\">\n {tasks.map((t) => (\n <BacklogItem\n key={t.id}\n task={t}\n agents={agents}\n onPromote={handlePromote}\n onDelete={handleDelete}\n onEdit={handleEdit}\n onRefresh={onRefresh}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","// src/views/Tasks.tsx\n//\n// v4.6.0 — Simplified task board.\n//\n// Design goals (per Odin):\n// - Create flow = title + description (+ optional priority hint + tags).\n// No agent picker. Odin decides what to do with the task and which\n// agent picks it up; the UI just records intent.\n// - Tasks grouped by status into 5 columns:\n// Todo (api: queued)\n// In progress (api: doing)\n// Done (api: done)\n// Failed (api: blocked)\n// Backlog (api: backlog, parked ideas)\n// - Each task row shows title, status, priority, createdAt, and the\n// agent that auto-claimed it (read-only — set by the orchestrator).\n// - Per-task actions: edit, delete, retry, change status.\n// - Backlog view: parked ideas; one-click \"promote to Todo\".\n//\n// We keep the API contract (statuses: queued/doing/done/blocked/backlog)\n// so the dashboard doesn't break the existing server, tasks store, and\n// tests. The UI maps API statuses to friendlier labels.\nimport React, { useEffect, useMemo, useState } from 'react';\nimport {\n CheckSquare,\n Plus,\n Trash2,\n ChevronLeft,\n ChevronRight,\n Search,\n X as XIcon,\n Clock,\n Tag as TagIcon,\n ArchiveRestore,\n RefreshCw,\n Send,\n Inbox,\n Edit2,\n RotateCw,\n Bot,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Spinner } from '../components/Spinner';\nimport { Tag } from '../components/Tag';\nimport { useModal } from '../components/Modal';\nimport { useToast } from '../components/Toast';\nimport { api, enhancePrompt } from '../lib/api';\nimport { cn, formatRelative, priorityColors } from '../lib/utils';\nimport type { Settings, Snapshot, Task } from '../lib/types';\nimport { BacklogPanel } from '../components/tasks/BacklogPanel';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype StatusKind = 'info' | 'accent' | 'success' | 'warning' | 'error';\n\n/**\n * UI <-> API status mapping. We keep the existing API enum\n * (queued | doing | done | blocked | archived | backlog) and only\n * rename the labels here so the dashboard, server, and tests stay in\n * sync. Switch back if you need to expose the raw API value.\n */\nconst COLUMNS: { id: Task['status']; label: string; kind: StatusKind }[] = [\n { id: 'queued', label: 'Todo', kind: 'info' },\n { id: 'doing', label: 'In progress', kind: 'accent' },\n { id: 'done', label: 'Done', kind: 'success' },\n { id: 'blocked', label: 'Failed', kind: 'error' },\n];\n\nconst PRIORITIES = ['low', 'normal', 'high'] as const;\ntype Priority = (typeof PRIORITIES)[number];\n\nfunction TasksInner({ snapshot, refreshSnapshot, setActiveTab }: Props) {\n const toast = useToast();\n const modal = useModal();\n const [tasks, setTasks] = useState<Task[]>(snapshot.tasks || []);\n const [loading, setLoading] = useState(!snapshot.tasks);\n const [filter, setFilter] = useState('');\n const [priorityFilter, setPriorityFilter] = useState<string>('');\n const [showBacklog, setShowBacklog] = useState(false);\n const [tick, setTick] = useState(0); // for live timer re-render\n const [statusAnnouncement, setStatusAnnouncement] = useState('');\n\n const reload = async () => {\n try {\n const data = await api.get<Task[]>('/tasks');\n setTasks(Array.isArray(data) ? data : []);\n } catch (err) {\n toast.error(`Tasks load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n if (snapshot.tasks) {\n setTasks(snapshot.tasks);\n setLoading(false);\n }\n }, [snapshot.tasks]);\n\n // Periodic tick keeps relative-time labels fresh without a full reload.\n useEffect(() => {\n const id = setInterval(() => setTick((t) => t + 1), 30_000);\n return () => clearInterval(id);\n }, []);\n\n const filtered = useMemo(() => {\n let out = tasks.filter((t) => t.status !== 'backlog');\n if (priorityFilter) {\n out = out.filter((t) => (t.priority || 'normal') === priorityFilter);\n }\n if (filter.trim()) {\n const q = filter.toLowerCase();\n out = out.filter((t) =>\n (t.title || '').toLowerCase().includes(q) ||\n (t.description || '').toLowerCase().includes(q),\n );\n }\n return out;\n }, [tasks, filter, priorityFilter]);\n\n const sorted = useMemo(() => {\n const priorityWeight = { high: 0, normal: 1, low: 2 } as Record<string, number>;\n return [...filtered].sort((a, b) => {\n const pa = priorityWeight[a.priority] ?? 1;\n const pb = priorityWeight[b.priority] ?? 1;\n if (pa !== pb) return pa - pb;\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n });\n }, [filtered]);\n\n const backlogCount = tasks.filter((t) => t.status === 'backlog').length;\n\n // ─── Actions ─────────────────────────────────────────────────────────────\n\n const moveTask = async (taskId: string, newStatus: string) => {\n const t = tasks.find((x) => x.id === taskId);\n if (!t) return;\n const prev = t.status;\n setTasks((cur) =>\n cur.map((x) => (x.id === taskId ? { ...x, status: newStatus } : x)),\n );\n setStatusAnnouncement(`Task ${t.title} moved to ${newStatus}.`);\n try {\n await api.patch(`/tasks/${encodeURIComponent(taskId)}/status`, {\n status: newStatus,\n });\n toast.success(`Moved to ${newStatus}.`, 1200);\n } catch (err) {\n setTasks((cur) =>\n cur.map((x) => (x.id === taskId ? { ...x, status: prev } : x)),\n );\n setStatusAnnouncement(`Failed to move task ${t.title}: ${(err as Error).message}`);\n toast.error(`Move failed: ${(err as Error).message}`);\n }\n };\n\n const deleteTask = async (taskId: string) => {\n if (!confirm('Delete this task?')) return;\n try {\n await api.del(`/tasks/${encodeURIComponent(taskId)}`);\n setTasks((cur) => cur.filter((t) => t.id !== taskId));\n toast.success('Task deleted.', 1200);\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const retryTask = async (taskId: string) => {\n try {\n // Re-dispatch via the existing /tasks/:id/start endpoint. The\n // server returns 202 on accept; failures surface as 502/404.\n const r = await api.post<{ ok: boolean; task: Task }>(\n `/tasks/${encodeURIComponent(taskId)}/start`,\n );\n if (r && r.task) {\n setTasks((cur) => cur.map((t) => (t.id === taskId ? r.task : t)));\n }\n toast.success('Retry dispatched.', 1200);\n } catch (err) {\n toast.error(`Retry failed: ${(err as Error).message}`);\n }\n };\n\n const submitToOdin = async (taskId: string) => {\n const t = tasks.find((x) => x.id === taskId);\n if (!t) return;\n try {\n // The /tasks/submit endpoint takes a title + description and\n // hands the bundle to Odin for delegation. We re-use the task's\n // existing fields.\n const r = await api.post<{ main: Task; subtasks: Task[] }>('/tasks/submit', {\n title: t.title,\n description: t.description,\n priority: t.priority,\n tags: t.tags,\n });\n const count = (r.subtasks || []).length;\n toast.success(\n count > 1\n ? `Odin split it into ${count} subtasks.`\n : 'Sent to Odin.',\n 1500,\n );\n if (r.subtasks && r.subtasks.length > 0) {\n setTasks((cur) => [r.main, ...r.subtasks, ...cur.filter((x) => x.id !== t.id)]);\n }\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Submit failed: ${(err as Error).message}`);\n }\n };\n\n return (\n <div className=\"view view-tasks\">\n {/* Hidden live region for screen-reader announcements of status changes. */}\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {statusAnnouncement}\n </div>\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <CheckSquare size={18} /> Tasks ({sorted.length})\n </h2>\n <p className=\"view-subtitle\">\n Add a task — title and description is all you need. Odin picks the agent and priority.\n </p>\n </div>\n </header>\n\n {/* Toolbar: search, filter, sort, actions */}\n <div className=\"tasks-toolbar\">\n <div className=\"tasks-toolbar-group\">\n <div className=\"search-input\" style={{ width: 200 }}>\n <Search size={12} aria-hidden />\n <input\n className=\"input\"\n type=\"text\"\n placeholder=\"Search…\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n aria-label=\"Search tasks\"\n />\n {filter && (\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Clear search\"\n onClick={() => setFilter('')}\n >\n <XIcon size={12} />\n </button>\n )}\n </div>\n </div>\n\n <div className=\"tasks-toolbar-divider\" />\n\n <div className=\"tasks-toolbar-group\">\n <label className=\"tasks-toolbar-label\" htmlFor=\"tasks-priority-filter\">Priority</label>\n <select\n id=\"tasks-priority-filter\"\n className=\"select select-sm\"\n value={priorityFilter}\n onChange={(e) => setPriorityFilter(e.target.value)}\n title=\"Filter by priority\"\n >\n <option value=\"\">All</option>\n {PRIORITIES.map((p) => (\n <option key={p} value={p}>{p}</option>\n ))}\n </select>\n </div>\n\n <div className=\"tasks-toolbar-spacer\" />\n\n <div className=\"tasks-toolbar-group\">\n <Button variant=\"ghost\" size=\"sm\" onClick={reload} title=\"Refresh\" aria-label=\"Refresh tasks\">\n <RefreshCw size={14} />\n </Button>\n {backlogCount > 0 && (\n <Button\n variant={showBacklog ? 'accent' : 'ghost'}\n size=\"sm\"\n onClick={() => setShowBacklog((v) => !v)}\n title={showBacklog ? 'Hide backlog' : 'Show backlog'}\n >\n <Inbox size={14} />\n Backlog\n <span className=\"badge\">{backlogCount}</span>\n </Button>\n )}\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => openCreateTaskModal(modal, toast, setTasks, reload, refreshSnapshot)}\n >\n <Plus size={14} /> New task\n </Button>\n </div>\n </div>\n\n {showBacklog && backlogCount > 0 && (\n <BacklogPanel\n agents={snapshot.agents || []}\n onRefresh={refreshSnapshot}\n />\n )}\n\n {loading ? (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n ) : (\n <div className=\"kanban\">\n {COLUMNS.map((col) => (\n <KanbanColumn\n key={col.id}\n column={col}\n tasks={sorted.filter((t) => t.status === col.id)}\n onMove={moveTask}\n onDelete={deleteTask}\n onRetry={retryTask}\n onEdit={(t) => openEditTaskModal(modal, toast, t, setTasks, reload, refreshSnapshot)}\n onSubmitToOdin={submitToOdin}\n tick={tick}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Column ────────────────────────────────────────────────────────────────\n\nfunction KanbanColumn({\n column,\n tasks,\n onMove,\n onDelete,\n onRetry,\n onEdit,\n onSubmitToOdin,\n tick,\n}: {\n column: { id: string; label: string; kind: StatusKind };\n tasks: Task[];\n onMove: (id: string, status: string) => void;\n onDelete: (id: string) => void;\n onRetry: (id: string) => void;\n onEdit: (t: Task) => void;\n onSubmitToOdin: (id: string) => void;\n tick: number;\n}) {\n const [dragOver, setDragOver] = useState(false);\n return (\n <div\n className={cn('kanban-column', dragOver && 'kanban-column-drop')}\n data-column={column.id}\n onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}\n onDragLeave={() => setDragOver(false)}\n onDrop={(e) => {\n e.preventDefault();\n setDragOver(false);\n const id = e.dataTransfer.getData('text/task-id');\n if (id) onMove(id, column.id);\n }}\n >\n <div className=\"kanban-col-header\">\n <CardTitle>\n <span className={cn('status-dot', `status-${column.kind}`)} />\n {column.label}\n </CardTitle>\n <span className=\"kanban-col-count tabular-nums\">{tasks.length}</span>\n </div>\n <div className=\"kanban-col-body\">\n {tasks.length === 0 ? (\n <div className=\"kanban-empty\">No tasks</div>\n ) : (\n tasks.map((t) => (\n <TaskCard\n key={t.id}\n task={t}\n onMove={(dir) => {\n const idx = COLUMNS.findIndex((c) => c.id === t.status);\n const next = idx + dir;\n if (next >= 0 && next < COLUMNS.length) onMove(t.id, COLUMNS[next].id);\n }}\n onEdit={() => onEdit(t)}\n onDelete={() => onDelete(t.id)}\n onRetry={() => onRetry(t.id)}\n onSubmitToOdin={() => onSubmitToOdin(t.id)}\n tick={tick}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n\n// ─── Card ──────────────────────────────────────────────────────────────────\n\nfunction TaskCard({\n task,\n onMove,\n onEdit,\n onDelete,\n onRetry,\n onSubmitToOdin,\n tick,\n}: {\n task: Task;\n onMove: (dir: -1 | 1) => void;\n onEdit: () => void;\n onDelete: () => void;\n onRetry: () => void;\n onSubmitToOdin: () => void;\n tick: number;\n}) {\n const assignedAgent = task.workedBy || task.assignee || null;\n return (\n <div\n className={cn('task-card', `priority-${task.priority}`)}\n data-task-id={task.id}\n draggable\n onDragStart={(e) => {\n e.dataTransfer.setData('text/task-id', task.id);\n e.dataTransfer.effectAllowed = 'move';\n }}\n data-tick={tick}\n >\n <div className=\"task-card-head\">\n <span\n className=\"priority-dot\"\n style={{ background: priorityColors[task.priority] || 'var(--info)' }}\n />\n <div className=\"task-card-title\">{task.title}</div>\n </div>\n {task.description && (\n <div className=\"task-card-desc\">{task.description.slice(0, 160)}</div>\n )}\n <div className=\"task-card-badges\">\n {assignedAgent && (\n <span className=\"task-card-badge\" title={`Auto-assigned to @${assignedAgent}`}>\n <Bot size={10} /> @{assignedAgent}\n </span>\n )}\n {task.timeSpent ? (\n <span className=\"task-card-badge\">\n <Clock size={10} /> {Math.round((task.timeSpent || 0) / 60)}m\n </span>\n ) : null}\n {task.tags && task.tags.length > 0 && task.tags.slice(0, 3).map((tag) => (\n <Tag key={tag}>{tag}</Tag>\n ))}\n </div>\n <div className=\"task-card-footer\">\n <span className=\"task-card-time tabular-nums muted\">\n {formatRelative(task.createdAt)}\n </span>\n <div className=\"task-card-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Move left\"\n title=\"Move left\"\n onClick={() => onMove(-1)}\n >\n <ChevronLeft size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Edit\"\n title=\"Edit\"\n onClick={onEdit}\n >\n <Edit2 size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Submit to Odin\"\n title=\"Re-delegate to Odin\"\n onClick={onSubmitToOdin}\n >\n <Send size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Retry\"\n title=\"Retry\"\n onClick={onRetry}\n >\n <RotateCw size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n aria-label=\"Delete\"\n title=\"Delete\"\n onClick={onDelete}\n >\n <Trash2 size={14} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Move right\"\n title=\"Move right\"\n onClick={() => onMove(1)}\n >\n <ChevronRight size={14} />\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n// ─── Create / Edit modal ───────────────────────────────────────────────────\n//\n// Simplified: title, description, priority hint, optional tags. NO\n// agent dropdown. The store will default `assignee` and `workedBy` to\n// null; the orchestrator sets them when it picks the task up.\n\nfunction openCreateTaskModal(\n modal: ReturnType<typeof useModal>,\n toast: ReturnType<typeof useToast>,\n setTasks: (updater: (cur: Task[]) => Task[]) => void,\n reload: () => Promise<void>,\n refreshSnapshot: () => Promise<void>,\n) {\n let titleEl: HTMLInputElement | null = null;\n let descEl: HTMLTextAreaElement | null = null;\n let tagsEl: HTMLInputElement | null = null;\n let priorityEl: HTMLSelectElement | null = null;\n\n const submit = async (e?: React.SyntheticEvent) => {\n if (e && typeof e.preventDefault === 'function') e.preventDefault();\n const title = (titleEl?.value || '').trim();\n const description = (descEl?.value || '').trim();\n if (!title) {\n toast.warning('Title is required.');\n titleEl?.focus();\n return;\n }\n const priority = (priorityEl?.value || 'normal') as Priority;\n const tags = (tagsEl?.value || '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n\n try {\n const created = await api.post<Task>('/tasks', {\n title,\n description,\n priority,\n tags,\n // No assignee / agent — Odin decides.\n });\n modal.close();\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new MouseEvent('mousedown'));\n }\n setTasks((cur) => [created, ...cur]);\n toast.success('Task created.', 1200);\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Create failed: ${(err as Error).message}`);\n }\n };\n\n const onTitleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n submit(e);\n }\n };\n\n modal.open({\n title: 'New task',\n width: 520,\n children: (\n <div className=\"task-form\">\n <label className=\"field-label\" htmlFor=\"task-title\">Title *</label>\n <input\n ref={(el) => { titleEl = el; }}\n id=\"task-title\"\n className=\"input\"\n type=\"text\"\n maxLength={200}\n placeholder=\"What needs to be done?\"\n autoFocus\n onKeyDown={onTitleKeyDown}\n />\n <label className=\"field-label\" htmlFor=\"task-desc\">Description</label>\n <div style={{ display: 'flex', gap: 6, alignItems: 'flex-start' }}>\n <textarea\n ref={(el) => { descEl = el; }}\n id=\"task-desc\"\n className=\"textarea\"\n rows={4}\n placeholder=\"Add any context Odin might need (markdown ok)…\"\n style={{ flex: 1 }}\n />\n <button\n type=\"button\"\n className=\"btn btn-ghost btn-icon\"\n title=\"Enhance with AI\"\n onClick={async () => {\n if (!descEl?.value?.trim()) return;\n const enhanced = await enhancePrompt(descEl.value);\n if (enhanced !== descEl.value) descEl.value = enhanced;\n }}\n >\n ✨\n </button>\n </div>\n <div className=\"task-form-row\">\n <label htmlFor=\"task-priority\" className=\"task-form-field\">\n Priority hint\n <select\n ref={(el) => { priorityEl = el; }}\n id=\"task-priority\"\n className=\"select\"\n defaultValue=\"normal\"\n >\n {PRIORITIES.map((p) => (\n <option key={p} value={p}>{p}</option>\n ))}\n </select>\n </label>\n <label htmlFor=\"task-tags\" className=\"task-form-field\" style={{ flex: 2 }}>\n Tags <span className=\"field-hint\">(comma-separated)</span>\n <input\n ref={(el) => { tagsEl = el; }}\n id=\"task-tags\"\n className=\"input\"\n type=\"text\"\n placeholder=\"bug, frontend, urgent\"\n />\n </label>\n </div>\n <p className=\"muted text-sm\" style={{ marginTop: 8 }}>\n The agent and final priority are decided by Odin after you submit.\n </p>\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button variant=\"primary\" type=\"button\" onClick={(e) => submit(e)}>\n <Plus size={14} /> Create task\n </Button>\n </div>\n ),\n });\n}\n\nfunction openEditTaskModal(\n modal: ReturnType<typeof useModal>,\n toast: ReturnType<typeof useToast>,\n task: Task,\n setTasks: (updater: (cur: Task[]) => Task[]) => void,\n reload: () => Promise<void>,\n refreshSnapshot: () => Promise<void>,\n) {\n let titleEl: HTMLInputElement | null = null;\n let descEl: HTMLTextAreaElement | null = null;\n let tagsEl: HTMLInputElement | null = null;\n let priorityEl: HTMLSelectElement | null = null;\n\n const submit = async () => {\n const title = (titleEl?.value || '').trim();\n const description = (descEl?.value || '').trim();\n if (!title) {\n toast.warning('Title is required.');\n titleEl?.focus();\n return;\n }\n const priority = (priorityEl?.value || 'normal') as Priority;\n const tags = (tagsEl?.value || '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n\n try {\n const updated = await api.put<Task>(`/tasks/${encodeURIComponent(task.id)}`, {\n title,\n description,\n priority,\n tags,\n });\n modal.close();\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new MouseEvent('mousedown'));\n }\n setTasks((cur) => cur.map((x) => (x.id === task.id ? updated : x)));\n toast.success('Task updated.', 1200);\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n };\n\n modal.open({\n title: 'Edit task',\n width: 520,\n children: (\n <div className=\"task-form\">\n <label className=\"field-label\" htmlFor=\"edit-task-title\">Title *</label>\n <input\n ref={(el) => { titleEl = el; }}\n id=\"edit-task-title\"\n className=\"input\"\n type=\"text\"\n maxLength={200}\n defaultValue={task.title}\n autoFocus\n />\n <label className=\"field-label\" htmlFor=\"edit-task-desc\">Description</label>\n <textarea\n ref={(el) => { descEl = el; }}\n id=\"edit-task-desc\"\n className=\"textarea\"\n rows={4}\n defaultValue={task.description || ''}\n />\n <div className=\"task-form-row\">\n <label htmlFor=\"edit-task-priority\" className=\"task-form-field\">\n Priority hint\n <select\n ref={(el) => { priorityEl = el; }}\n id=\"edit-task-priority\"\n className=\"select\"\n defaultValue={task.priority || 'normal'}\n >\n {PRIORITIES.map((p) => (\n <option key={p} value={p}>{p}</option>\n ))}\n </select>\n </label>\n <label htmlFor=\"edit-task-tags\" className=\"task-form-field\" style={{ flex: 2 }}>\n Tags\n <input\n ref={(el) => { tagsEl = el; }}\n id=\"edit-task-tags\"\n className=\"input\"\n type=\"text\"\n defaultValue={(task.tags || []).join(', ')}\n placeholder=\"comma-separated\"\n />\n </label>\n </div>\n <Card>\n <CardTitle><TagIcon size={12} /> Status</CardTitle>\n <CardMeta>\n Current: <strong>{task.status}</strong>\n {task.workedBy && <> · Worked by @{task.workedBy}</>}\n {task.assignee && !task.workedBy && <> · Assigned @{task.assignee}</>}\n </CardMeta>\n </Card>\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button variant=\"primary\" onClick={submit}>\n <ArchiveRestore size={14} /> Save\n </Button>\n </div>\n ),\n });\n}\nexport const Tasks = React.memo(TasksInner);\n","// src/web/components/ArtifactViewer.tsx — modal viewer for rendered HTML artifacts.\nimport { useEffect, useState } from 'react';\nimport { X, ExternalLink, Download, FileText } from 'lucide-react';\nimport { useModal } from './Modal';\nimport { Spinner } from './Spinner';\nimport { api } from '../lib/api';\n\ntype ArtifactMeta = {\n id: string;\n name: string;\n contentType: string;\n size: number;\n createdAt: string;\n};\n\ntype Props = {\n artifactId: string;\n onClose: () => void;\n};\n\nexport function ArtifactViewer({ artifactId, onClose }: Props) {\n const [meta, setMeta] = useState<ArtifactMeta | null>(null);\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n setLoading(true);\n try {\n const [metaData, contentData] = await Promise.all([\n api.get<ArtifactMeta>(`/artifacts/${encodeURIComponent(artifactId)}`),\n fetchRawContent(artifactId),\n ]);\n if (!cancelled) {\n setMeta(metaData);\n setContent(contentData);\n }\n } catch (err) {\n if (!cancelled) {\n console.error('Failed to load artifact:', err);\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => { cancelled = true; };\n }, [artifactId]);\n\n return (\n <div className=\"modal-backdrop\" onClick={(e) => { e.stopPropagation(); if (e.target === e.currentTarget) onClose(); }}>\n <div className=\"modal artifact-viewer-modal\" role=\"dialog\" aria-modal=\"true\">\n <header className=\"modal-header\">\n <div className=\"modal-title-group\">\n <FileText size={16} />\n <h2 className=\"modal-title\">{meta?.name || 'Artifact'}</h2>\n {meta && (\n <span className=\"artifact-viewer-meta muted\">\n {meta.contentType} · {formatBytes(meta.size)}\n </span>\n )}\n </div>\n <div className=\"modal-header-actions\">\n {meta && (\n <>\n <a\n href={getArtifactContentUrl(artifactId)}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"icon-btn\"\n aria-label=\"Open artifact in new tab\"\n title=\"Open in new tab\"\n >\n <ExternalLink size={16} />\n </a>\n <a\n href={getArtifactContentUrl(artifactId)}\n download={meta.name || 'artifact.html'}\n className=\"icon-btn\"\n aria-label=\"Download artifact\"\n title=\"Download\"\n >\n <Download size={16} />\n </a>\n </>\n )}\n <button type=\"button\" className=\"icon-btn\" aria-label=\"Close\" onClick={onClose}>\n <X size={16} />\n </button>\n </div>\n </header>\n <div className=\"modal-body artifact-viewer-body\">\n {loading ? (\n <div className=\"artifact-viewer-loading\">\n <Spinner />\n <span className=\"muted\">Loading artifact…</span>\n </div>\n ) : content ? (\n <iframe\n srcDoc={content}\n className=\"artifact-viewer-iframe\"\n sandbox=\"allow-scripts allow-forms allow-popups allow-same-origin\"\n title={meta?.name || 'Artifact'}\n />\n ) : (\n <div className=\"artifact-viewer-empty muted\">\n <FileText size={32} />\n <p>No content available.</p>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// Fetch raw text content — bypasses the JSON api wrapper.\nasync function fetchRawContent(artifactId: string): Promise<string> {\n const r = await fetch(getArtifactContentUrl(artifactId));\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.text();\n}\n\nfunction getArtifactContentUrl(artifactId: string): string {\n return api.urlWithToken(`/artifacts/${encodeURIComponent(artifactId)}/content`);\n}\n\n// v3.5.7 — Open the artifact in a new browser tab at full window size.\n// The artifact's own HTML renders edge-to-edge, which is what users want\n// for visual artifacts (they're meant to be viewed, not crammed in a modal).\nexport function openArtifactViewer(\n _modal: ReturnType<typeof useModal>,\n artifactId: string,\n): void {\n const url = getArtifactContentUrl(artifactId);\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n","// src/views/Activity.tsx — v3.5.4: timeline-based activity view (replaces the v3.5.2 graph+strip hybrid).\n// Layout: CSS grid with 3 sibling columns — left event stream, center timeline canvas, right detail panel.\n// X axis is time; Y axis is lanes (BG instances + tasks). Active tasks pulse; queued tasks are translucent\n// dashed; done tasks are faded. A red \"now\" line updates every 1s and re-anchors when it nears the right edge.\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n Activity as ActivityIcon,\n Bot,\n CheckSquare,\n Cpu,\n RefreshCw,\n Send,\n X,\n Plus,\n Trash2,\n MessageSquare,\n History,\n Pause,\n Play,\n PanelLeftClose,\n PanelLeftOpen,\n Layers,\n Target,\n FileText,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card, CardTitle } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { VirtualList } from '../components/VirtualList';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\nimport type { Settings, Snapshot, Task, Agent } from '../lib/types';\nimport { openArtifactViewer } from '../components/ArtifactViewer';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype BgInstance = {\n instanceId: string;\n agent?: string;\n status?: string;\n startedAt?: number;\n completedAt?: number;\n lastEventAt?: number;\n promptPreview?: string;\n resultPreview?: string;\n error?: string;\n parentAgent?: string;\n parentInstanceId?: string;\n tmuxSession?: string;\n tmuxActive?: boolean;\n taskId?: string; // v3.6.2 — linked task for artifact lookup\n _bgDir?: string;\n};\n\ntype ActivityEvent = {\n ts: string;\n kind: string;\n nodeId?: string;\n text?: string;\n author?: string;\n taskId?: string;\n [k: string]: unknown;\n};\n\n// ─── Time / layout constants ──────────────────────────────────────────\n\nconst ZOOM_RANGES = {\n '1m': 60 * 1000,\n '5m': 5 * 60 * 1000,\n '30m': 30 * 60 * 1000,\n '1h': 60 * 60 * 1000,\n} as const;\ntype ZoomKey = keyof typeof ZOOM_RANGES;\n\nconst LANE_HEIGHT = 56;\nconst TIME_AXIS_HEIGHT = 32;\nconst EVENTS_STRIP_HEIGHT = 22;\nconst MIN_BAR_WIDTH = 4;\nconst REANCHOR_RATIO = 0.9; // when now_x exceeds this fraction of canvas width, re-anchor viewStart\n\n// ─── Status → color ───────────────────────────────────────────────────\n\nconst STATUS_COLORS: Record<string, string> = {\n working: 'var(--success)',\n running: 'var(--success)',\n doing: 'var(--info)',\n queued: 'var(--info)',\n done: 'var(--success)',\n success: 'var(--success)',\n blocked: 'var(--warning)',\n error: 'var(--error)',\n failed: 'var(--error)',\n stuck: 'var(--warning)',\n killed: 'var(--error)',\n idle: 'var(--text-dim)',\n pending: 'var(--info)',\n timed_out: 'var(--warning)',\n};\n\nfunction statusColor(s: string | null | undefined): string {\n if (!s) return STATUS_COLORS.idle;\n return STATUS_COLORS[s] || STATUS_COLORS.idle;\n}\n\nfunction shortLabel(s: string | null | undefined, n = 24): string {\n if (!s) return '';\n if (s.length <= n) return s;\n return s.slice(0, n - 1) + '…';\n}\n\n// ─── Time helpers ─────────────────────────────────────────────────────\n\nfunction parseTs(ts: string | number | null | undefined): number {\n if (ts == null) return 0;\n if (typeof ts === 'number') return ts;\n const t = new Date(ts).getTime();\n return Number.isNaN(t) ? 0 : t;\n}\n\nfunction taskStartMs(t: Task): number {\n // v3.5.4 — prefer _timerStart (set when work begins), fall back to createdAt.\n const ts = (t as { _timerStart?: number })._timerStart;\n if (typeof ts === 'number' && ts > 0) return ts;\n return parseTs(t.createdAt) || Date.now();\n}\n\nfunction taskEndMs(t: Task, now: number): number {\n if (t.status === 'done' || t.status === 'archived' || t.status === 'failed' || t.status === 'killed') {\n return parseTs(t.completedAt) || parseTs(t.updatedAt) || now;\n }\n // Active tasks: pin to now.\n return now;\n}\n\nfunction bgStartMs(b: BgInstance): number {\n return typeof b.startedAt === 'number' && b.startedAt > 0 ? b.startedAt : Date.now();\n}\n\nfunction bgEndMs(b: BgInstance, now: number): number {\n if (\n b.status === 'done'\n || b.status === 'success'\n || b.status === 'killed'\n || b.status === 'failed'\n || b.status === 'error'\n || b.status === 'timed_out'\n ) {\n return b.completedAt || b.lastEventAt || now;\n }\n return now;\n}\n\nfunction chooseTickStep(rangeMs: number): number {\n if (rangeMs <= 60_000) return 10_000;\n if (rangeMs <= 300_000) return 30_000;\n if (rangeMs <= 1_800_000) return 300_000;\n return 600_000;\n}\n\nfunction formatTickLabel(t: number, rangeMs: number): string {\n const d = new Date(t);\n if (rangeMs <= 300_000) {\n return d.toLocaleTimeString('en-GB', { hour12: false });\n }\n return d.toLocaleTimeString('en-GB', { hour12: false, hour: '2-digit', minute: '2-digit' });\n}\n\n// ─── Lane + tick types ────────────────────────────────────────────────\n\ntype Lane =\n | { kind: 'bg'; id: string; index: number; label: string; sub: string; start: number; end: number; data: BgInstance }\n | { kind: 'task'; id: string; index: number; label: string; sub: string; start: number; end: number; data: Task }\n | { kind: 'events'; id: string; index: number; label: string; sub: string; start: number; end: number };\n\ntype SelectedItem = {\n id: string;\n kind: 'task' | 'bg' | 'agent';\n label: string;\n status: string;\n data: Task | BgInstance | Agent;\n};\n\ntype EventMarker = {\n id: string;\n x: number;\n y: number;\n kind: string;\n ts: number;\n text: string;\n author?: string;\n};\n\ntype TaskBar = {\n id: string;\n laneIndex: number;\n x: number;\n y: number;\n w: number;\n h: number;\n label: string;\n statusClass: 'doing' | 'done' | 'queued' | 'blocked' | 'failed';\n selected: boolean;\n data: Task | BgInstance;\n kind: 'task' | 'bg';\n start: number;\n end: number;\n};\n\n// ─── Component ────────────────────────────────────────────────────────\n\nexport function Activity({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const canvasWrapRef = useRef<HTMLDivElement | null>(null);\n\n // View state\n const [mode, setMode] = useState<'live' | 'pause'>('live');\n const [zoom, setZoom] = useState<ZoomKey>('5m');\n const [streamOpen, setStreamOpen] = useState(() => {\n if (typeof window === 'undefined') return true;\n return window.innerWidth > 900;\n });\n\n // Data\n const [bgInstances, setBgInstances] = useState<BgInstance[]>([]);\n const [events, setEvents] = useState<ActivityEvent[]>([]);\n const [loading, setLoading] = useState(true);\n const [refreshTick, setRefreshTick] = useState(0);\n\n // Time\n const [nowTick, setNowTick] = useState<number>(Date.now());\n const [viewStart, setViewStart] = useState<number>(() => Date.now() - ZOOM_RANGES['5m'] * 0.1);\n\n // Canvas size (observed)\n const [canvasSize, setCanvasSize] = useState<{ width: number; height: number }>({ width: 800, height: 400 });\n\n // Selection / detail\n const [selectedItem, setSelectedItem] = useState<SelectedItem | null>(null);\n\n // Detail panel local state\n const [commentText, setCommentText] = useState('');\n const [comments, setComments] = useState<ActivityEvent[]>([]);\n const [taskTitle, setTaskTitle] = useState('');\n const [taskPriority, setTaskPriority] = useState('normal');\n const [bgMessage, setBgMessage] = useState('');\n const [bgOutput, setBgOutput] = useState('');\n const [creatingTask, setCreatingTask] = useState(false);\n const [postingComment, setPostingComment] = useState(false);\n // v3.6.2 — artifact IDs fetched from the task linked to the selected bg instance.\n const [bgArtifactIds, setBgArtifactIds] = useState<string[]>([]);\n\n const modal = useModal();\n\n const agents = snapshot.agents || [];\n const tasks = snapshot.tasks || [];\n const rangeMs = ZOOM_RANGES[zoom];\n const rangeStart = viewStart;\n const rangeEnd = viewStart + rangeMs;\n\n // ─── Data polling ───────────────────────────────────────────────────\n const reloadAll = useCallback(async () => {\n try {\n const [bgRes, evRes] = await Promise.all([\n api.get<{ instances: BgInstance[] }>('/background').catch(() => ({ instances: [] })),\n api.get<{ events: ActivityEvent[] }>('/activity?limit=200').catch(() => ({ events: [] })),\n ]);\n setBgInstances(bgRes.instances || []);\n setEvents(evRes.events || []);\n } catch (err) {\n console.warn('activity reload failed:', err);\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n reloadAll();\n const id = setInterval(reloadAll, 3000);\n return () => clearInterval(id);\n }, [reloadAll]);\n\n // Trigger a re-fetch when the snapshot's task/agent counts change.\n useEffect(() => {\n setRefreshTick((t) => t + 1);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [tasks.length, agents.length]);\n\n // ─── Now tick (1s) — paused when mode === 'pause' ───────────────────\n useEffect(() => {\n if (mode === 'pause') return;\n setNowTick(Date.now());\n const id = setInterval(() => setNowTick(Date.now()), 1000);\n return () => clearInterval(id);\n }, [mode, refreshTick]);\n\n // ─── Re-anchor viewStart when the now line nears the right edge ────\n useEffect(() => {\n if (mode === 'pause') return;\n const nowRatio = (nowTick - viewStart) / rangeMs;\n if (nowRatio > REANCHOR_RATIO) {\n setViewStart(nowTick - rangeMs * 0.1);\n }\n }, [nowTick, viewStart, rangeMs, mode]);\n\n // On zoom change, reset viewStart so now sits at 10% from the left.\n useEffect(() => {\n setViewStart(Date.now() - rangeMs * 0.1);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [zoom]);\n\n // On resume from pause, re-anchor so the now line lands at 10%.\n useEffect(() => {\n if (mode === 'live') {\n setViewStart(Date.now() - rangeMs * 0.1);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode]);\n\n // ─── Canvas size observer ───────────────────────────────────────────\n useLayoutEffect(() => {\n const el = canvasWrapRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n setCanvasSize({\n width: Math.max(200, Math.floor(width)),\n height: Math.max(120, Math.floor(height)),\n });\n }\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // ─── Lane allocation ────────────────────────────────────────────────\n const lanes: Lane[] = useMemo(() => {\n const out: Lane[] = [];\n let idx = 0;\n\n // BG instances — one lane each, at the top.\n for (const bg of bgInstances) {\n const start = bgStartMs(bg);\n const end = bgEndMs(bg, nowTick);\n if (end < rangeStart || start > rangeEnd) continue;\n out.push({\n kind: 'bg',\n id: `bg:${bg.instanceId}`,\n index: idx++,\n label: `BG ${shortLabel(bg.promptPreview, 20) || bg.instanceId.slice(0, 10)}`,\n sub: bg.status || 'pending',\n start,\n end,\n data: bg,\n });\n }\n\n // Tasks — greedy lane assignment (fill first lane that has no overlap).\n const sorted = [...tasks].sort((a, b) => taskStartMs(a) - taskStartMs(b));\n const taskLaneEnds: number[] = []; // end-time of last task placed in each lane\n for (const t of sorted) {\n const s = taskStartMs(t);\n const e = taskEndMs(t, nowTick);\n if (e < rangeStart || s > rangeEnd) continue;\n let assigned = -1;\n for (let i = 0; i < taskLaneEnds.length; i++) {\n if (taskLaneEnds[i] <= s) {\n taskLaneEnds[i] = e;\n assigned = i;\n break;\n }\n }\n if (assigned === -1) {\n taskLaneEnds.push(e);\n assigned = taskLaneEnds.length - 1;\n }\n out.push({\n kind: 'task',\n id: `task:${t.id}`,\n index: idx + assigned,\n label: shortLabel(t.title, 32),\n sub: t.status,\n start: s,\n end: e,\n data: t,\n });\n }\n\n return out;\n }, [bgInstances, tasks, nowTick, rangeStart, rangeEnd]);\n\n const laneById = useMemo(() => {\n const m = new Map<string, Lane>();\n for (const l of lanes) m.set(l.id, l);\n return m;\n }, [lanes]);\n\n // ─── Time → X coordinate ────────────────────────────────────────────\n const timeToX = useCallback(\n (t: number): number => {\n if (rangeMs <= 0) return 0;\n return ((t - rangeStart) / rangeMs) * canvasSize.width;\n },\n [rangeStart, rangeMs, canvasSize.width],\n );\n\n // ─── Tick marks for the time axis ───────────────────────────────────\n const ticks = useMemo(() => {\n const step = chooseTickStep(rangeMs);\n const result: { t: number; x: number; label: string }[] = [];\n // Align to step boundary.\n const startAligned = Math.floor(rangeStart / step) * step;\n for (let t = startAligned; t <= rangeEnd + step; t += step) {\n if (t < rangeStart - step) continue;\n if (t > rangeEnd) break;\n const x = timeToX(t);\n if (x < -40 || x > canvasSize.width + 40) continue;\n result.push({ t, x, label: formatTickLabel(t, rangeMs) });\n }\n return result;\n }, [rangeStart, rangeEnd, rangeMs, canvasSize.width, timeToX]);\n\n // ─── Build task/bg bars ─────────────────────────────────────────────\n const bars: TaskBar[] = useMemo(() => {\n const out: TaskBar[] = [];\n for (const lane of lanes) {\n if (lane.kind === 'events') continue;\n const visibleStart = Math.max(lane.start, rangeStart);\n const visibleEnd = Math.min(lane.end, rangeEnd);\n if (visibleEnd < rangeStart || visibleStart > rangeEnd) continue;\n const x = timeToX(visibleStart);\n const xEnd = timeToX(visibleEnd);\n const w = Math.max(MIN_BAR_WIDTH, xEnd - x);\n const y = TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lane.index * LANE_HEIGHT + 8;\n const h = LANE_HEIGHT - 16;\n\n let statusClass: TaskBar['statusClass'] = 'doing';\n if (lane.kind === 'bg') {\n const s = lane.data.status || 'pending';\n if (s === 'done' || s === 'success') statusClass = 'done';\n else if (s === 'failed' || s === 'killed' || s === 'error') statusClass = 'failed';\n else if (s === 'queued' || s === 'pending') statusClass = 'queued';\n else if (s === 'blocked' || s === 'stuck') statusClass = 'blocked';\n else statusClass = 'doing';\n } else {\n const s = lane.data.status;\n if (s === 'done' || s === 'archived') statusClass = 'done';\n else if (s === 'failed' || s === 'killed') statusClass = 'failed';\n else if (s === 'queued') statusClass = 'queued';\n else if (s === 'blocked') statusClass = 'blocked';\n else statusClass = 'doing';\n }\n\n const selected = selectedItem?.id === lane.id;\n\n out.push({\n id: lane.id,\n laneIndex: lane.index,\n x,\n y,\n w,\n h,\n label: lane.label,\n statusClass,\n selected,\n data: lane.data,\n kind: lane.kind,\n start: lane.start,\n end: lane.end,\n });\n }\n return out;\n }, [lanes, timeToX, selectedItem, rangeStart, rangeEnd]);\n\n // ─── Build event markers (placed on the lane of their related entity) ─\n const eventMarkers: EventMarker[] = useMemo(() => {\n const out: EventMarker[] = [];\n for (const ev of events) {\n const ts = parseTs(ev.ts);\n if (ts < rangeStart - 5000 || ts > rangeEnd + 5000) continue;\n const x = timeToX(ts);\n\n // Try to find a related lane.\n let y = TIME_AXIS_HEIGHT + 12; // default: events strip\n if (ev.taskId) {\n const lane = laneById.get(`task:${ev.taskId}`);\n if (lane) y = TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lane.index * LANE_HEIGHT + LANE_HEIGHT / 2;\n } else if (ev.nodeId) {\n const id = String(ev.nodeId);\n const lane = laneById.get(id.startsWith('task:') || id.startsWith('bg:') ? id : `task:${id}`);\n if (lane) y = TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lane.index * LANE_HEIGHT + LANE_HEIGHT / 2;\n }\n\n out.push({\n id: `${ev.ts}-${ev.kind}-${ev.author ?? ''}-${ev.taskId ?? ''}`,\n x,\n y,\n kind: ev.kind || 'event',\n ts,\n text: String(ev.text || ev.kind || ''),\n author: ev.author as string | undefined,\n });\n }\n return out;\n }, [events, rangeStart, rangeEnd, timeToX, laneById]);\n\n // ─── Lane backgrounds (alternating) ─────────────────────────────────\n const laneRects = useMemo(() => {\n return lanes.map((lane) => ({\n id: lane.id,\n y: TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lane.index * LANE_HEIGHT,\n h: LANE_HEIGHT,\n }));\n }, [lanes]);\n\n // ─── Now line position ──────────────────────────────────────────────\n const nowX = useMemo(() => {\n const x = timeToX(nowTick);\n return Math.max(0, Math.min(canvasSize.width, x));\n }, [timeToX, nowTick, canvasSize.width]);\n\n // ─── Click on a bar → open detail panel ─────────────────────────────\n const onSelectBar = useCallback((bar: TaskBar) => {\n const id = bar.id; // 'task:xxx' or 'bg:xxx'\n const item: SelectedItem = {\n id,\n kind: bar.kind,\n label: bar.label,\n status: bar.statusClass,\n data: bar.data,\n };\n setSelectedItem(item);\n }, []);\n\n // ─── Detail panel: fetch related data when selection changes ────────\n useEffect(() => {\n if (!selectedItem) {\n setComments([]);\n setBgOutput('');\n setBgArtifactIds([]);\n return;\n }\n setCommentText('');\n setTaskTitle('');\n setBgMessage('');\n setBgArtifactIds([]);\n (async () => {\n try {\n const r = await api.get<{ events: ActivityEvent[] }>(\n `/activity?nodeId=${encodeURIComponent(selectedItem.id)}&limit=50`,\n );\n setComments(r.events || []);\n } catch {\n setComments([]);\n }\n if (selectedItem.kind === 'bg') {\n const bgData = selectedItem.data as BgInstance;\n try {\n const r = await api.get<{ output: string }>(\n `/background/${encodeURIComponent(bgData.instanceId)}/output?lines=80`,\n );\n setBgOutput(r.output || '');\n } catch {\n setBgOutput('');\n }\n // v3.6.2 — If the bg instance has a linked taskId, fetch its artifacts.\n if (bgData.taskId) {\n try {\n const artR = await api.get<{ artifacts: { id: string }[] }>(\n `/tasks/${encodeURIComponent(bgData.taskId)}/artifacts`,\n );\n setBgArtifactIds((artR.artifacts || []).map((a) => a.id));\n } catch {\n setBgArtifactIds([]);\n }\n }\n }\n })();\n }, [selectedItem]);\n\n // ─── Detail actions ─────────────────────────────────────────────────\n const onAddComment = async () => {\n if (!selectedItem || !commentText.trim()) return;\n setPostingComment(true);\n try {\n await api.post('/comments', { nodeId: selectedItem.id, text: commentText, author: 'user' });\n setCommentText('');\n const r = await api.get<{ events: ActivityEvent[] }>(\n `/activity?nodeId=${encodeURIComponent(selectedItem.id)}&limit=50`,\n );\n setComments(r.events || []);\n toast.success('Comment added.');\n } catch (err) {\n toast.error(`Comment failed: ${(err as Error).message}`);\n } finally {\n setPostingComment(false);\n }\n };\n\n const onCreateTaskFromNode = async () => {\n if (!selectedItem || !taskTitle.trim()) return;\n setCreatingTask(true);\n try {\n await api.post(`/nodes/${encodeURIComponent(selectedItem.id)}/tasks`, {\n title: taskTitle,\n description: `Created from timeline selection ${selectedItem.id}.`,\n priority: taskPriority,\n });\n setTaskTitle('');\n toast.success('Task created.');\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Task create failed: ${(err as Error).message}`);\n } finally {\n setCreatingTask(false);\n }\n };\n\n const onSendBgMessage = async () => {\n if (!selectedItem || selectedItem.kind !== 'bg' || !bgMessage.trim()) return;\n const bgData = selectedItem.data as BgInstance;\n try {\n const r = await api.post<{ ok: boolean; error?: string }>(\n `/background/${encodeURIComponent(bgData.instanceId)}/message`,\n { message: bgMessage },\n );\n if (r.ok) {\n toast.success('Message sent.');\n setBgMessage('');\n } else {\n toast.warning(r.error || 'Send failed');\n }\n } catch (err) {\n toast.error(`Send failed: ${(err as Error).message}`);\n }\n };\n\n const onKillBg = async () => {\n if (!selectedItem || selectedItem.kind !== 'bg') return;\n if (!confirm('Kill this bg instance session?')) return;\n const bgData = selectedItem.data as BgInstance;\n try {\n const r = await api.del<{ ok: boolean; error?: string }>(\n `/background/${encodeURIComponent(bgData.instanceId)}`,\n );\n if (r.ok) toast.success('Session killed.');\n else toast.warning(r.error || 'Kill failed');\n await reloadAll();\n } catch (err) {\n toast.error(`Kill failed: ${(err as Error).message}`);\n }\n };\n\n const refetchOutput = async () => {\n if (!selectedItem || selectedItem.kind !== 'bg') return;\n const bgData = selectedItem.data as BgInstance;\n try {\n const r = await api.get<{ output: string }>(\n `/background/${encodeURIComponent(bgData.instanceId)}/output?lines=80`,\n );\n setBgOutput(r.output || '');\n } catch {\n /* ignore */\n }\n };\n\n // ─── Keyboard helpers ───────────────────────────────────────────────\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setSelectedItem(null);\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, []);\n\n // ─── Refresh handler ────────────────────────────────────────────────\n const refresh = () => {\n setRefreshTick((t) => t + 1);\n reloadAll();\n };\n\n // ─── Derived: total content height (for SVG sizing) ─────────────────\n const contentHeight = TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lanes.length * LANE_HEIGHT;\n\n // ─── Render ─────────────────────────────────────────────────────────\n return (\n <div className=\"view view-activity\">\n {/* Top header bar — title + live/pause + zoom + refresh */}\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <ActivityIcon size={18} /> Activity\n </h2>\n <p className=\"view-subtitle\">\n Live timeline of agents, tasks, and background sessions. Active tasks pulse; the red line marks “now”.\n </p>\n </div>\n <div className=\"view-actions\">\n <div className=\"tl-mode-toggle\">\n <Button\n variant={mode === 'live' ? 'primary' : 'secondary'}\n size=\"sm\"\n onClick={() => setMode(mode === 'live' ? 'pause' : 'live')}\n title={mode === 'live' ? 'Pause timeline' : 'Resume timeline'}\n >\n {mode === 'live' ? <Pause size={14} /> : <Play size={14} />}\n {mode === 'live' ? 'Live' : 'Paused'}\n </Button>\n <div className=\"tl-zoom-group\">\n {(['1m', '5m', '30m', '1h'] as ZoomKey[]).map((z) => (\n <button\n type=\"button\"\n key={z}\n className={cn('tl-zoom-btn', zoom === z && 'tl-zoom-btn-active')}\n onClick={() => setZoom(z)}\n title={`Zoom to ${z}`}\n >\n {z}\n </button>\n ))}\n </div>\n <Button variant=\"secondary\" size=\"sm\" onClick={refresh} title=\"Refresh\">\n <RefreshCw size={14} /> Refresh\n </Button>\n </div>\n </div>\n </header>\n\n {loading && (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n )}\n\n {!loading && agents.length === 0 && tasks.length === 0 && bgInstances.length === 0 && events.length === 0 ? (\n <EmptyState\n icon={<ActivityIcon size={32} />}\n title=\"No activity yet\"\n message=\"Once agents, tasks, or background instances exist, they'll show up here on the timeline.\"\n />\n ) : (\n <div className={cn('tl-view', selectedItem && 'tl-view-detail-open')}>\n <div className={cn('tl-body', !streamOpen && 'tl-body-stream-collapsed')}>\n {/* Left column — event stream (sibling, not overlay) */}\n <aside className={cn('tl-stream', !streamOpen && 'tl-stream-collapsed')}>\n <div className=\"tl-stream-head\">\n <h3>\n <History size={13} /> Live events\n </h3>\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => setStreamOpen(false)}\n title=\"Hide event stream\"\n aria-label=\"Hide event stream\"\n >\n <PanelLeftClose size={14} />\n </button>\n </div>\n <div className=\"tl-stream-list\">\n {events.length === 0 ? (\n <div className=\"tl-stream-empty\">\n <p>No events yet.</p>\n </div>\n ) : (\n <VirtualList\n items={[...events].reverse()}\n itemHeight={40}\n height={400}\n className=\"tl-stream-virtual\"\n renderItem={(ev) => {\n const Icon =\n ev.author ? Bot : ev.kind === 'task' ? CheckSquare : ev.kind === 'bg' ? Cpu : ActivityIcon;\n return (\n <div className=\"tl-stream-event\">\n <span className=\"tl-stream-event-time\">\n {new Date(ev.ts).toLocaleTimeString('en-GB', { hour12: false })}\n </span>\n <span className=\"tl-stream-event-icon\" style={{ color: statusColor(ev.kind) }}>\n <Icon size={12} />\n </span>\n <span className=\"tl-stream-event-text\">\n {ev.author || ev.text || ev.kind}\n </span>\n </div>\n );\n }}\n />\n )}\n </div>\n </aside>\n\n {/* Center column — timeline canvas */}\n <div className=\"tl-canvas-wrap\" ref={canvasWrapRef}>\n <div className=\"tl-canvas-toolbar\">\n <div className=\"tl-canvas-toolbar-left\">\n {!streamOpen && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setStreamOpen(true)}\n title=\"Show event stream\"\n >\n <PanelLeftOpen size={14} /> Events\n </Button>\n )}\n <span className=\"tl-canvas-mode\">\n {mode === 'live' ? '● Live' : '⏸ Paused'}\n </span>\n <span className=\"tl-canvas-range\">\n {new Date(rangeStart).toLocaleTimeString('en-GB', { hour12: false })} →{' '}\n {new Date(rangeEnd).toLocaleTimeString('en-GB', { hour12: false })}\n </span>\n </div>\n <div className=\"tl-canvas-legend\">\n <span className=\"tl-legend-item\"><span className=\"tl-legend-dot\" style={{ background: 'var(--success)' }} /> active</span>\n <span className=\"tl-legend-item\"><span className=\"tl-legend-dot tl-legend-dot-dashed\" style={{ borderColor: 'var(--info)' }} /> queued</span>\n <span className=\"tl-legend-item\"><span className=\"tl-legend-dot\" style={{ background: 'var(--warning)' }} /> blocked</span>\n <span className=\"tl-legend-item\"><span className=\"tl-legend-dot\" style={{ background: 'var(--error)' }} /> error</span>\n <span className=\"tl-legend-sep\" />\n <span className=\"tl-legend-item\"><Layers size={11} /> agent</span>\n <span className=\"tl-legend-item\"><Target size={11} /> task</span>\n <span className=\"tl-legend-item\"><Cpu size={11} /> bg</span>\n </div>\n </div>\n\n <div className=\"tl-canvas-scroll\">\n <svg\n className=\"tl-canvas\"\n width={canvasSize.width}\n height={Math.max(canvasSize.height, contentHeight)}\n role=\"application\"\n aria-label=\"Activity timeline\"\n >\n <defs>\n <pattern\n id=\"tl-canvas-grid\"\n width={canvasSize.width}\n height={LANE_HEIGHT}\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n d={`M 0 0 L 0 ${LANE_HEIGHT}`}\n fill=\"none\"\n stroke=\"var(--border)\"\n strokeWidth={0.5}\n opacity={0.35}\n />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" fill=\"url(#tl-canvas-grid)\" />\n\n {/* Lane backgrounds (alternating) */}\n {laneRects.map((lr) => (\n <rect\n key={`bg-${lr.id}`}\n className=\"tl-lane-bg\"\n x={0}\n y={lr.y}\n width={canvasSize.width}\n height={lr.h}\n fill={lr.id.charCodeAt(lr.id.length - 1) % 2 === 0 ? 'var(--bg-elev-2)' : 'var(--bg-elev)'}\n opacity={0.4}\n />\n ))}\n\n {/* Time axis tick lines + labels */}\n <g className=\"tl-time-axis\">\n {ticks.map((t) => (\n <g key={`tick-${t.t}`}>\n <line\n x1={t.x}\n y1={0}\n x2={t.x}\n y2={contentHeight}\n stroke=\"var(--border)\"\n strokeWidth={0.5}\n strokeDasharray=\"2,4\"\n opacity={0.5}\n />\n <text\n x={t.x + 4}\n y={TIME_AXIS_HEIGHT - 8}\n fontSize={10}\n fontFamily=\"var(--font-mono)\"\n fill=\"var(--text-dim)\"\n >\n {t.label}\n </text>\n </g>\n ))}\n </g>\n\n {/* Lane labels (rendered inside SVG, x=4) */}\n {lanes.map((lane) => {\n const y = TIME_AXIS_HEIGHT + EVENTS_STRIP_HEIGHT + lane.index * LANE_HEIGHT + LANE_HEIGHT / 2;\n return (\n <g key={`label-${lane.id}`} className=\"tl-lane-label-group\">\n <text\n x={6}\n y={y - 2}\n className=\"tl-lane-label\"\n textAnchor=\"start\"\n >\n {shortLabel(lane.label, 28)}\n </text>\n <text\n x={6}\n y={y + 10}\n className=\"tl-lane-label-sub\"\n textAnchor=\"start\"\n >\n {lane.sub}\n </text>\n </g>\n );\n })}\n\n {/* Task / BG bars */}\n {bars.map((bar) => {\n const fillColor = statusColor(bar.statusClass);\n const isSelected = bar.id === selectedItem?.id;\n return (\n <g\n key={`bar-${bar.id}`}\n className={cn('tl-task-bar', `tl-task-bar-${bar.statusClass}`, isSelected && 'tl-task-bar-selected')}\n onClick={() => onSelectBar(bar)}\n >\n <rect\n x={bar.x}\n y={bar.y}\n width={bar.w}\n height={bar.h}\n rx={6}\n fill={fillColor}\n fillOpacity={bar.statusClass === 'done' ? 0.35 : bar.statusClass === 'queued' ? 0.18 : 0.85}\n stroke={fillColor}\n strokeWidth={isSelected ? 2.5 : 1.5}\n strokeOpacity={bar.statusClass === 'done' ? 0.5 : 1}\n strokeDasharray={bar.statusClass === 'queued' ? '4 4' : undefined}\n style={{ cursor: 'pointer' }}\n />\n {bar.w > 36 && (\n <text\n x={bar.x + 8}\n y={bar.y + bar.h / 2 + 4}\n fontSize={11}\n fontFamily=\"var(--font-sans)\"\n fontWeight={500}\n fill=\"var(--text-strong)\"\n style={{ pointerEvents: 'none' }}\n opacity={bar.statusClass === 'done' ? 0.7 : 1}\n >\n {shortLabel(bar.label, Math.max(4, Math.floor(bar.w / 7)))}\n </text>\n )}\n </g>\n );\n })}\n\n {/* Event markers */}\n {eventMarkers.map((m) => {\n const color = statusColor(m.kind);\n return (\n <g key={`ev-${m.id}`} className=\"tl-event-marker-group\">\n <line\n x1={m.x}\n y1={m.y - 6}\n x2={m.x}\n y2={m.y + 6}\n stroke={color}\n strokeWidth={1.2}\n opacity={0.7}\n />\n <circle\n cx={m.x}\n cy={m.y}\n r={4}\n fill={color}\n opacity={0.9}\n >\n <title>\n {`${m.kind}${m.author ? ` · ${m.author}` : ''} · ${new Date(m.ts).toLocaleTimeString('en-GB', { hour12: false })}`}\n </title>\n </circle>\n </g>\n );\n })}\n\n {/* Now line (red, vertical) */}\n <line\n className=\"tl-now-line\"\n x1={nowX}\n y1={0}\n x2={nowX}\n y2={contentHeight}\n stroke=\"var(--error)\"\n strokeWidth={1.5}\n opacity={0.9}\n />\n <g className=\"tl-now-marker\">\n <circle cx={nowX} cy={TIME_AXIS_HEIGHT - 4} r={4} fill=\"var(--error)\" />\n <text\n x={nowX + 6}\n y={TIME_AXIS_HEIGHT - 4}\n fontSize={10}\n fontWeight={700}\n fill=\"var(--error)\"\n fontFamily=\"var(--font-mono)\"\n >\n now\n </text>\n </g>\n </svg>\n </div>\n </div>\n\n {/* Right column — detail panel */}\n {selectedItem && (\n <aside className=\"tl-detail tl-detail-enter\" key={selectedItem.id}>\n <Card>\n <CardTitle>\n {selectedItem.kind === 'agent' && <Bot size={14} />}\n {selectedItem.kind === 'task' && <CheckSquare size={14} />}\n {selectedItem.kind === 'bg' && <Cpu size={14} />}\n {selectedItem.label}\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => setSelectedItem(null)}\n title=\"Close\"\n aria-label=\"Close activity detail\"\n style={{ marginLeft: 'auto' }}\n >\n <X size={14} />\n </button>\n </CardTitle>\n <div className=\"tl-detail-meta\">\n <div><span className=\"muted\">type</span> {selectedItem.kind}</div>\n <div><span className=\"muted\">status</span> <code>{selectedItem.status}</code></div>\n {selectedItem.kind === 'agent' && (() => {\n const a = selectedItem.data as Agent;\n return (\n <>\n {a.role && <div><span className=\"muted\">role</span> {a.role}</div>}\n {a.model && <div><span className=\"muted\">model</span> {a.model}</div>}\n </>\n );\n })()}\n {selectedItem.kind === 'task' && (() => {\n const t = selectedItem.data as Task;\n return (\n <>\n {t.assignee && <div><span className=\"muted\">assignee</span> @{t.assignee}</div>}\n {t.priority && <div><span className=\"muted\">priority</span> {t.priority}</div>}\n {t.createdAt && <div><span className=\"muted\">created</span> {new Date(t.createdAt).toLocaleString()}</div>}\n </>\n );\n })()}\n {selectedItem.kind === 'bg' && (() => {\n const b = selectedItem.data as BgInstance;\n return (\n <>\n {b.startedAt && <div><span className=\"muted\">started</span> {new Date(b.startedAt).toLocaleString()}</div>}\n {b.tmuxSession && <div><span className=\"muted\">tmux</span> <code>{b.tmuxSession}</code> {b.tmuxActive ? <span className=\"tag tag-success\">active</span> : <span className=\"tag\">inactive</span>}</div>}\n </>\n );\n })()}\n </div>\n {selectedItem.kind === 'task' && (selectedItem.data as Task).description && (\n <div className=\"tl-detail-desc\">{(selectedItem.data as Task).description}</div>\n )}\n {selectedItem.kind === 'bg' && (selectedItem.data as BgInstance).promptPreview && (\n <div className=\"tl-detail-desc\">{(selectedItem.data as BgInstance).promptPreview}</div>\n )}\n\n {selectedItem.kind === 'bg' && (\n <div className=\"tl-detail-bg\">\n <pre className=\"tl-bg-output\">{bgOutput || '(no output — start the session via tmux attach)'}</pre>\n <div className=\"tl-bg-output-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={refetchOutput}>\n <RefreshCw size={12} /> Refresh output\n </Button>\n {bgArtifactIds.length > 0 && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => openArtifactViewer(modal, bgArtifactIds[0])}\n >\n <FileText size={12} /> Open artifact\n </Button>\n )}\n <Button variant=\"danger\" size=\"sm\" onClick={onKillBg}>\n <Trash2 size={12} /> Kill session\n </Button>\n </div>\n <div className=\"tl-form-row\">\n <label htmlFor=\"bg-message-input\" className=\"sr-only\">Send a message to this bg session</label>\n <input\n id=\"bg-message-input\"\n className=\"input\"\n placeholder=\"Send a message to this bg session…\"\n value={bgMessage}\n onChange={(e) => setBgMessage(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onSendBgMessage();\n }}\n aria-label=\"Send a message to this bg session\"\n />\n <Button variant=\"primary\" size=\"sm\" disabled={!bgMessage.trim()} onClick={onSendBgMessage}>\n <Send size={12} /> Send\n </Button>\n </div>\n </div>\n )}\n\n {selectedItem.kind !== 'bg' && (\n <div className=\"tl-detail-create\">\n <label className=\"field-label\" htmlFor=\"followup-task-title\">Create follow-up task</label>\n <input\n id=\"followup-task-title\"\n className=\"input\"\n placeholder=\"Task title\"\n value={taskTitle}\n onChange={(e) => setTaskTitle(e.target.value)}\n />\n <div className=\"tl-form-row\">\n <label htmlFor=\"followup-task-priority\" className=\"sr-only\">Task priority</label>\n <select\n id=\"followup-task-priority\"\n className=\"select\"\n value={taskPriority}\n onChange={(e) => setTaskPriority(e.target.value)}\n aria-label=\"Task priority\"\n >\n <option value=\"low\">Low</option>\n <option value=\"normal\">Normal</option>\n <option value=\"high\">High</option>\n </select>\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={!taskTitle.trim() || creatingTask}\n onClick={onCreateTaskFromNode}\n >\n <Plus size={12} /> Add task\n </Button>\n </div>\n </div>\n )}\n\n <div className=\"tl-detail-comments\">\n <div className=\"field-label\">\n <MessageSquare size={12} /> Comments & activity\n </div>\n <ul className=\"comment-list\">\n {comments.length === 0 && <li className=\"muted\">No comments yet.</li>}\n {comments.map((c, i) => (\n <li key={`c-${i}`} className=\"comment-item\">\n <div className=\"comment-head\">\n <strong>{c.author || 'system'}</strong>\n <span className=\"muted\">\n {c.kind} · {new Date(c.ts).toLocaleString()}\n </span>\n </div>\n {c.text && <div className=\"comment-text\">{c.text}</div>}\n {c.taskId && (\n <div className=\"muted\">\n → task <code>{String(c.taskId)}</code>\n </div>\n )}\n </li>\n ))}\n </ul>\n <div className=\"comment-input-row\">\n <label htmlFor=\"comment-input\" className=\"sr-only\">Add a comment</label>\n <input\n id=\"comment-input\"\n className=\"input\"\n placeholder=\"Add a comment…\"\n value={commentText}\n onChange={(e) => setCommentText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) onAddComment();\n }}\n aria-label=\"Add a comment\"\n />\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={!commentText.trim() || postingComment}\n onClick={onAddComment}\n >\n <Send size={12} /> Post\n </Button>\n </div>\n </div>\n </Card>\n </aside>\n )}\n </div>\n </div>\n )}\n </div>\n );\n}\n","// src/web/lib/search.ts — fuzzy search with typo tolerance (Levenshtein distance).\n// Provides SearchableItem/SearchResult types and a fuzzySearch function for\n// settings, commands, and any structured UI search.\n\nexport interface SearchableItem {\n key: string;\n label: string;\n section: string;\n value?: string | number | boolean;\n description?: string;\n}\n\nexport interface SearchResult extends SearchableItem {\n score: number;\n matchedField: 'label' | 'value' | 'description';\n matchedTerm: string;\n}\n\n/**\n * Levenshtein distance for typo tolerance.\n */\nexport function levenshtein(a: string, b: string): number {\n const alen = a.length;\n const blen = b.length;\n const matrix: number[][] = Array.from({ length: blen + 1 }, () => Array(alen + 1).fill(0));\n for (let i = 0; i <= alen; i++) matrix[0][i] = i;\n for (let j = 0; j <= blen; j++) matrix[j][0] = j;\n for (let j = 1; j <= blen; j++) {\n for (let i = 1; i <= alen; i++) {\n const indicator = a[i - 1] === b[j - 1] ? 0 : 1;\n matrix[j][i] = Math.min(\n matrix[j][i - 1] + 1,\n matrix[j - 1][i] + 1,\n matrix[j - 1][i - 1] + indicator,\n );\n }\n }\n return matrix[blen][alen];\n}\n\n/**\n * Score a single field against the query.\n * Returns a numeric score (higher = better match) or 0 if no match.\n *\n * Scoring tiers (mutually exclusive — first match wins):\n * 100 — exact field match (query === field)\n * 90 — field starts with query (prefix match)\n * 80 — a word in the field starts with query (word boundary)\n * 40 — typo-tolerant match (Levenshtein ≤ 2 against the first query.length chars)\n * 30 — substring match anywhere in field (fallback)\n */\nexport function scoreField(query: string, field: string): number {\n // Exact match\n if (field === query) return 100;\n\n // Field prefix match (field starts with query)\n if (field.startsWith(query)) return 90;\n\n // Word boundary match (any word starts with query)\n const words = field.split(/\\s+/);\n for (const word of words) {\n if (word.startsWith(query)) return 80;\n }\n\n // Typo tolerance: compare query against first query.length chars of field\n const compareLen = Math.min(query.length, field.length);\n const dist = levenshtein(query, field.substring(0, compareLen));\n if (dist <= 2) return 40;\n\n // Substring match (anywhere)\n if (field.includes(query)) return 30;\n\n return 0;\n}\n\n/**\n * Fuzzy search over an array of SearchableItem.\n * Returns results sorted by descending score. Empty query returns [].\n */\nexport function fuzzySearch(query: string, items: SearchableItem[]): SearchResult[] {\n const q = query.toLowerCase().trim();\n if (!q) return [];\n\n return items\n .map((item) => {\n const labelScore = scoreField(q, item.label.toLowerCase());\n const valueScore = item.value ? scoreField(q, String(item.value).toLowerCase()) : 0;\n const descScore = item.description ? scoreField(q, item.description.toLowerCase()) : 0;\n\n const max = Math.max(labelScore, valueScore, descScore);\n if (max === 0) return null;\n\n const matchedField: SearchResult['matchedField'] =\n labelScore >= valueScore && labelScore >= descScore\n ? 'label'\n : valueScore >= labelScore && valueScore >= descScore\n ? 'value'\n : 'description';\n const matchedTerm =\n matchedField === 'label'\n ? item.label\n : matchedField === 'value'\n ? String(item.value)\n : item.description!;\n\n return {\n ...item,\n score: max,\n matchedField,\n matchedTerm,\n };\n })\n .filter((r): r is SearchResult => r !== null)\n .sort((a, b) => b.score - a.score);\n}\n","// src/web/components/SettingsSearch.tsx — fuzzy search across Settings sections with scroll-to highlight.\n// v4.9: replaces Fuse.js with Levenshtein-based fuzzySearch; adds recent searches + match highlighting.\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Search, X } from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport { fuzzySearch, type SearchableItem, type SearchResult } from '../lib/search';\n\nexport type SettingsSection = {\n id: string;\n label: string;\n icon?: string;\n fields: SettingsField[];\n};\n\nexport type SettingsField = {\n key: string; // e.g. \"theme.accent\"\n label: string; // e.g. \"Accent color\"\n value?: string; // current value (masked if secret)\n section: string; // parent section id\n};\n\ntype Props = {\n sections: SettingsSection[];\n onJump: (sectionId: string, fieldKey?: string) => void;\n};\n\n/* ─── Recent searches (localStorage) ─── */\n\nconst RECENT_KEY = 'bizar_settings_recent';\n\nfunction getRecentSearches(): string[] {\n try {\n const stored = localStorage.getItem(RECENT_KEY);\n return stored ? JSON.parse(stored) : [];\n } catch {\n return [];\n }\n}\n\nfunction saveRecentSearch(query: string) {\n if (!query) return;\n try {\n const recent = getRecentSearches().filter((q) => q !== query);\n recent.unshift(query);\n localStorage.setItem(RECENT_KEY, JSON.stringify(recent.slice(0, 5)));\n } catch {\n // localStorage may be full or disabled — silently ignore\n }\n}\n\n/* ─── Highlight matched terms ─── */\n\nfunction highlightMatch(text: string, query: string): React.ReactNode {\n if (!query) return text;\n // Escape regex special characters in the user query\n const escaped = query.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(`(${escaped})`, 'gi');\n const parts = text.split(regex);\n return parts.map((part, i) =>\n regex.test(part) ? <mark key={i}>{part}</mark> : <span key={i}>{part}</span>,\n );\n}\n\n/* ─── Build SearchableItems from sections ─── */\n\nfunction toSearchableItems(sections: SettingsSection[]): SearchableItem[] {\n const items: SearchableItem[] = [];\n for (const section of sections) {\n // Section itself is searchable\n items.push({\n key: section.id,\n label: section.label,\n section: section.id,\n description: `${section.fields.length} field${section.fields.length === 1 ? '' : 's'}`,\n });\n // Each field is searchable\n for (const field of section.fields) {\n items.push({\n key: field.key,\n label: field.label,\n section: section.id,\n value: field.value,\n });\n }\n }\n return items;\n}\n\n/* ─── Component ─── */\n\nexport function SettingsSearch({ sections, onJump }: Props) {\n const [q, setQ] = useState('');\n const [matches, setMatches] = useState<SearchResult[]>([]);\n const [activeIdx, setActiveIdx] = useState(0);\n const [highlighted, setHighlighted] = useState<string | null>(null);\n const [focused, setFocused] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const highlightTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const allItems = useRef<SearchableItem[]>([]);\n // Rebuild items when sections change\n useEffect(() => {\n allItems.current = toSearchableItems(sections);\n }, [sections]);\n\n const search = useCallback(\n (query: string, immediate = false) => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (!query.trim()) {\n setMatches([]);\n setActiveIdx(0);\n return;\n }\n const run = () => {\n const results = fuzzySearch(query, allItems.current);\n setMatches(results);\n setActiveIdx(0);\n };\n if (immediate) {\n run();\n } else {\n debounceRef.current = setTimeout(run, 150);\n }\n },\n [], // stable — allItems is a ref\n );\n\n useEffect(() => {\n search(q);\n }, [q, search]);\n\n // Cleanup timers\n useEffect(() => {\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n };\n }, []);\n\n /* ─── Quick-jump with flash ─── */\n\n const jumpToSection = (sectionId: string, key: string) => {\n // Look for the field by data-setting-id within the section\n const fieldEl = document.querySelector(\n `[data-section=\"${sectionId}\"] [data-setting-id=\"${key}\"]`,\n );\n if (fieldEl) {\n fieldEl.scrollIntoView({ behavior: 'smooth', block: 'center' });\n fieldEl.classList.add('setting-flash');\n setTimeout(() => fieldEl.classList.remove('setting-flash'), 2000);\n }\n // Also scroll the section Card into view\n const sectionEl = document.querySelector(`[data-section=\"${sectionId}\"]`);\n if (sectionEl) {\n sectionEl.scrollIntoView({ behavior: 'smooth', block: fieldEl ? 'nearest' : 'start' });\n }\n };\n\n const highlightSection = (sectionId: string) => {\n setHighlighted(sectionId);\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n highlightTimerRef.current = setTimeout(() => setHighlighted(null), 1500);\n const el = document.querySelector(`[data-section=\"${sectionId}\"]`);\n if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });\n };\n\n const commitSelection = (result: SearchResult) => {\n saveRecentSearch(q);\n if (result.key === result.section) {\n // It's a section match — jump to section\n highlightSection(result.section);\n onJump(result.section);\n } else {\n // It's a field match — jump to field with flash\n highlightSection(result.section);\n onJump(result.section, result.key);\n jumpToSection(result.section, result.key);\n }\n setQ('');\n inputRef.current?.blur();\n };\n\n /* ─── Keyboard navigation ─── */\n\n const handleKey = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setQ('');\n inputRef.current?.blur();\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n setActiveIdx((i) => Math.min(i + 1, matches.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setActiveIdx((i) => Math.max(i - 1, 0));\n } else if (e.key === 'Enter') {\n e.preventDefault();\n // If debounce hasn't fired yet, search immediately\n if (matches.length === 0 && q.trim()) {\n search(q, true);\n }\n if (matches[activeIdx]) {\n commitSelection(matches[activeIdx]);\n }\n }\n };\n\n const handleSelect = (m: SearchResult) => {\n commitSelection(m);\n };\n\n /* ─── Recent searches helpers ─── */\n\n const recent = getRecentSearches();\n\n const handleRecentClick = (term: string) => {\n setQ(term);\n inputRef.current?.focus();\n };\n\n const clearRecent = () => {\n try {\n localStorage.removeItem(RECENT_KEY);\n } catch {\n // ignore\n }\n // Force re-render\n setFocused((f) => f);\n };\n\n /* ─── Render ─── */\n\n const showRecent = focused && !q.trim() && recent.length > 0;\n\n return (\n <div className=\"settings-search\">\n <div className=\"settings-search-input-wrap\">\n <Search size={13} className=\"settings-search-icon\" />\n <input\n ref={inputRef}\n className=\"settings-search-input\"\n placeholder=\"Search settings…\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={handleKey}\n onFocus={() => setFocused(true)}\n onBlur={() => setTimeout(() => setFocused(false), 150)}\n aria-label=\"Search settings\"\n />\n {q && (\n <button\n type=\"button\"\n className=\"icon-btn settings-search-clear\"\n onClick={() => setQ('')}\n aria-label=\"Clear search\"\n >\n <X size={12} />\n </button>\n )}\n </div>\n\n {/* Recent searches dropdown */}\n {showRecent && (\n <div className=\"settings-search-recent\">\n <div className=\"settings-search-recent-header\">\n <span className=\"settings-search-recent-label\">Recent</span>\n <button\n type=\"button\"\n className=\"settings-search-recent-clear\"\n onClick={clearRecent}\n tabIndex={-1}\n >\n Clear\n </button>\n </div>\n {recent.map((term) => (\n <button\n key={term}\n type=\"button\"\n className=\"settings-search-recent-item\"\n onMouseDown={(e) => {\n e.preventDefault();\n handleRecentClick(term);\n }}\n >\n <Search size={11} />\n <span>{term}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Search results */}\n {q && matches.length > 0 && (\n <div className=\"settings-search-results\">\n {matches.map((m, idx) => (\n <button\n key={`${m.section}::${m.key}`}\n type=\"button\"\n className={cn('settings-search-result', idx === activeIdx && 'settings-search-result-active')}\n onClick={() => handleSelect(m)}\n onMouseEnter={() => setActiveIdx(idx)}\n >\n <span\n className={cn(\n 'settings-search-result-type',\n m.key === m.section && 'settings-search-result-type-section',\n )}\n >\n {m.key === m.section ? 'section' : 'field'}\n </span>\n <span className=\"settings-search-result-label\">\n {highlightMatch(m.label, q)}\n </span>\n {m.key !== m.section && (\n <span className=\"settings-search-result-key mono muted\">{m.key}</span>\n )}\n </button>\n ))}\n </div>\n )}\n\n {q && matches.length === 0 && (\n <div className=\"settings-search-empty muted\">No matching settings.</div>\n )}\n </div>\n );\n}\n","// src/web/views/settings/ThemeSection.tsx\nimport React from 'react';\nimport { Palette, Sun, Moon, Monitor } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport { cn } from '../../lib/utils';\nimport type { Settings, ThemeName } from '../../lib/types';\n\ntype Props = {\n settings: Settings;\n patchTheme: (patch: Partial<Settings['theme']>) => void;\n patchUi: (patch: Partial<Settings['ui']>) => void;\n};\n\nconst THEMES: { id: ThemeName; label: string; Icon: typeof Sun }[] = [\n { id: 'dark', label: 'Dark', Icon: Moon },\n { id: 'light', label: 'Light', Icon: Sun },\n { id: 'system', label: 'System', Icon: Monitor },\n];\n\nconst PRESET_THEMES = [\n { name: 'Purple', accent: '#8b5cf6' },\n { name: 'Blue', accent: '#3b82f6' },\n { name: 'Green', accent: '#10b981' },\n { name: 'Orange', accent: '#f97316' },\n { name: 'Red', accent: '#ef4444' },\n { name: 'Pink', accent: '#ec4899' },\n { name: 'Cyan', accent: '#06b6d4' },\n { name: 'Mono', accent: '#6b7280' },\n];\n\nconst FONT_FAMILIES = [\n 'Inter',\n 'system-ui',\n 'Segoe UI',\n 'Roboto',\n 'JetBrains Mono',\n 'SF Mono',\n 'Cascadia Code',\n];\n\nexport function ThemeSection({ settings, patchTheme, patchUi }: Props) {\n return (\n <Card id=\"settings-theme\" data-section=\"theme\">\n <CardTitle><Palette size={14} /> Theme</CardTitle>\n <CardMeta>Mode, accent, and colors. Live preview as you tweak.</CardMeta>\n\n {/* Accent presets */}\n <div className=\"field\" data-setting-id=\"theme.presets\">\n <label className=\"field-label\">Accent presets</label>\n <div className=\"theme-presets\">\n {PRESET_THEMES.map((t) => (\n <button\n key={t.name}\n type=\"button\"\n className={cn(\n 'theme-preset',\n settings.theme.accent === t.accent && 'theme-preset-active',\n )}\n onClick={() => patchTheme({ accent: t.accent })}\n title={t.name}\n >\n <span\n className=\"theme-preset-swatch\"\n style={{ background: t.accent }}\n />\n <span className=\"theme-preset-name\">{t.name}</span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Mode */}\n <div className=\"field\" data-setting-id=\"theme.mode\">\n <label className=\"field-label\">Mode</label>\n <div className=\"theme-row\">\n {THEMES.map(({ id, label, Icon }) => {\n const active = settings.theme.mode === id;\n return (\n <button\n key={id}\n type=\"button\"\n className={cn('theme-card', active && 'theme-card-active')}\n onClick={() => patchTheme({ mode: id })}\n >\n <Icon size={16} />\n <span className=\"theme-card-label\">{label}</span>\n <span\n className={cn(\n 'theme-card-swatch',\n `theme-card-swatch-${id}`,\n )}\n />\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Custom colors */}\n <div className=\"theme-colors\">\n {(['accent', 'success', 'warning', 'error', 'info'] as const).map((c) => (\n <div key={c} className=\"field\" data-setting-id={`theme.${c}`}>\n <label className=\"field-label\">{c.charAt(0).toUpperCase() + c.slice(1)}</label>\n <div className=\"color-row\">\n <input\n type=\"color\"\n className=\"input color-input\"\n value={settings.theme[c]}\n onChange={(e) => patchTheme({ [c]: e.target.value })}\n aria-label={`${c} color`}\n />\n <input\n type=\"text\"\n className=\"input\"\n value={settings.theme[c]}\n onChange={(e) => patchTheme({ [c]: e.target.value })}\n aria-label={`${c} color hex`}\n />\n </div>\n </div>\n ))}\n </div>\n\n {/* Font */}\n <div className=\"field\" data-setting-id=\"theme.fontFamily\">\n <label className=\"field-label\">Font family</label>\n <select\n className=\"select\"\n value={settings.theme.fontFamily}\n onChange={(e) => patchTheme({ fontFamily: e.target.value })}\n >\n {FONT_FAMILIES.map((f) => (\n <option key={f} value={f}>{f}</option>\n ))}\n </select>\n </div>\n\n <div className=\"field\" data-setting-id=\"theme.fontSize\">\n <label className=\"field-label\">Font size: {settings.theme.fontSize}px</label>\n <input\n type=\"range\"\n min={12}\n max={20}\n value={settings.theme.fontSize}\n onChange={(e) => patchTheme({ fontSize: Number(e.target.value) })}\n />\n </div>\n\n <label className=\"checkbox-row\" data-setting-id=\"theme.compactMode\">\n <input\n type=\"checkbox\"\n checked={settings.theme.compactMode}\n onChange={(e) => patchTheme({ compactMode: e.target.checked })}\n />\n <span>Compact mode (denser UI)</span>\n </label>\n\n <label className=\"checkbox-row\" data-setting-id=\"theme.animations\">\n <input\n type=\"checkbox\"\n checked={settings.theme.animations}\n onChange={(e) => patchTheme({ animations: e.target.checked })}\n />\n <span>Enable animations</span>\n </label>\n </Card>\n );\n}\n","// src/web/views/settings/NetworkSection.tsx\nimport React from 'react';\nimport { Server as ServerIcon, Plug } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport { Button } from '../../components/Button';\nimport type { TailscaleStatus } from '../../lib/types';\n\ntype Props = {\n tailscale: TailscaleStatus | null;\n tailscaleDraft: { port: number; https: boolean; hostname: string };\n setTailscaleDraft: React.Dispatch<React.SetStateAction<{ port: number; https: boolean; hostname: string }>>;\n onTailscaleToggle: () => void;\n};\n\nexport function NetworkSection({ tailscale, tailscaleDraft, setTailscaleDraft, onTailscaleToggle }: Props) {\n return (\n <>\n {/* Service */}\n <Card id=\"settings-service\" data-section=\"service\">\n <CardTitle><ServerIcon size={14} /> Service</CardTitle>\n <CardMeta>Background daemon that runs schedules.</CardMeta>\n <div data-setting-id=\"service.enabled\">\n {tailscale ? (\n <div className=\"service-card\">\n <p>\n Status: <strong>{tailscale.settings.enabled ? 'enabled' : 'disabled'}</strong>\n {' '}· Tailscale installed: <strong>{tailscale.installed ? 'yes' : 'no'}</strong>\n {' '}· authenticated: <strong>{tailscale.authenticated ? 'yes' : 'no'}</strong>\n </p>\n <p className=\"muted\">\n Use <code>bizar service start</code> / <code>bizar service stop</code> in\n your terminal to control the daemon.\n </p>\n </div>\n ) : (\n <p className=\"muted\">Loading service status…</p>\n )}\n </div>\n </Card>\n\n {/* Tailscale */}\n <Card id=\"settings-tailscale\" data-section=\"tailscale\">\n <CardTitle><Plug size={14} /> Tailscale serve</CardTitle>\n <CardMeta>Expose the dashboard over your Tailscale network.</CardMeta>\n {tailscale ? (\n <>\n <p>\n Installed: <strong>{tailscale.installed ? 'yes' : 'no'}</strong>{' '}\n {tailscale.version && <span className=\"muted\">({tailscale.version})</span>}\n </p>\n <p>\n Authenticated: <strong>{tailscale.authenticated ? 'yes' : 'no'}</strong>\n </p>\n <p>\n Serve enabled: <strong>{tailscale.settings.enabled ? 'yes' : 'no'}</strong>\n </p>\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\">Port</label>\n <input\n type=\"number\"\n className=\"input\"\n value={tailscaleDraft.port}\n onChange={(e) => setTailscaleDraft((cur) => ({ ...cur, port: Number(e.target.value) || 4321 }))}\n />\n </div>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"tailscale-https\">Use HTTPS</label>\n <input\n id=\"tailscale-https\"\n type=\"checkbox\"\n checked={tailscaleDraft.https}\n onChange={(e) => setTailscaleDraft((cur) => ({ ...cur, https: e.target.checked }))}\n />\n </div>\n </div>\n <Button variant=\"primary\" onClick={onTailscaleToggle}>\n {tailscale.settings.enabled ? 'Disable serve' : 'Enable serve'}\n </Button>\n </>\n ) : (\n <p className=\"muted\">Loading Tailscale status…</p>\n )}\n </Card>\n </>\n );\n}\n","// src/web/views/settings/NotificationsSection.tsx\nimport React from 'react';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport type { Settings } from '../../lib/types';\n\ntype Props = {\n settings: Settings;\n patchNotifications: (patch: Partial<Settings['notifications']>) => void;\n};\n\nexport function NotificationsSection({ settings, patchNotifications }: Props) {\n return (\n <Card id=\"settings-notifications\" data-section=\"notifications\">\n <CardTitle>Notifications</CardTitle>\n <CardMeta>Toast triggers inside the dashboard.</CardMeta>\n <label className=\"checkbox-row\" data-setting-id=\"notifications.onAgentComplete\">\n <input\n type=\"checkbox\"\n checked={!!settings.notifications.onAgentComplete}\n onChange={(e) => patchNotifications({ onAgentComplete: e.target.checked })}\n />\n <span>Notify when an agent invocation completes</span>\n </label>\n <label className=\"checkbox-row\" data-setting-id=\"notifications.onPlanApproval\">\n <input\n type=\"checkbox\"\n checked={!!settings.notifications.onPlanApproval}\n onChange={(e) => patchNotifications({ onPlanApproval: e.target.checked })}\n />\n <span>Notify when a plan needs approval</span>\n </label>\n </Card>\n );\n}\n","// src/web/views/settings/AuthSection.tsx\nimport React, { useEffect, useState } from 'react';\nimport { Shield, Copy, KeyRound, RotateCcw } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport { Button } from '../../components/Button';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport type { Settings } from '../../lib/types';\n\ntype AuthStatus = { required: boolean; loopback: boolean; peer: string };\n\ntype Props = {\n settings: Settings;\n authStatus: AuthStatus | null;\n setAuthStatus: React.Dispatch<React.SetStateAction<AuthStatus | null>>;\n};\n\nexport function AuthSection({ authStatus, setAuthStatus }: Props) {\n const toast = useToast();\n const [authToken, setAuthToken] = useState<string>(api.getToken());\n const [revealedToken, setRevealedToken] = useState<string>('');\n\n // Probe the server once on mount\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const r = await api.probeAuthStatus();\n if (!cancelled) setAuthStatus(r);\n } catch {\n if (!cancelled) {\n setAuthStatus({ required: true, loopback: false, peer: '' });\n }\n }\n })();\n return () => { cancelled = true; };\n }, []);\n\n const onCopyToken = async () => {\n try {\n const r = await api.get<{ token: string }>('/auth/reveal');\n setRevealedToken(r.token);\n setAuthToken(r.token);\n api.setToken(r.token);\n try {\n await navigator.clipboard.writeText(r.token);\n toast.success('Token copied to clipboard.');\n } catch {\n toast.success('Token revealed — copy from the field below.');\n }\n } catch (err) {\n toast.error(`Reveal failed: ${(err as Error).message}`);\n }\n };\n\n const onRegenerateToken = async () => {\n if (!confirm('Regenerate the auth token? Anything still using the old token will start getting 401 errors immediately.')) {\n return;\n }\n try {\n const r = await api.post<{ token: string }>('/auth/regenerate');\n setRevealedToken(r.token);\n setAuthToken(r.token);\n api.setToken(r.token);\n try {\n await navigator.clipboard.writeText(r.token);\n toast.success('New token generated and copied to clipboard.');\n } catch {\n toast.success('New token generated — copy from the field below. Old token is now invalid.');\n }\n } catch (err) {\n toast.error(`Regenerate failed: ${(err as Error).message}`);\n }\n };\n\n const onSaveToken = () => {\n api.setToken(authToken.trim());\n toast.success('Token saved. The dashboard will use it on the next request.');\n };\n\n return (\n <Card id=\"settings-auth\" data-section=\"auth\">\n <CardTitle><Shield size={14} /> Authentication</CardTitle>\n <CardMeta>\n Localhost and Tailscale browser access are auto-trusted via loopback.\n A bearer token is still available for non-loopback clients and\n forced-auth mode.\n </CardMeta>\n\n <div className=\"field\" data-setting-id=\"auth.status\">\n <label className=\"field-label\">Server status</label>\n <p style={{ margin: '4px 0' }}>\n Auth required:{' '}\n <strong>{authStatus ? (authStatus.required ? 'yes' : 'no') : 'probing…'}</strong>\n </p>\n <p style={{ margin: '4px 0' }}>\n Connection:{' '}\n <strong>\n {authStatus\n ? (authStatus.loopback ? 'loopback (auto-trusted)' : 'remote')\n : 'probing…'}\n </strong>\n </p>\n <p style={{ margin: '4px 0' }}>\n Peer address:{' '}\n {authStatus?.peer ? <code>{authStatus.peer}</code> : <span className=\"muted\">probing…</span>}\n </p>\n <p className=\"muted\" style={{ fontSize: 12, margin: '4px 0' }}>\n Localhost and Tailscale browser access are auto-trusted because the\n dashboard sees a loopback peer. Paste a token only for non-loopback\n API clients/scripts, or if you force auth for every connection with{' '}\n <code>BIZAR_DASHBOARD_REQUIRE_AUTH=1</code>.\n </p>\n <p className=\"muted\" style={{ fontSize: 12, margin: '4px 0' }}>\n Dashboard tokens are generated on first boot and saved to{' '}\n <code>~/.config/bizar/dashboard-secret</code> (mode 0600).\n </p>\n <p className=\"muted\" style={{ fontSize: 12, margin: '4px 0' }}>\n For Tailscale Serve or any reverse-proxy access, paste this token\n once via the boot screen — it is saved per-origin and works for all\n subsequent visits.\n </p>\n </div>\n\n <div className=\"field\" data-setting-id=\"auth.token\">\n <label className=\"field-label\">Token (this browser)</label>\n <input\n type=\"password\"\n className=\"input mono\"\n value={authToken}\n onChange={(e) => setAuthToken(e.target.value)}\n placeholder=\"Paste token from server stderr or another browser\"\n spellCheck={false}\n autoComplete=\"off\"\n />\n <div className=\"task-form-row\" style={{ marginTop: 8 }}>\n <Button variant=\"secondary\" size=\"sm\" onClick={onSaveToken}>\n <KeyRound size={14} /> Save token\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onCopyToken}>\n <Copy size={14} /> Reveal & copy server token\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onRegenerateToken}>\n <RotateCcw size={14} /> Regenerate\n </Button>\n </div>\n {revealedToken ? (\n <p className=\"muted\" style={{ fontSize: 12, marginTop: 8 }}>\n Last revealed token (one-time): <code className=\"mono\">{revealedToken}</code>\n </p>\n ) : null}\n <p className=\"muted\" style={{ fontSize: 12, marginTop: 8 }}>\n Regenerating invalidates the current token immediately. Anything\n still using the old token will see 401 until it's updated.\n </p>\n </div>\n </Card>\n );\n}\n","// src/web/views/settings/AgentSection.tsx\nimport React, { useEffect, useState } from 'react';\nimport { Server as ServerIcon, Globe, Save } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport { Button } from '../../components/Button';\nimport { AutosaveField } from '../../components/AutosaveField';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport type { Settings } from '../../lib/types';\n\ntype Props = {\n settings: Settings;\n patchAgents: (patch: Partial<Settings['agents']>) => void;\n patchDashboard: (patch: Partial<Settings['dashboard']>) => void;\n /** Called after state is patched; parent debounces the API save */\n autoSave?: (key: keyof Settings, value: Settings[keyof Settings]) => void;\n};\n\nexport function AgentSection({ settings, patchAgents, patchDashboard, autoSave }: Props) {\n const toast = useToast();\n const [pluginOptions, setPluginOptions] = useState<Record<string, number>>({});\n\n useEffect(() => {\n api.get<Record<string, number>>('/settings/plugin-options')\n .then(setPluginOptions)\n .catch(() => { /* not persisted yet — use defaults */ });\n }, []);\n\n const onSavePluginOptions = async () => {\n try {\n await api.put('/settings/plugin-options', pluginOptions);\n toast.success('Saved — restart opencode for changes to take effect.');\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n };\n\n const onCleanupBackground = async () => {\n try {\n const r = await fetch('/api/background/cleanup', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ maxAgeDays: 7 }),\n });\n const result = await r.json();\n toast.success(`Cleaned up ${result.deleted} old instances.`);\n } catch (err) {\n toast.error(`Cleanup failed: ${(err as Error).message}`);\n }\n };\n\n return (\n <>\n {/* Agents */}\n <Card id=\"settings-agents\" data-section=\"agents\">\n <CardTitle><ServerIcon size={14} /> Agent Behavior</CardTitle>\n <CardMeta>Limits and timeouts for background agent dispatch.</CardMeta>\n <div className=\"form-row\">\n <label htmlFor=\"agents-maxParallel\">\n Max parallel agents\n <span className=\"meta-badge\">default: 6</span>\n </label>\n <input\n id=\"agents-maxParallel\"\n type=\"number\"\n min={1}\n max={20}\n value={settings.agents?.maxParallel ?? 6}\n onChange={(e) => patchAgents({ maxParallel: Math.max(1, Math.min(20, parseInt(e.target.value, 10) || 6)) })}\n />\n </div>\n <div className=\"form-row\">\n <label htmlFor=\"agents-stuckThresholdMs\">\n Stuck threshold (ms)\n <span className=\"meta-badge\">default: 600000 (10 min)</span>\n </label>\n <input\n id=\"agents-stuckThresholdMs\"\n type=\"number\"\n min={60000}\n max={3600000}\n step={60000}\n value={settings.agents?.stuckThresholdMs ?? 600000}\n onChange={(e) => patchAgents({ stuckThresholdMs: Math.max(60000, Math.min(3600000, parseInt(e.target.value, 10) || 600000)) })}\n />\n </div>\n <label className=\"checkbox-row\" data-setting-id=\"agents.autoRestart\">\n <input\n type=\"checkbox\"\n checked={!!settings.agents?.autoRestart}\n onChange={(e) => patchAgents({ autoRestart: e.target.checked })}\n />\n <span>Auto-restart stuck agents</span>\n </label>\n </Card>\n\n {/* Dashboard */}\n <Card id=\"settings-dashboard\" data-section=\"dashboard\">\n <CardTitle><Globe size={14} /> Dashboard</CardTitle>\n <CardMeta>Controls how <code>bizar</code> starts up.</CardMeta>\n <label className=\"checkbox-row\" data-setting-id=\"dashboard.autoLaunchWeb\">\n <input\n type=\"checkbox\"\n checked={settings.dashboard.autoLaunchWeb !== false}\n onChange={(e) => patchDashboard({ autoLaunchWeb: e.target.checked })}\n />\n <span>Auto-launch web UI alongside TUI</span>\n </label>\n\n <div className=\"field\" data-setting-id=\"dashboard.projectsDirectory\" style={{ marginTop: 'var(--space-4)' }}>\n <label className=\"field-label\" htmlFor=\"set-projects-directory\">Projects directory</label>\n <input\n id=\"set-projects-directory\"\n className=\"input\"\n type=\"text\"\n placeholder=\"/home/user/projects\"\n value={settings.dashboard.projectsDirectory ?? ''}\n onChange={(e) => patchDashboard({ projectsDirectory: e.target.value })}\n />\n <p className=\"field-help\">\n New projects created via the dashboard will land here, and existing project\n directories inside this folder are auto-recognized on startup.\n </p>\n {settings.dashboard.projectsDirectory && (\n <>\n {!/^\\/|^[A-Za-z]:/.test(settings.dashboard.projectsDirectory) && (\n <p style={{ color: 'var(--warning)', fontSize: 11, marginTop: 4 }}>\n Path should be absolute (start with / on Linux/Mac, or a drive letter on Windows).\n </p>\n )}\n {settings.dashboard.projectsDirectory.includes('..') && (\n <p style={{ color: 'var(--error)', fontSize: 11, marginTop: 4 }}>\n Path traversal not allowed — this will be rejected server-side.\n </p>\n )}\n </>\n )}\n </div>\n\n {/* allowedRoots textarea */}\n <div className=\"field\" data-setting-id=\"dashboard.allowedRoots\" style={{ marginTop: 'var(--space-4)' }}>\n <label className=\"field-label\" htmlFor=\"set-allowed-roots\">\n Additional allowed roots <span className=\"muted\">(advanced)</span>\n </label>\n {/* key= forces re-mount when allowedRoots changes externally (e.g. reset/reload) */}\n <AutosaveField\n key={settings.dashboard.allowedRoots?.join('\\n')}\n initialValue={(settings.dashboard.allowedRoots ?? []).join('\\n')}\n delay={1500}\n saveFn={async (v) => {\n const lines = v.split('\\n').map((l) => l.trim()).filter(Boolean);\n patchDashboard({ allowedRoots: lines });\n autoSave?.('dashboard', { allowedRoots: lines } as Settings['dashboard']);\n }}\n render={({ value, onChange, onBlur }) => (\n <textarea\n id=\"set-allowed-roots\"\n className=\"textarea\"\n rows={4}\n placeholder=\"/workspace /srv/projects\"\n value={value}\n onChange={e => onChange(e.target.value)}\n onBlur={onBlur}\n />\n )}\n />\n <p className=\"field-help\">\n Optional. Add filesystem roots beyond your home directory that the file\n browser and project scanner can access. Each path must be inside your\n home directory. One per line.\n </p>\n {(() => {\n const rawLines = (settings.dashboard.allowedRoots ?? []).join('\\n').split('\\n');\n const warnings: { key: string; msg: React.ReactNode }[] = [];\n rawLines.forEach((line, i) => {\n if (!line.trim()) return;\n if (!/^\\/|^[A-Za-z]:/.test(line)) {\n warnings.push({\n key: `noabs-${i}`,\n msg: (\n <p style={{ color: 'var(--warning)', fontSize: 11, marginTop: 2 }}>\n Line {i + 1}: "{line}" — should be absolute (start with / or a drive letter).\n </p>\n ),\n });\n }\n if (line.includes('..')) {\n warnings.push({\n key: `dots-${i}`,\n msg: (\n <p style={{ color: 'var(--error)', fontSize: 11, marginTop: 2 }}>\n Line {i + 1}: "{line}" — contains '..' (server will reject this).\n </p>\n ),\n });\n }\n });\n return warnings.map((w) => w.msg);\n })()}\n </div>\n </Card>\n\n {/* Background agents */}\n <Card id=\"settings-background\" data-section=\"background\">\n <CardTitle><ServerIcon size={14} /> Background Agents</CardTitle>\n <CardMeta>Tune plugin options. Changes take effect on next plugin restart.</CardMeta>\n\n <div className=\"form-row\">\n <label htmlFor=\"bg-maxConcurrent\">\n Max concurrent instances\n <span className=\"meta-badge\">default: 8</span>\n </label>\n <input\n id=\"bg-maxConcurrent\"\n type=\"number\"\n min={1}\n max={32}\n value={pluginOptions.maxConcurrentInstances ?? 8}\n onChange={(e) => setPluginOptions((cur) => ({ ...cur, maxConcurrentInstances: Math.max(1, Math.min(32, parseInt(e.target.value, 10) || 8)) }))}\n />\n <small className=\"muted\">Plugin option: <code>maxConcurrentInstances</code></small>\n </div>\n\n <div className=\"form-row\">\n <label htmlFor=\"bg-toolCallCap\">\n Tool-call cap\n <span className=\"meta-badge\">default: 500</span>\n </label>\n <input\n id=\"bg-toolCallCap\"\n type=\"number\"\n min={1}\n max={5000}\n value={pluginOptions.backgroundToolCallCap ?? 500}\n onChange={(e) => setPluginOptions((cur) => ({ ...cur, backgroundToolCallCap: Math.max(1, Math.min(5000, parseInt(e.target.value, 10) || 500)) }))}\n />\n <small className=\"muted\">Plugin option: <code>backgroundToolCallCap</code></small>\n </div>\n\n <div className=\"form-row\">\n <label htmlFor=\"bg-stallTimeout\">\n Stall timeout (ms)\n <span className=\"meta-badge\">default: 180000</span>\n </label>\n <input\n id=\"bg-stallTimeout\"\n type=\"number\"\n min={10000}\n max={600000}\n step={1000}\n value={pluginOptions.backgroundStallTimeoutMs ?? 180000}\n onChange={(e) => setPluginOptions((cur) => ({ ...cur, backgroundStallTimeoutMs: Math.max(10000, Math.min(600000, parseInt(e.target.value, 10) || 180000)) }))}\n />\n <small className=\"muted\">Plugin option: <code>backgroundStallTimeoutMs</code></small>\n </div>\n\n <div className=\"form-row\">\n <label htmlFor=\"bg-thinkingLoopTimeout\">\n Thinking-loop timeout (ms)\n <span className=\"meta-badge\">default: 300000</span>\n </label>\n <input\n id=\"bg-thinkingLoopTimeout\"\n type=\"number\"\n min={30000}\n max={900000}\n step={1000}\n value={pluginOptions.backgroundThinkingLoopTimeoutMs ?? 300000}\n onChange={(e) => setPluginOptions((cur) => ({ ...cur, backgroundThinkingLoopTimeoutMs: Math.max(30000, Math.min(900000, parseInt(e.target.value, 10) || 300000)) }))}\n />\n <small className=\"muted\">Plugin option: <code>backgroundThinkingLoopTimeoutMs</code></small>\n </div>\n\n <div className=\"form-row\">\n <label htmlFor=\"bg-maxInterventions\">\n Max interventions\n <span className=\"meta-badge\">default: 1</span>\n </label>\n <input\n id=\"bg-maxInterventions\"\n type=\"number\"\n min={1}\n max={3}\n value={pluginOptions.backgroundMaxInterventions ?? 1}\n onChange={(e) => setPluginOptions((cur) => ({ ...cur, backgroundMaxInterventions: Math.max(1, Math.min(3, parseInt(e.target.value, 10) || 1)) }))}\n />\n <small className=\"muted\">Plugin option: <code>backgroundMaxInterventions</code></small>\n </div>\n\n <div className=\"form-row\">\n <Button variant=\"secondary\" size=\"sm\" onClick={onSavePluginOptions}>\n <Save size={14} /> Save plugin options\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onCleanupBackground}>\n Cleanup old instances (>7 days)\n </Button>\n </div>\n\n <div className=\"form-row\">\n <small>Plugin options are read at startup. Save changes and run <code>bizar update</code> to apply.</small>\n </div>\n </Card>\n </>\n );\n}\n","// src/web/components/InviteDialog.tsx — v5.0.0 — modal to create and manage workspace invites.\nimport { useState, useEffect } from 'react';\nimport { Copy, Check, Trash2, Mail, Link2 } from 'lucide-react';\nimport { useModal } from './Modal';\nimport { Button } from './Button';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\n\nexport type InviteInfo = {\n token: string;\n email: string;\n role: 'admin' | 'editor' | 'viewer';\n invitedBy: string;\n expiresAt: string;\n};\n\ntype Props = {\n workspaceId: string;\n onInviteCreated?: () => void;\n};\n\nexport function InviteDialog({ workspaceId, onInviteCreated }: Props) {\n const modal = useModal();\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<'admin' | 'editor' | 'viewer'>('editor');\n const [invites, setInvites] = useState<InviteInfo[]>([]);\n const [loading, setLoading] = useState(false);\n const [creating, setCreating] = useState(false);\n const [copied, setCopied] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n loadInvites();\n }, [workspaceId]);\n\n async function loadInvites() {\n setLoading(true);\n try {\n const r = await api.get<{ invites: InviteInfo[] }>(`/workspaces/${workspaceId}/invites`);\n setInvites(r.invites || []);\n } catch {\n // Ignore load errors\n } finally {\n setLoading(false);\n }\n }\n\n async function handleCreate(e: React.FormEvent) {\n e.preventDefault();\n if (!email.trim()) return;\n setCreating(true);\n setError(null);\n try {\n const result = await api.post<{ token: string; url: string }>(`/workspaces/${workspaceId}/invites`, {\n email: email.trim(),\n role,\n });\n setEmail('');\n await loadInvites();\n onInviteCreated?.();\n\n // Show the invite URL in a copy dialog\n modal.open({\n title: 'Invite Link Created',\n children: (\n <div className=\"invite-link-dialog\">\n <p>Share this link with <strong>{email}</strong> to invite them as <strong>{role}</strong>:</p>\n <div className=\"invite-url-box\">\n <Link2 size={14} />\n <input\n type=\"text\"\n readOnly\n value={result.url}\n onClick={(e) => (e.target as HTMLInputElement).select()}\n />\n <button\n type=\"button\"\n className=\"invite-copy-btn\"\n onClick={() => {\n navigator.clipboard.writeText(result.url).catch(() => undefined);\n setCopied(result.token);\n setTimeout(() => setCopied(null), 2000);\n }}\n >\n {copied === result.token ? <Check size={14} /> : <Copy size={14} />}\n </button>\n </div>\n <p className=\"invite-url-note\">This link expires in 7 days.</p>\n </div>\n ),\n footer: (\n <Button variant=\"primary\" size=\"sm\" onClick={() => modal.close()}>\n Done\n </Button>\n ),\n });\n } catch (err: unknown) {\n setError((err as Error).message || 'Failed to create invite');\n } finally {\n setCreating(false);\n }\n }\n\n async function handleRevoke(token: string) {\n if (!confirm('Revoke this invite?')) return;\n try {\n await api.del(`/workspaces/${workspaceId}/invites/${token}`);\n await loadInvites();\n } catch (err: unknown) {\n setError((err as Error).message || 'Failed to revoke invite');\n }\n }\n\n function copyToClipboard(text: string, key: string) {\n navigator.clipboard.writeText(text).catch(() => undefined);\n setCopied(key);\n setTimeout(() => setCopied(null), 2000);\n }\n\n const roleColors: Record<string, string> = {\n admin: 'role-admin',\n editor: 'role-editor',\n viewer: 'role-viewer',\n };\n\n return (\n <div className=\"invite-dialog\">\n <form className=\"invite-form\" onSubmit={handleCreate}>\n <div className=\"invite-form-row\">\n <div className=\"invite-form-field\">\n <label htmlFor=\"invite-email\">Email address</label>\n <input\n id=\"invite-email\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n required\n />\n </div>\n <div className=\"invite-form-field invite-form-field-role\">\n <label htmlFor=\"invite-role\">Role</label>\n <select\n id=\"invite-role\"\n value={role}\n onChange={(e) => setRole(e.target.value as 'admin' | 'editor' | 'viewer')}\n >\n <option value=\"viewer\">Viewer</option>\n <option value=\"editor\">Editor</option>\n <option value=\"admin\">Admin</option>\n </select>\n </div>\n <Button\n type=\"submit\"\n variant=\"primary\"\n size=\"sm\"\n loading={creating}\n disabled={!email.trim()}\n >\n <Mail size={13} />\n Invite\n </Button>\n </div>\n {error && <p className=\"invite-error\">{error}</p>}\n </form>\n\n <div className=\"invite-list\">\n <h4 className=\"invite-list-title\">Pending Invites</h4>\n {loading && <p className=\"invite-loading\">Loading...</p>}\n {!loading && invites.length === 0 && (\n <p className=\"invite-empty\">No pending invites</p>\n )}\n {invites.map((inv) => (\n <div key={inv.token} className=\"invite-item\">\n <div className=\"invite-item-info\">\n <span className=\"invite-item-email\">{inv.email}</span>\n <span className={cn('invite-item-role', roleColors[inv.role])}>{inv.role}</span>\n </div>\n <div className=\"invite-item-actions\">\n <button\n type=\"button\"\n className=\"invite-action-btn\"\n title=\"Copy invite link\"\n onClick={() => {\n const url = `${window.location.origin}/accept-invite?token=${inv.token}`;\n copyToClipboard(url, inv.token);\n }}\n >\n {copied === inv.token ? <Check size={13} /> : <Copy size={13} />}\n </button>\n <button\n type=\"button\"\n className=\"invite-action-btn invite-action-revoke\"\n title=\"Revoke invite\"\n onClick={() => handleRevoke(inv.token)}\n >\n <Trash2 size={13} />\n </button>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","// src/web/views/settings/WorkspacesSection.tsx — v5.0.0 — workspace management in settings.\nimport { useState, useEffect } from 'react';\nimport { Users, Plus, Trash2, Crown, Shield, Eye, Copy, Check } from 'lucide-react';\nimport { api } from '../../lib/api';\nimport { Button } from '../../components/Button';\nimport { useModal } from '../../components/Modal';\nimport { InviteDialog } from '../../components/InviteDialog';\nimport { cn } from '../../lib/utils';\n\nexport type WorkspaceInfo = {\n id: string;\n name: string;\n ownerId: string;\n createdAt: string;\n};\n\nexport type WorkspaceWithRole = {\n workspace: WorkspaceInfo;\n role: string;\n};\n\nexport type WorkspaceMember = {\n userId: string;\n email: string;\n name: string;\n role: string;\n joinedAt: string;\n};\n\nconst ROLE_ICONS = { admin: Crown, editor: Shield, viewer: Eye };\nconst ROLE_COLORS = { admin: 'role-admin', editor: 'role-editor', viewer: 'role-viewer' };\n\nexport function WorkspacesSection() {\n const [workspaces, setWorkspaces] = useState<WorkspaceWithRole[]>([]);\n const [loading, setLoading] = useState(true);\n const [creating, setCreating] = useState(false);\n const [newName, setNewName] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [copied, setCopied] = useState<string | null>(null);\n const modal = useModal();\n\n useEffect(() => {\n loadWorkspaces();\n }, []);\n\n async function loadWorkspaces() {\n setLoading(true);\n try {\n const r = await api.get<{ workspaces: WorkspaceWithRole[] }>('/workspaces');\n setWorkspaces(r.workspaces || []);\n } catch {\n setError('Failed to load workspaces');\n } finally {\n setLoading(false);\n }\n }\n\n async function handleCreate(e: React.FormEvent) {\n e.preventDefault();\n if (!newName.trim()) return;\n setCreating(true);\n try {\n await api.post('/workspaces', { name: newName.trim() });\n setNewName('');\n await loadWorkspaces();\n } catch (err: unknown) {\n setError((err as Error).message || 'Failed to create workspace');\n } finally {\n setCreating(false);\n }\n }\n\n async function handleDelete(workspaceId: string, name: string) {\n if (!confirm(`Delete workspace \"${name}\"?`)) return;\n if (!confirm('This cannot be undone.')) return;\n try {\n await api.del(`/workspaces/${workspaceId}`);\n await loadWorkspaces();\n } catch (err: unknown) {\n setError((err as Error).message || 'Failed to delete workspace');\n }\n }\n\n function copyInviteLink(workspaceId: string) {\n navigator.clipboard.writeText(`${window.location.origin}/accept-invite?workspace=${workspaceId}`).catch(() => undefined);\n setCopied(workspaceId);\n setTimeout(() => setCopied(null), 2000);\n }\n\n if (loading) {\n return <div className=\"settings-section-loading\">Loading workspaces...</div>;\n }\n\n return (\n <div className=\"settings-section settings-section-workspaces\">\n <h3 className=\"settings-section-title\">Workspaces</h3>\n <p className=\"settings-section-desc\">\n Workspaces let you share access with team members. Each workspace has its own members, settings, and data.\n </p>\n\n {error && (\n <div className=\"settings-section-error\">\n <span>{error}</span>\n <button onClick={() => setError(null)}>×</button>\n </div>\n )}\n\n {/* Create new workspace */}\n <form className=\"workspace-create-form\" onSubmit={handleCreate}>\n <input\n type=\"text\"\n placeholder=\"New workspace name\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n maxLength={64}\n />\n <Button type=\"submit\" variant=\"primary\" size=\"sm\" loading={creating} disabled={!newName.trim()}>\n <Plus size={13} />\n Create\n </Button>\n </form>\n\n {/* Workspace list */}\n <div className=\"workspace-list\">\n {workspaces.length === 0 && (\n <p className=\"workspace-list-empty\">No workspaces yet. Create one above.</p>\n )}\n {workspaces.map(({ workspace, role }) => {\n const RoleIcon = ROLE_ICONS[role as keyof typeof ROLE_ICONS] || Eye;\n return (\n <div key={workspace.id} className=\"workspace-item\">\n <div className=\"workspace-item-info\">\n <div className=\"workspace-item-icon\">\n <Users size={16} />\n </div>\n <div className=\"workspace-item-details\">\n <span className=\"workspace-item-name\">{workspace.name}</span>\n <span className={cn('workspace-item-role', ROLE_COLORS[role as keyof typeof ROLE_COLORS])}>\n <RoleIcon size={11} />\n {role}\n </span>\n </div>\n </div>\n <div className=\"workspace-item-actions\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n title=\"Copy invite link\"\n onClick={() => copyInviteLink(workspace.id)}\n >\n {copied === workspace.id ? <Check size={13} /> : <Copy size={13} />}\n </Button>\n {role === 'admin' && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n title=\"Manage members\"\n onClick={() => {\n modal.open({\n title: `Manage \"${workspace.name}\"`,\n children: <InviteDialog workspaceId={workspace.id} onInviteCreated={() => loadWorkspaces()} />,\n width: 520,\n });\n }}\n >\n <Users size={13} />\n </Button>\n )}\n {role === 'admin' && workspaces.length > 1 && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n iconOnly\n title=\"Delete workspace\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n >\n <Trash2 size={13} />\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n","// src/views/Settings.tsx — v4 settings shell: routes to focused sub-components.\nimport React, { useEffect, useState, useRef, useCallback } from 'react';\nimport { Sliders, Save, RefreshCw, RotateCcw } from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\nimport { applyTheme, applyThemeTokens, type Settings, type SettingsResponse, type Snapshot, type TailscaleStatus } from '../lib/types';\n\nimport { SettingsSearch, type SettingsSection, type SettingsField } from '../components/SettingsSearch';\nimport { ThemeSection } from './settings/ThemeSection';\nimport { UpdatesSection } from './settings/UpdatesSection';\nimport { GeneralSection } from './settings/GeneralSection';\nimport { NetworkSection } from './settings/NetworkSection';\nimport { TailscaleSettings } from '../components/TailscaleSettings';\nimport { NotificationsSection } from './settings/NotificationsSection';\nimport { AuthSection } from './settings/AuthSection';\nimport { AgentSection } from './settings/AgentSection';\nimport { SystemLlmSection } from './settings/SystemLlmSection';\nimport { HeadroomSection } from './settings/HeadroomSection';\nimport { ActivitySection } from './settings/ActivitySection';\nimport { WorkspacesSection } from './settings/WorkspacesSection';\nimport { EnvVarsSection } from './settings/EnvVarsSection';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n /** v4.9.0 — When true, navigation uses the sidebar instead of the subnav bar. */\n settingsMode?: boolean;\n /** v4.9.0 — The active section. Null means \"show all\". Used when settingsMode is true. */\n settingsActiveSection?: string | null;\n /** v4.9.0 — Called when the user selects a section via the sidebar. */\n setSettingsActiveSection?: (id: string | null) => void;\n};\n\nconst SECTION_LINKS = [\n { id: 'theme', label: 'Theme' },\n { id: 'updates', label: 'Updates' },\n { id: 'layout', label: 'Layout' },\n { id: 'general', label: 'General' },\n { id: 'env-vars', label: 'Env Vars' },\n { id: 'network', label: 'Network' },\n { id: 'notifications', label: 'Notifications' },\n { id: 'auth', label: 'Auth' },\n { id: 'agents', label: 'Agents' },\n { id: 'dashboard', label: 'Dashboard' },\n { id: 'background', label: 'Background' },\n { id: 'system-llm', label: 'System LLM' },\n { id: 'headroom', label: 'Headroom' },\n { id: 'activity-log', label: 'Activity' },\n { id: 'about', label: 'About' },\n { id: 'workspaces', label: 'Workspaces' },\n] as const;\n\n/* ─── Settings search sections metadata ─── */\nconst SETTINGS_SECTIONS: SettingsSection[] = [\n { id: 'theme', label: 'Theme', fields: [\n { key: 'theme.presets', label: 'Accent presets', section: 'theme' },\n { key: 'theme.accent', label: 'Accent color', section: 'theme' },\n { key: 'theme.success', label: 'Success color', section: 'theme' },\n { key: 'theme.warning', label: 'Warning color', section: 'theme' },\n { key: 'theme.error', label: 'Error color', section: 'theme' },\n { key: 'theme.info', label: 'Info color', section: 'theme' },\n { key: 'theme.fontFamily', label: 'Font family', section: 'theme' },\n { key: 'theme.fontSize', label: 'Font size', section: 'theme' },\n { key: 'theme.compactMode', label: 'Compact mode', section: 'theme' },\n { key: 'theme.animations', label: 'Animations', section: 'theme' },\n ] },\n { id: 'updates', label: 'Updates', fields: [\n { key: 'updates.channel', label: 'Update channel', section: 'updates' },\n ] },\n { id: 'layout', label: 'Layout', fields: [\n { key: 'ui.layout', label: 'UI layout', section: 'layout' },\n { key: 'ui.showHeader', label: 'Show header', section: 'layout' },\n { key: 'ui.showStatusBar', label: 'Show status bar', section: 'layout' },\n { key: 'ui.defaultTab', label: 'Default tab', section: 'layout' },\n ] },\n { id: 'general', label: 'General', fields: [\n { key: 'defaultAgent', label: 'Default agent', section: 'general' },\n { key: 'defaultModel', label: 'Model override', section: 'general' },\n ] },\n { id: 'env-vars', label: 'Environment Variables', fields: [\n { key: 'env-vars.count', label: 'Env var count', section: 'env-vars' },\n ] },\n { id: 'network', label: 'Network', fields: [\n { key: 'tailscale.enabled', label: 'Tailscale Serve', section: 'network' },\n { key: 'tailscale.port', label: 'Tailscale port', section: 'network' },\n { key: 'tailscale.https', label: 'Tailscale HTTPS', section: 'network' },\n { key: 'tailscale.hostname', label: 'Tailscale hostname', section: 'network' },\n ] },\n { id: 'notifications', label: 'Notifications', fields: [\n { key: 'notifications.onAgentComplete', label: 'Notify on agent complete', section: 'notifications' },\n { key: 'notifications.onPlanApproval', label: 'Notify on plan approval', section: 'notifications' },\n ] },\n { id: 'auth', label: 'Auth', fields: [\n { key: 'auth.enabled', label: 'Auth enabled', section: 'auth' },\n { key: 'auth.loopback', label: 'Loopback mode', section: 'auth' },\n { key: 'auth.token', label: 'Auth token', section: 'auth' },\n ] },\n { id: 'agents', label: 'Agents', fields: [\n { key: 'agents.maxParallel', label: 'Max parallel agents', section: 'agents' },\n { key: 'agents.stuckThresholdMs', label: 'Stuck threshold', section: 'agents' },\n { key: 'agents.autoRestart', label: 'Auto restart', section: 'agents' },\n { key: 'workflow.artifactsEnabled', label: 'Artifacts enabled', section: 'agents' },\n { key: 'workflow.agentsDecideAutonomously', label: 'Autonomous decisions', section: 'agents' },\n ] },\n { id: 'dashboard', label: 'Dashboard', fields: [\n { key: 'dashboard.autoLaunchWeb', label: 'Auto-launch web', section: 'dashboard' },\n { key: 'dashboard.projectsDirectory', label: 'Projects directory', section: 'dashboard' },\n { key: 'dashboard.allowedRoots', label: 'Allowed roots', section: 'dashboard' },\n ] },\n { id: 'background', label: 'Background', fields: [\n { key: 'service.enabled', label: 'Background service', section: 'background' },\n { key: 'service.autostart', label: 'Auto-start service', section: 'background' },\n ] },\n { id: 'system-llm', label: 'System LLM', fields: [\n { key: 'systemLlm.enabled', label: 'System LLM enabled', section: 'system-llm' },\n ] },\n { id: 'headroom', label: 'Headroom', fields: [\n { key: 'headroom.enabled', label: 'Headroom enabled', section: 'headroom' },\n { key: 'headroom.port', label: 'Headroom port', section: 'headroom' },\n { key: 'headroom.budget', label: 'Headroom budget', section: 'headroom' },\n { key: 'headroom.backend', label: 'Headroom backend', section: 'headroom' },\n ] },\n { id: 'activity-log', label: 'Activity', fields: [\n { key: 'activity.log', label: 'Activity log', section: 'activity-log' },\n ] },\n { id: 'about', label: 'About', fields: [\n { key: 'about.version', label: 'Version', section: 'about' },\n { key: 'about.homepage', label: 'Homepage', section: 'about' },\n { key: 'about.license', label: 'License', section: 'about' },\n ] },\n];\n\nfunction SettingsViewInner({ settings: initial, refreshSnapshot, settingsMode, settingsActiveSection, setSettingsActiveSection, setActiveTab }: Props) {\n const toast = useToast();\n const [settings, setSettings] = useState<Settings>(initial);\n const [dirty, setDirty] = useState(false);\n const [saving, setSaving] = useState(false);\n const [tailscale, setTailscale] = useState<TailscaleStatus | null>(null);\n const [tailscaleDraft, setTailscaleDraft] = useState({ port: 4321, https: true, hostname: '' });\n const [authStatus, setAuthStatus] = useState<{ required: boolean; loopback: boolean; peer: string } | null>(null);\n\n // v4.9.0 — Exit settings mode by switching back to overview tab.\n const handleExitSettings = () => { setActiveTab('overview'); };\n\n useEffect(() => { setSettings(initial); setDirty(false); if (initial.theme) applyThemeTokens(initial.theme); }, [initial]);\n useEffect(() => { if (!tailscale) return; setTailscaleDraft({ port: tailscale.settings.port, https: tailscale.settings.https !== false, hostname: tailscale.settings.hostname || '' }); }, [tailscale]);\n useEffect(() => { api.get<TailscaleStatus>('/tailscale/status').then(setTailscale).catch(() => undefined); }, []);\n\n const autoSaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const autoSave = useCallback(async (key: keyof Settings, value: Settings[keyof Settings]) => {\n setSettings((cur) => ({ ...cur, [key]: value }));\n if (autoSaveTimeoutRef.current) clearTimeout(autoSaveTimeoutRef.current);\n autoSaveTimeoutRef.current = setTimeout(async () => {\n try {\n await api.put('/settings', { ...settings, [key]: value });\n } catch (err) {\n console.error('autoSave failed', err);\n }\n }, 300);\n }, [settings]);\n\n useEffect(() => () => {\n if (autoSaveTimeoutRef.current) clearTimeout(autoSaveTimeoutRef.current);\n }, []);\n\n const patchTheme = (patch: Partial<Settings['theme']>) => { setSettings((cur) => { const next = { ...cur, theme: { ...cur.theme, ...patch } }; applyThemeTokens(next.theme); return next; }); setDirty(true); };\n const patchUi = (patch: Partial<Settings['ui']>) => { setSettings((cur) => ({ ...cur, ui: { ...cur.ui, ...patch } })); setDirty(true); };\n const patchTop = <K extends keyof Settings>(key: K, value: Settings[K]) => { setSettings((cur) => ({ ...cur, [key]: value })); setDirty(true); };\n const patchNotifications = (patch: Partial<Settings['notifications']>) => { setSettings((cur) => ({ ...cur, notifications: { ...cur.notifications, ...patch } })); setDirty(true); };\n const patchAgents = (patch: Partial<Settings['agents']>) => { setSettings((cur) => ({ ...cur, agents: { ...cur.agents, ...patch } })); setDirty(true); };\n const patchDashboard = (patch: Partial<Settings['dashboard']>) => { setSettings((cur) => ({ ...cur, dashboard: { ...cur.dashboard, ...patch } })); setDirty(true); };\n\n // v4.9.0 — In settingsMode, section navigation is driven by the sidebar via\n // settingsActiveSection (shared state at App level). Outside settingsMode,\n // fall back to local hash-based state for backwards compatibility.\n const [localActiveSection, setLocalActiveSection] = useState<string | null>(() => {\n if (typeof window === 'undefined') return null;\n const hash = window.location.hash.replace(/^#settings-/, '');\n return SECTION_LINKS.some((s) => s.id === hash) ? hash : null;\n });\n\n // The effective active section: use sidebar state in settingsMode, local state otherwise.\n const activeSection = settingsMode ? (settingsActiveSection ?? null) : localActiveSection;\n\n // v4.9.0 — In settingsMode, update the shared App-level state. Otherwise update local state.\n const handleJumpSection = (id: string | null) => {\n if (settingsMode) {\n setSettingsActiveSection?.(id);\n } else {\n setLocalActiveSection(id);\n try {\n history.replaceState(null, '', id ? `#settings-${id}` : window.location.pathname);\n if (id) { const el = document.getElementById(`settings-${id}`); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }\n else window.scrollTo({ top: 0, behavior: 'smooth' });\n } catch { /* ignore */ }\n }\n if (id) {\n const el = document.getElementById(`settings-${id}`);\n if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });\n } else {\n window.scrollTo({ top: 0, behavior: 'smooth' });\n }\n };\n\n const onTailscaleToggle = async () => {\n try {\n if (tailscale?.settings.enabled) { await api.post('/tailscale/disable'); toast.success('Tailscale serve disabled.'); }\n else { await api.post('/tailscale/enable', { port: tailscaleDraft.port || 4321, https: tailscaleDraft.https, hostname: tailscaleDraft.hostname || '' }); toast.success('Tailscale serve enabled.'); }\n setTailscale(await api.get<TailscaleStatus>('/tailscale/status'));\n } catch (err) { toast.error(`Tailscale failed: ${(err as Error).message}`); }\n };\n\n const onSave = async () => {\n setSaving(true);\n try {\n const r = await api.put<SettingsResponse>('/settings', settings);\n setSettings(r.data); setDirty(false); applyTheme(r.data.theme); applyThemeTokens(r.data.theme);\n toast.success('Settings saved.'); await refreshSnapshot();\n } catch (err) { toast.error(`Save failed: ${(err as Error).message}`); }\n finally { setSaving(false); }\n };\n\n const onReload = async () => {\n try {\n const r = await api.get<SettingsResponse>('/settings');\n setSettings(r.data); setDirty(false); applyTheme(r.data.theme); applyThemeTokens(r.data.theme);\n toast.info('Settings reloaded.', 1500);\n } catch (err) { toast.error(`Reload failed: ${(err as Error).message}`); }\n };\n\n const onReset = async () => {\n if (!confirm('Reset all settings to defaults?')) return;\n try {\n const r = await api.post<SettingsResponse>('/settings/reset');\n setSettings(r.data); setDirty(false); applyTheme(r.data.theme); applyThemeTokens(r.data.theme);\n toast.success('Settings reset.'); await refreshSnapshot();\n } catch (err) { toast.error(`Reset failed: ${(err as Error).message}`); }\n };\n\n const sp = { settings, patchTheme, patchUi, patchTop, patchNotifications, patchAgents, patchDashboard };\n const about = settings.about || { version: '3.0.4', homepage: 'https://github.com/DrB0rk/BizarHarness', license: 'MIT' };\n\n // v4.9.0 — showAll means no section is filtered (activeSection is null).\n const showAll = activeSection === null;\n const sectionOf = (id: string) => activeSection === id;\n\n return (\n <div className=\"view view-settings\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\"><Sliders size={18} /> Settings</h2>\n <p className=\"view-subtitle\">Personal preferences. Changes are saved to <code>~/.config/bizar/settings.json</code>.</p>\n </div>\n <div className=\"view-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onReset}><RotateCcw size={14} /> Reset</Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onReload}><RefreshCw size={14} /> Reload</Button>\n <Button variant=\"primary\" size=\"sm\" disabled={!dirty || saving} onClick={onSave}>\n {saving ? <span className=\"btn-spinner\" /> : <Save size={14} />}{saving ? 'Saving…' : 'Save'}\n </Button>\n </div>\n </header>\n\n {settingsMode && (\n <div className=\"settings-mode-banner\">\n <span>You're in settings mode. All sections are visible in the sidebar.</span>\n <Button variant=\"secondary\" size=\"sm\" onClick={handleExitSettings}>← Back to main view</Button>\n </div>\n )}\n\n <SettingsSearch sections={SETTINGS_SECTIONS} onJump={handleJumpSection} />\n\n {/* v4.9.0 — Subnav removed; section navigation is now driven by the sidebar */}\n {/*\n <nav className=\"settings-subnav\" aria-label=\"Settings sections\">\n <button type=\"button\" className={cn('settings-subnav-button', 'settings-subnav-button-all', showAll && 'settings-subnav-button-active')} onClick={() => handleJumpSection(null)} title=\"Show all settings sections\">All</button>\n {SECTION_LINKS.map((s) => (\n <button key={s.id} type=\"button\" className={cn('settings-subnav-button', activeSection === s.id && 'settings-subnav-button-active')} onClick={() => handleJumpSection(s.id)}>{s.label}</button>\n ))}\n </nav>\n */}\n\n <div className={cn('settings-grid', activeSection && 'settings-grid-filtered')} data-active-section={activeSection || undefined}>\n {(showAll || sectionOf('theme')) && <div id=\"settings-theme\"><ThemeSection {...sp} /></div>}\n {(showAll || sectionOf('updates')) && <div id=\"settings-updates\"><UpdatesSection /></div>}\n {(showAll || sectionOf('layout')) && <div id=\"settings-general\"><GeneralSection {...sp} autoSave={autoSave} /></div>}\n {(showAll || sectionOf('env-vars')) && <div id=\"settings-env-vars\"><EnvVarsSection /></div>}\n {(showAll || sectionOf('network') || sectionOf('service') || sectionOf('tailscale')) && <div id=\"settings-network\"><NetworkSection tailscale={tailscale} tailscaleDraft={tailscaleDraft} setTailscaleDraft={setTailscaleDraft} onTailscaleToggle={onTailscaleToggle} /></div>}\n {(showAll || sectionOf('network') || sectionOf('tailscale')) && <TailscaleSettings initialStatus={tailscale} />}\n {(showAll || sectionOf('notifications')) && <div id=\"settings-notifications\"><NotificationsSection {...sp} /></div>}\n {(showAll || sectionOf('auth')) && <div id=\"settings-auth\"><AuthSection settings={settings} authStatus={authStatus} setAuthStatus={setAuthStatus} /></div>}\n {(showAll || sectionOf('agents') || sectionOf('dashboard') || sectionOf('background')) && <div id=\"settings-agents\"><AgentSection {...sp} autoSave={autoSave} /></div>}\n {(showAll || sectionOf('system-llm')) && <div id=\"settings-system-llm\"><SystemLlmSection {...sp} /></div>}\n {(showAll || sectionOf('headroom')) && <div id=\"settings-headroom\"><HeadroomSection settings={settings} setSettings={setSettings} setDirty={setDirty} /></div>}\n {(showAll || sectionOf('activity-log') || sectionOf('about')) && <div id=\"settings-activity-log\"><ActivitySection about={about} /></div>}\n {(showAll || sectionOf('workspaces')) && <div id=\"settings-workspaces\"><WorkspacesSection /></div>}\n </div>\n </div>\n );\n}\n\nexport const SettingsView = React.memo(SettingsViewInner);\n","// src/web/components/PluginPermissions.tsx — renders permission chips for a plugin.\n\nimport { Globe, FileText, Settings, Terminal, Shield, type LucideIcon } from 'lucide-react';\n\nconst PERMISSION_LABELS: Record<string, { label: string; icon: LucideIcon; color: string; description: string }> = {\n net: { label: 'Network access', icon: Globe, color: 'blue', description: 'Can make HTTP requests to external services' },\n fs: { label: 'Filesystem', icon: FileText, color: 'yellow', description: 'Can read and write files' },\n config: { label: 'Config access', icon: Settings, color: 'gray', description: 'Can read and write Bizar config' },\n log: { label: 'Logging', icon: FileText, color: 'gray', description: 'Can write to the structured log' },\n exec: { label: 'Shell execution', icon: Terminal, color: 'red', description: 'Can run shell commands' },\n};\n\nexport type PluginPermissionsProps = {\n permissions: string[];\n};\n\nexport function PluginPermissions({ permissions }: PluginPermissionsProps) {\n return (\n <div className=\"plugin-permissions\" aria-label=\"Required permissions\">\n {permissions.map((perm) => {\n const info = PERMISSION_LABELS[perm] ?? { label: perm, icon: Shield, color: 'gray', description: '' };\n const Icon = info.icon;\n return (\n <div\n key={perm}\n className={`permission-chip is-${info.color}`}\n title={info.description}\n >\n <Icon size={12} aria-hidden />\n <span>{info.label}</span>\n </div>\n );\n })}\n </div>\n );\n}\n","// src/web/components/MarketplacePluginCard.tsx — card for a plugin listed in the marketplace.\n\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { Button } from './Button';\nimport { PluginPermissions } from './PluginPermissions';\n\nexport type MarketplacePlugin = {\n id: string;\n name: string;\n version: string;\n author: string;\n description?: string;\n category: string;\n tags?: string[];\n permissions?: string[];\n};\n\nexport type MarketplacePluginCardProps = {\n plugin: MarketplacePlugin;\n onInstall: () => void;\n onView: () => void;\n};\n\nexport function MarketplacePluginCard({ plugin, onInstall, onView }: MarketplacePluginCardProps) {\n return (\n <Card className=\"marketplace-plugin-card\">\n <div className=\"marketplace-plugin-head\">\n <div>\n <CardTitle>{plugin.name}</CardTitle>\n <CardMeta>v{plugin.version} · {plugin.category}</CardMeta>\n </div>\n <div className=\"marketplace-plugin-author\">{plugin.author}</div>\n </div>\n {plugin.description && (\n <p className=\"marketplace-plugin-description\">{plugin.description}</p>\n )}\n {plugin.tags && plugin.tags.length > 0 && (\n <div className=\"marketplace-plugin-tags\">\n {plugin.tags.map((tag) => (\n <span key={tag} className=\"tag\">{tag}</span>\n ))}\n </div>\n )}\n <PluginPermissions permissions={plugin.permissions ?? []} />\n <div className=\"marketplace-plugin-actions\">\n <Button onClick={onView}>Details</Button>\n <Button variant=\"primary\" onClick={onInstall}>Install</Button>\n </div>\n </Card>\n );\n}\n","// src/web/components/InstallConfirmDialog.tsx — confirmation dialog for installing a marketplace plugin.\n\nimport { useEffect, useRef } from 'react';\nimport { AlertTriangle } from 'lucide-react';\nimport { useModal } from './Modal';\nimport { Button } from './Button';\nimport { PluginPermissions } from './PluginPermissions';\nimport type { MarketplacePlugin } from './MarketplacePluginCard';\n\nexport type InstallConfirmDialogProps = {\n plugin: MarketplacePlugin;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n installing: boolean;\n};\n\nexport function InstallConfirmDialog({ plugin, onConfirm, onCancel, installing }: InstallConfirmDialogProps) {\n const modal = useModal();\n // Track the plugin id we've opened the modal for, so we don't re-open on every render.\n const openedForRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!plugin) return;\n // Only open if we haven't already opened for this plugin.\n if (openedForRef.current === plugin.id) return;\n openedForRef.current = plugin.id;\n\n modal.open({\n title: `Install ${plugin.name}?`,\n width: 560,\n onClose: () => {\n openedForRef.current = null;\n onCancel();\n },\n children: (\n <div className=\"install-confirm\">\n <h3>{plugin.name} v{plugin.version}</h3>\n {plugin.description && <p>{plugin.description}</p>}\n\n <div className=\"install-warning\">\n <AlertTriangle size={16} />\n <p>This plugin will run code on your machine. It requests these permissions:</p>\n </div>\n\n <PluginPermissions permissions={plugin.permissions ?? []} />\n\n <div className=\"install-confirm-actions\">\n <Button onClick={onCancel} disabled={installing}>Cancel</Button>\n <Button variant=\"primary\" onClick={onConfirm} disabled={installing}>\n {installing ? 'Installing...' : 'Install'}\n </Button>\n </div>\n </div>\n ),\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [plugin, installing]);\n\n // This component manages its own modal state via useModal.\n // Render nothing in the React tree — the modal is rendered via portal.\n return null;\n}\n","// src/web/views/Marketplace.tsx — browse and install plugins from the marketplace registry.\n// v6.x — Better UX: explicit loading + registry URL, refresh button, \"showing\n// cached\" notice when the disk cache is the source, and a friendlier empty\n// state when the registry returns zero plugins. The category filter chips\n// are kept (they were already there but unverified).\nimport { useCallback, useEffect, useState } from 'react';\nimport { Store, RefreshCw, AlertTriangle, Wifi, Globe, Clock } from 'lucide-react';\nimport { MarketplacePluginCard, type MarketplacePlugin } from '../components/MarketplacePluginCard';\nimport { InstallConfirmDialog } from '../components/InstallConfirmDialog';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { Button } from '../components/Button';\nimport { useToast } from '../components/Toast';\nimport { api, ApiError } from '../lib/api';\n\ntype RegistryResponse = {\n plugins: MarketplacePlugin[];\n registry?: {\n source?: string | null;\n updatedAt?: string | null;\n };\n /** v6.x — Server indicates when this response came from the on-disk cache. */\n cached?: boolean;\n /** v6.x — When the on-disk cache was last refreshed (epoch ms). */\n cacheTimestamp?: number | null;\n /** v6.x — How many registry URLs were tried. */\n urlsTried?: number;\n};\n\nexport function Marketplace() {\n const toast = useToast();\n const [registry, setRegistry] = useState<RegistryResponse | null>(null);\n const [search, setSearch] = useState('');\n const [category, setCategory] = useState<string | null>(null);\n const [installing, setInstalling] = useState<MarketplacePlugin | null>(null);\n const [selected, setSelected] = useState<MarketplacePlugin | null>(null);\n const [loading, setLoading] = useState(true);\n const [refreshing, setRefreshing] = useState(false);\n const [error, setError] = useState<{ message: string; url?: string } | null>(null);\n\n const fetchRegistry = useCallback(async (opts: { refresh?: boolean } = {}) => {\n if (opts.refresh) setRefreshing(true);\n else setLoading(true);\n setError(null);\n try {\n const r = await api.get<RegistryResponse>('/plugins/registry');\n setRegistry(r);\n } catch (err) {\n const e = err as ApiError;\n const data = e?.data as { registryUrl?: string } | null;\n const url = data?.registryUrl;\n const message = e?.message || 'unknown error';\n setError({ message, url });\n toast.error(`Failed to load marketplace: ${message}`);\n } finally {\n setLoading(false);\n setRefreshing(false);\n }\n }, [toast]);\n\n useEffect(() => {\n fetchRegistry();\n }, [fetchRegistry]);\n\n const install = async (plugin: MarketplacePlugin) => {\n setInstalling(plugin);\n try {\n await api.post('/plugins/install', { pluginId: plugin.id });\n toast.success(`${plugin.name} installed`);\n setInstalling(null);\n setSelected(null);\n } catch (err) {\n toast.error(`Install failed: ${(err as Error).message}`);\n setInstalling(null);\n }\n };\n\n const plugins = registry?.plugins ?? [];\n const filtered = plugins.filter(\n (p) =>\n (!search || p.name.toLowerCase().includes(search.toLowerCase())) &&\n (!category || p.category === category),\n );\n const categories = [...new Set(plugins.map((p) => p.category))];\n\n const sourceUrl = registry?.registry?.source;\n const isCached = !!registry?.cached;\n const cacheTimestamp = registry?.cacheTimestamp ?? null;\n\n // ── Loading state ──────────────────────────────────────────────────────\n if (loading) {\n return (\n <div className=\"view view-marketplace\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Store size={18} aria-hidden />\n Plugin Marketplace\n </h2>\n <p className=\"view-subtitle\">\n Fetching registry from the community server…\n </p>\n </div>\n </header>\n <div className=\"view-loading\" data-testid=\"marketplace-loading\">\n <Spinner size=\"lg\" />\n <p>Fetching registry from <code>{sourceUrl ?? 'https://github.com/DrB0rk/bizar-mods'}</code>…</p>\n </div>\n </div>\n );\n }\n\n // ── Error state ────────────────────────────────────────────────────────\n if (error) {\n return (\n <div className=\"view view-marketplace\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Store size={18} aria-hidden />\n Plugin Marketplace\n </h2>\n <p className=\"view-subtitle\">\n Couldn't reach the community registry.\n </p>\n </div>\n <div className=\"view-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => fetchRegistry({ refresh: true })} disabled={refreshing}>\n {refreshing ? <Spinner size=\"sm\" /> : <RefreshCw size={14} />}\n Retry\n </Button>\n </div>\n </header>\n <EmptyState\n icon={<AlertTriangle size={32} />}\n title=\"Registry unreachable\"\n message={\n <>\n <p>All registry URLs failed to respond.</p>\n {error.url && (\n <p className=\"mono muted\" style={{ marginTop: 8, fontSize: 12 }}>\n Last tried: {error.url}\n </p>\n )}\n <p className=\"muted\" style={{ marginTop: 8, fontSize: 12 }}>{error.message}</p>\n </>\n }\n action={\n <Button variant=\"primary\" size=\"sm\" onClick={() => fetchRegistry({ refresh: true })} disabled={refreshing}>\n {refreshing ? <Spinner size=\"sm\" /> : <RefreshCw size={14} />} Try again\n </Button>\n }\n />\n </div>\n );\n }\n\n // ── Success state ──────────────────────────────────────────────────────\n return (\n <div className=\"view view-marketplace\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Store size={18} aria-hidden />\n Plugin Marketplace\n </h2>\n <p className=\"view-subtitle\">\n Discover and install plugins from the community registry.\n </p>\n </div>\n <div className=\"view-actions\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => fetchRegistry({ refresh: true })}\n disabled={refreshing}\n data-testid=\"marketplace-refresh\"\n >\n {refreshing ? <Spinner size=\"sm\" /> : <RefreshCw size={14} />}\n Refresh\n </Button>\n </div>\n </header>\n\n {/* Registry source banner */}\n <div className=\"marketplace-source-banner muted\" data-testid=\"marketplace-source\">\n <Globe size={12} aria-hidden />\n <span>\n Source:{' '}\n {sourceUrl ? (\n <code className=\"mono\">{sourceUrl}</code>\n ) : (\n <span>community registry</span>\n )}\n </span>\n {isCached && (\n <span className=\"marketplace-cache-notice\" data-testid=\"marketplace-cache-notice\">\n <Clock size={12} aria-hidden /> Showing cached results\n {cacheTimestamp && ` from ${new Date(cacheTimestamp).toLocaleString()}`}\n </span>\n )}\n <span className=\"marketplace-count-pill\" data-testid=\"marketplace-count\">\n {plugins.length} plugin{plugins.length === 1 ? '' : 's'}\n </span>\n </div>\n\n <div className=\"marketplace-search-row\">\n <input\n className=\"input\"\n type=\"search\"\n placeholder=\"Search plugins...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n style={{ maxWidth: 320 }}\n aria-label=\"Search marketplace plugins\"\n />\n </div>\n\n {categories.length > 0 && (\n <div className=\"category-chips\">\n <button\n type=\"button\"\n onClick={() => setCategory(null)}\n className={!category ? 'active' : ''}\n data-testid=\"marketplace-category-all\"\n >\n All\n </button>\n {categories.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setCategory(c)}\n className={category === c ? 'active' : ''}\n data-testid={`marketplace-category-${c.toLowerCase().replace(/\\s+/g, '-')}`}\n >\n {c}\n </button>\n ))}\n </div>\n )}\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={plugins.length === 0 ? <Wifi size={32} /> : <Store size={32} />}\n title={plugins.length === 0 ? 'No plugins published yet' : 'No plugins match your filter'}\n message={\n plugins.length === 0 ? (\n <>\n <p>The community registry is empty right now.</p>\n {sourceUrl && (\n <p className=\"mono muted\" style={{ marginTop: 8, fontSize: 12 }}>\n Check back at <code>{sourceUrl}</code> later, or publish your own.\n </p>\n )}\n </>\n ) : search ? (\n `No plugins match \"${search}\".`\n ) : category ? (\n `No plugins in \"${category}\".`\n ) : (\n 'Try a different search or category filter.'\n )\n }\n action={\n plugins.length === 0 ? (\n <Button variant=\"secondary\" size=\"sm\" onClick={() => fetchRegistry({ refresh: true })} disabled={refreshing}>\n {refreshing ? <Spinner size=\"sm\" /> : <RefreshCw size={14} />} Refresh\n </Button>\n ) : null\n }\n />\n ) : (\n <div className=\"marketplace-grid\" data-testid=\"marketplace-grid\">\n {filtered.map((p) => (\n <MarketplacePluginCard\n key={p.id}\n plugin={p}\n onInstall={() => setSelected(p)}\n onView={() => setSelected(p)}\n />\n ))}\n </div>\n )}\n\n {selected && (\n <InstallConfirmDialog\n plugin={selected}\n onConfirm={() => install(selected)}\n onCancel={() => setSelected(null)}\n installing={installing?.id === selected.id || false}\n />\n )}\n </div>\n );\n}","// src/views/Mods.tsx — list, install, enable/disable mods + mod views.\nimport { useEffect, useState } from 'react';\nimport {\n Puzzle,\n Plus,\n Trash2,\n Power,\n RefreshCw,\n Folder,\n FileText,\n FileCode,\n User,\n Terminal,\n BookOpen,\n X,\n ExternalLink,\n Globe,\n LayoutTemplate,\n Download,\n ChevronDown,\n ChevronRight,\n ShieldCheck,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\nimport type { Mod, Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype ModView = {\n id: string;\n modId: string;\n kind: 'iframe' | 'tab';\n label: string;\n description?: string;\n path?: string;\n};\n\nexport function Mods({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const modal = useModal();\n // v3.3.0 — Always start by loading from the server, not just the\n // snapshot. The snapshot can be stale if the user installed a mod\n // from the CLI or added files directly to ~/.config/bizar/mods.\n // We seed the initial state from the snapshot for instant paint\n // but always re-fetch on mount and after every mutation.\n const [mods, setMods] = useState<Mod[]>(Array.isArray(snapshot.mods) ? snapshot.mods : []);\n const [loading, setLoading] = useState(true);\n const [selected, setSelected] = useState<string | null>(null);\n const [modViews, setModViews] = useState<ModView[]>([]);\n const [iframeUrl, setIframeUrl] = useState<string | null>(null);\n // v3.16.0 — Registry browser\n const [registryOpen, setRegistryOpen] = useState(false);\n const [registry, setRegistry] = useState<{\n source: string;\n version?: number;\n updatedAt?: string;\n mods: Array<{\n id: string;\n name: string;\n latest?: string;\n description?: string;\n author?: string;\n tags?: string[];\n permissions?: string[];\n homepage?: string;\n installed?: boolean;\n installedVersion?: string | null;\n upgradeAvailable?: string | null;\n }>;\n error?: string;\n } | null>(null);\n const [registryLoading, setRegistryLoading] = useState(false);\n const [installing, setInstalling] = useState<Record<string, boolean>>({});\n\n const loadRegistry = async () => {\n setRegistryLoading(true);\n try {\n const r = await api.get<{\n registry?: { source?: string; version?: number; updatedAt?: string };\n mods?: Array<{\n id: string;\n name: string;\n latest?: string;\n description?: string;\n author?: string;\n tags?: string[];\n permissions?: string[];\n homepage?: string;\n installed?: boolean;\n installedVersion?: string | null;\n upgradeAvailable?: string | null;\n }>;\n }>('/mods/registry');\n setRegistry({\n source: r.registry?.source || '',\n version: r.registry?.version,\n updatedAt: r.registry?.updatedAt,\n mods: r.mods || [],\n });\n } catch (err) {\n setRegistry({ source: '', mods: [], error: (err as Error).message });\n } finally {\n setRegistryLoading(false);\n }\n };\n\n const onInstallFromRegistry = async (id: string) => {\n setInstalling((cur) => ({ ...cur, [id]: true }));\n try {\n const m = await api.post<Mod>('/mods', { id });\n setMods((cur) => [...cur.filter((x) => x.id !== m.id), m]);\n toast.success(`Mod \"${m.id}\" installed from registry.`);\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Install failed: ${(err as Error).message}`);\n } finally {\n setInstalling((cur) => ({ ...cur, [id]: false }));\n }\n };\n\n // v3.20.5 — Upgrade handler. Calls the dedicated `/mods/:id/upgrade`\n // endpoint (the install endpoint refuses if the mod is already on disk).\n // Reports oldVersion → newVersion in the success toast.\n const onUpgradeFromRegistry = async (id: string, backup = false) => {\n setInstalling((cur) => ({ ...cur, [id]: true }));\n try {\n const r = await api.post<{\n ok: boolean;\n from: string;\n to: string;\n backupPath: string | null;\n mod: Mod;\n }>(`/mods/${encodeURIComponent(id)}/upgrade`, { backup });\n setMods((cur) => [...cur.filter((x) => x.id !== r.mod.id), r.mod]);\n const backupNote = r.backupPath ? ` (backup at ${r.backupPath})` : '';\n toast.success(`Mod \"${id}\" upgraded v${r.from} → v${r.to}${backupNote}.`);\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Upgrade failed: ${(err as Error).message}`);\n } finally {\n setInstalling((cur) => ({ ...cur, [id]: false }));\n }\n };\n\n const reload = async () => {\n try {\n // Always pull fresh from the server. snapshot is fine for\n // optimistic initial render, but a fresh fetch makes the page\n // behave correctly even if the snapshot was empty or stale.\n const r = await api.get<{ mods: Mod[] }>('/mods');\n setMods(r.mods || []);\n try {\n const v = await api.get<{ views: ModView[] }>('/mods/views');\n setModViews(v.views || []);\n } catch {\n setModViews([]);\n }\n } catch (err) {\n toast.error(`Mods load failed: ${(err as Error).message}`);\n } finally {\n // v3.3.0 — Always clear loading even on failure so the empty\n // state can render. Without this, a network blip would leave\n // the user staring at a spinner forever.\n setLoading(false);\n }\n };\n\n // Initial load — runs once on mount.\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Re-sync from snapshot when it changes (other tabs may have\n // triggered a refreshSnapshot that updated the mod list).\n useEffect(() => {\n if (Array.isArray(snapshot.mods) && snapshot.mods !== mods) {\n setMods(snapshot.mods);\n }\n // eslint-disable-next-line react-hooks-exhaustive-deps\n }, [snapshot.mods]);\n\n const onInstall = () => {\n let pathEl: HTMLInputElement | null = null;\n modal.open({\n title: 'Install mod',\n children: (\n <div>\n <p className=\"muted\">\n Provide the absolute path to a mod folder (one that contains\n a <code>mod.json</code>). The folder will be copied to\n {' '}<code>~/.config/bizar/mods/<id>/</code>.\n </p>\n <label className=\"field-label\" htmlFor=\"install-mod-path\">Path</label>\n <input\n id=\"install-mod-path\"\n ref={(el) => (pathEl = el)}\n className=\"input\"\n type=\"text\"\n placeholder=\"/path/to/my-mod\"\n autoFocus\n />\n </div>\n ),\n footer: (\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" onClick={() => modal.close()}>Cancel</Button>\n <Button\n variant=\"primary\"\n onClick={async () => {\n const path = (pathEl?.value || '').trim();\n if (!path) {\n toast.warning('Path is required.');\n return;\n }\n try {\n const m = await api.post<Mod>('/mods', { path });\n setMods((cur) => [...cur, m]);\n toast.success(`Mod \"${m.id}\" installed.`);\n modal.close();\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Install failed: ${(err as Error).message}`);\n }\n }}\n >\n Install\n </Button>\n </div>\n ),\n });\n };\n\n const onUninstall = async (id: string) => {\n if (!confirm(`Uninstall mod \"${id}\"? This removes the folder from ~/.config/bizar/mods/.`)) return;\n try {\n await api.del(`/mods/${encodeURIComponent(id)}`);\n setMods((cur) => cur.filter((m) => m.id !== id));\n if (selected === id) setSelected(null);\n toast.success('Mod uninstalled.');\n } catch (err) {\n toast.error(`Uninstall failed: ${(err as Error).message}`);\n }\n };\n\n const onToggleEnabled = async (mod: Mod) => {\n try {\n const next = await api.put<Mod>(`/mods/${encodeURIComponent(mod.id)}`, { enabled: !mod.enabled });\n setMods((cur) => cur.map((m) => (m.id === mod.id ? next : m)));\n toast.success(`Mod ${next.enabled ? 'enabled' : 'disabled'}.`);\n } catch (err) {\n toast.error(`Toggle failed: ${(err as Error).message}`);\n }\n };\n\n const sel = mods.find((m) => m.id === selected) || null;\n\n if (loading) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n return (\n <div className=\"view view-mods\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Puzzle size={18} /> Mods ({mods.length})\n </h2>\n <p className=\"view-subtitle\">\n Extensions installed in <code>~/.config/bizar/mods/</code>.\n Mods can add agents, commands, routes, and views.\n </p>\n </div>\n <div className=\"view-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={reload}>\n <RefreshCw size={14} /> Refresh\n </Button>\n <Button variant=\"primary\" size=\"sm\" onClick={onInstall}>\n <Plus size={14} /> Install mod\n </Button>\n </div>\n </header>\n\n {mods.length === 0 ? (\n <EmptyState\n icon={<Puzzle size={32} />}\n title=\"No mods installed\"\n message=\"Mods are folders with a mod.json. Install one to extend Bizar with custom agents, commands, and views.\"\n />\n ) : (\n <div className=\"mods-layout\">\n <div className=\"mods-list\">\n {mods.map((m) => (\n <div\n key={m.id}\n className={cn('mod-list-item', selected === m.id && 'mod-list-item-active')}\n onClick={() => setSelected(m.id)}\n >\n <div className=\"mod-list-item-head\">\n <div>\n <div className=\"mod-list-item-name\">{m.name}</div>\n <div className=\"mod-list-item-meta\">v{m.version} · {m.type} · {m.author}</div>\n </div>\n <div className=\"mod-list-item-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Toggle enabled\"\n title={m.enabled ? 'Disable' : 'Enable'}\n onClick={() => onToggleEnabled(m)}\n >\n <Power size={12} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n aria-label=\"Uninstall\"\n title=\"Uninstall\"\n onClick={() => onUninstall(m.id)}\n >\n <Trash2 size={12} />\n </button>\n </div>\n </div>\n <div className=\"mod-list-item-desc ellipsis-2\" title={m.description}>\n {m.description}\n </div>\n <div className=\"mod-list-item-status\">\n <span className={`mod-mini-pill ${m.enabled ? 'mod-mini-pill-on' : 'mod-mini-pill-off'}`}>\n {m.enabled ? 'enabled' : 'disabled'}\n </span>\n </div>\n </div>\n ))}\n </div>\n {sel && <ModDetails mod={sel} />}\n </div>\n )}\n\n {/* v3.16.0 — Registry browser */}\n <Card className=\"mods-registry-card\">\n <button\n type=\"button\"\n className=\"mods-registry-head\"\n aria-expanded={registryOpen}\n aria-controls=\"mods-registry-body\"\n onClick={() => {\n if (!registry && !registryLoading) loadRegistry();\n setRegistryOpen((v) => !v);\n }}\n >\n <Globe size={14} aria-hidden />\n <span className=\"mods-registry-title\">Mod registry</span>\n <span className=\"muted\" style={{ fontSize: 11 }}>\n {registry?.mods ? `${registry.mods.length} available` : 'click to browse'}\n </span>\n <span className=\"mods-registry-spacer\" />\n {registryOpen ? <ChevronDown size={14} aria-hidden /> : <ChevronRight size={14} aria-hidden />}\n </button>\n {registryOpen && (\n <div id=\"mods-registry-body\" className=\"mods-registry-body\">\n {registryLoading ? (\n <div className=\"muted\" style={{ padding: 12, fontSize: 12 }}>Loading registry…</div>\n ) : registry?.error ? (\n <div className=\"mods-registry-error\">\n <ShieldCheck size={12} /> Could not load registry: {registry.error}\n </div>\n ) : !registry || registry.mods.length === 0 ? (\n <div className=\"muted\" style={{ padding: 12, fontSize: 12 }}>\n No mods listed in the registry yet.\n </div>\n ) : (\n <>\n {registry.source && (\n <div className=\"muted\" style={{ fontSize: 11, marginBottom: 8 }}>\n Source: <code>{registry.source}</code>\n </div>\n )}\n <div className=\"mods-registry-grid\">\n {registry.mods.map((rm) => {\n const installed = mods.some((m) => m.id === rm.id);\n const isInstalling = !!installing[rm.id];\n return (\n <div key={rm.id} className=\"mod-registry-card\">\n <div className=\"mod-registry-card-head\">\n <div className=\"mod-registry-card-name\">{rm.name}</div>\n {rm.latest && (\n <span className={cn('mod-registry-version', rm.upgradeAvailable && 'mod-registry-version-upgrade')}>\n v{rm.latest}{rm.upgradeAvailable ? ' ↑' : ''}\n </span>\n )}\n </div>\n {rm.description && (\n <div className=\"mod-registry-card-desc\">{rm.description}</div>\n )}\n <div className=\"mod-registry-card-meta\">\n {rm.author && <span className=\"muted\">by {rm.author}</span>}\n {rm.homepage && (\n <a href={rm.homepage} target=\"_blank\" rel=\"noopener noreferrer\" className=\"mod-registry-link\">\n homepage\n </a>\n )}\n </div>\n {(rm.permissions || []).length > 0 && (\n <div className=\"mod-registry-perms\">\n <ShieldCheck size={10} />\n {(rm.permissions || []).slice(0, 4).map((p) => (\n <span key={p} className=\"mod-registry-perm\">{p}</span>\n ))}\n {(rm.permissions || []).length > 4 && (\n <span className=\"mod-registry-perm-more\">+{rm.permissions!.length - 4}</span>\n )}\n </div>\n )}\n <div className=\"mod-registry-card-actions\">\n {!installed && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={isInstalling}\n onClick={() => onInstallFromRegistry(rm.id)}\n title=\"Install from registry\"\n >\n {isInstalling ? <Spinner size=\"sm\" /> : (<><Download size={12} /> Install</>)}\n </Button>\n )}\n {installed && rm.upgradeAvailable && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={isInstalling}\n onClick={() => onUpgradeFromRegistry(rm.id)}\n title={`Upgrade from v${rm.installedVersion || '?'} to v${rm.upgradeAvailable}`}\n >\n {isInstalling ? <Spinner size=\"sm\" /> : (<><Download size={12} /> Upgrade to v{rm.upgradeAvailable}</>)}\n </Button>\n )}\n {installed && !rm.upgradeAvailable && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled\n title={`Installed v${rm.installedVersion || '?'}`}\n >\n Installed v{rm.installedVersion || '?'}\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n </>\n )}\n </div>\n )}\n </Card>\n\n {/* v3.20.3 — Mod views now appear in the sidebar nav as first-class\n tabs (handled by App.tsx), so this section is a hint pointing\n users to the sidebar. */}\n {modViews.length > 0 && (\n <Card className=\"mod-views-hint\">\n <CardTitle><Globe size={14} /> Mod views</CardTitle>\n <CardMeta>\n {modViews.length} mod-supplied view{modViews.length === 1 ? '' : 's'} are now available in the sidebar navigation.\n Look for the <strong>Mods</strong> section at the bottom of the sidebar.\n </CardMeta>\n </Card>\n )}\n\n {/* Iframe panel for mod web views */}\n {iframeUrl && (\n <div className=\"mod-iframe-panel\">\n <div className=\"mod-iframe-header\">\n <span>Mod view — <a href={iframeUrl} target=\"_blank\" rel=\"noreferrer\">{iframeUrl}</a></span>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Close iframe\"\n onClick={() => setIframeUrl(null)}\n >\n <X size={14} />\n </button>\n </div>\n <iframe\n src={iframeUrl}\n className=\"mod-iframe\"\n title=\"Mod view\"\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction ModDetails({ mod }: { mod: Mod }) {\n const toast = useToast();\n const [instructions, setInstructions] = useState<{\n modId: string;\n modName: string;\n total: number;\n agents: Array<{ filename: string; path: string; fullPath: string; content: string | null }>;\n commands: Array<{ filename: string; path: string; fullPath: string; content: string | null }>;\n skills: Array<{ name: string; fullPath: string; content: string | null }>;\n } | null>(null);\n const [instructionsLoading, setInstructionsLoading] = useState(false);\n const [instructionsOpen, setInstructionsOpen] = useState(false);\n const [expandedFile, setExpandedFile] = useState<string | null>(null);\n\n const loadInstructions = async () => {\n setInstructionsLoading(true);\n try {\n const r = await api.get<typeof instructions>(`/mods/${mod.id}/instructions`);\n setInstructions(r);\n setInstructionsOpen(true);\n } catch (err) {\n toast.error(`Failed to load instructions: ${(err as Error).message}`);\n } finally {\n setInstructionsLoading(false);\n }\n };\n\n const onReinstallInstructions = async () => {\n try {\n const r = await api.post<{ ok: boolean; counts: { agents: number; commands: number; skills: number; instructions: number } }>(\n `/mods/${mod.id}/instructions/reinstall`,\n {},\n );\n toast.success(`Reinstalled: ${r.counts.agents} agents, ${r.counts.commands} commands, ${r.counts.skills} skills, ${r.counts.instructions} instructions.`);\n await loadInstructions();\n } catch (err) {\n toast.error(`Reinstall failed: ${(err as Error).message}`);\n }\n };\n\n return (\n <Card className=\"mod-details\">\n <CardTitle><FileText size={14} /> Mod details — {mod.name}</CardTitle>\n <CardMeta>\n <code>{mod.path}</code>\n </CardMeta>\n <dl className=\"env-table\">\n <dt>ID</dt>\n <dd className=\"mono\">{mod.id}</dd>\n <dt>Version</dt>\n <dd className=\"mono\">{mod.version}</dd>\n <dt>Type</dt>\n <dd className=\"mono\">{mod.type}</dd>\n <dt>Author</dt>\n <dd className=\"mono\">{mod.author || '—'}</dd>\n <dt>Bizar</dt>\n <dd className=\"mono\">{mod.bizar || '*'}</dd>\n <dt>Enabled</dt>\n <dd>{mod.enabled ? 'yes' : 'no'}</dd>\n <dt>Permissions</dt>\n <dd>\n {(mod.permissions || []).map((p) => (\n <span key={p} className=\"tag\">{p}</span>\n ))}\n {(mod.permissions || []).length === 0 && <span className=\"muted\">(none)</span>}\n </dd>\n </dl>\n <div className=\"mod-files\">\n <div className=\"muted\">Files</div>\n <ul>\n {(mod.files || []).map((f) => (\n <li key={f.path}>\n <span className=\"mod-file-cat\">{f.category}</span>\n <span className=\"mono\">{f.path}</span>\n </li>\n ))}\n </ul>\n </div>\n\n {/* v3.20 — Installed instructions (agents / commands / skills) */}\n <div className=\"mod-instructions\">\n <button\n type=\"button\"\n className=\"mod-instructions-head\"\n aria-expanded={instructionsOpen}\n aria-controls={`mod-instructions-body-${mod.id}`}\n onClick={() => {\n if (!instructions && !instructionsLoading) loadInstructions();\n setInstructionsOpen((v) => !v);\n }}\n >\n <FileCode size={14} aria-hidden />\n <span>Installed instructions</span>\n <span className=\"muted\" style={{ fontSize: 11 }}>\n {instructions ? `${instructions.total} files` : 'click to view'}\n </span>\n <span className=\"mod-instructions-spacer\" />\n {instructionsOpen ? <ChevronDown size={14} aria-hidden /> : <ChevronRight size={14} aria-hidden />}\n </button>\n {instructionsOpen && instructions && (\n <div id={`mod-instructions-body-${mod.id}`} className=\"mod-instructions-body\">\n {instructions.agents.length > 0 && (\n <div className=\"mod-instructions-section\">\n <div className=\"mod-instructions-section-title\">\n <User size={11} /> Agents ({instructions.agents.length})\n </div>\n {instructions.agents.map((f) => (\n <div key={f.filename} className=\"mod-instructions-file\">\n <div\n className=\"mod-instructions-file-head\"\n onClick={() => setExpandedFile((cur) => cur === f.filename ? null : f.filename)}\n >\n <span className=\"mono\">{f.filename}</span>\n <span className=\"muted\" style={{ fontSize: 10 }}>\n installed at {f.fullPath}\n </span>\n </div>\n {expandedFile === f.filename && (\n <pre className=\"mod-instructions-content\">\n {f.content || <em className=\"muted\">(file missing on disk)</em>}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n {instructions.commands.length > 0 && (\n <div className=\"mod-instructions-section\">\n <div className=\"mod-instructions-section-title\">\n <Terminal size={11} /> Commands ({instructions.commands.length})\n </div>\n {instructions.commands.map((f) => (\n <div key={f.filename} className=\"mod-instructions-file\">\n <div\n className=\"mod-instructions-file-head\"\n onClick={() => setExpandedFile((cur) => cur === f.filename ? null : f.filename)}\n >\n <span className=\"mono\">{f.filename}</span>\n <span className=\"muted\" style={{ fontSize: 10 }}>\n installed at {f.fullPath}\n </span>\n </div>\n {expandedFile === f.filename && (\n <pre className=\"mod-instructions-content\">\n {f.content || <em className=\"muted\">(file missing on disk)</em>}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n {instructions.skills.length > 0 && (\n <div className=\"mod-instructions-section\">\n <div className=\"mod-instructions-section-title\">\n <BookOpen size={11} /> Skills ({instructions.skills.length})\n </div>\n {instructions.skills.map((s) => (\n <div key={s.name} className=\"mod-instructions-file\">\n <div\n className=\"mod-instructions-file-head\"\n onClick={() => setExpandedFile((cur) => cur === s.name ? null : s.name)}\n >\n <span className=\"mono\">{s.name}</span>\n <span className=\"muted\" style={{ fontSize: 10 }}>\n installed at {s.fullPath}\n </span>\n </div>\n {expandedFile === s.name && (\n <pre className=\"mod-instructions-content\">\n {s.content || <em className=\"muted\">(file missing on disk)</em>}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n {instructions.total === 0 && (\n <div className=\"muted\" style={{ padding: 8, fontSize: 12 }}>\n This mod did not install any instruction files. Mods install instructions by shipping a top-level <code>INSTRUCTIONS.md</code>, an <code>agents/</code> directory, a <code>commands/</code> directory, or a <code>skills/</code> directory.\n </div>\n )}\n <div className=\"mod-instructions-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onReinstallInstructions}>\n <RefreshCw size={11} /> Reinstall from mod folder\n </Button>\n </div>\n </div>\n )}\n </div>\n </Card>\n );\n}\n","// src/components/Toggle.tsx — toggle switch control.\n\nimport { type InputHTMLAttributes, forwardRef } from 'react';\nimport { cn } from '../lib/utils';\n\nexport type ToggleProps = InputHTMLAttributes<HTMLInputElement> & {\n /** Called with the new checked value on change. */\n onChange?: (checked: boolean) => void;\n};\n\nexport const Toggle = forwardRef<HTMLInputElement, ToggleProps>(\n function Toggle({ className, checked, onChange, onClick, ...rest }, ref) {\n return (\n <label className={cn('toggle', className)}>\n <input\n ref={ref}\n type=\"checkbox\"\n role=\"switch\"\n aria-checked={checked}\n checked={checked}\n onChange={(e) => onChange?.(e.target.checked)}\n onClick={(e) => {\n onClick?.(e as unknown as React.MouseEvent<HTMLInputElement>);\n }}\n {...rest}\n />\n <span className=\"toggle-slider\" aria-hidden />\n </label>\n );\n },\n);\n","// src/web/components/PluginCard.tsx — card for one installed plugin with toggle, configure, and uninstall.\n\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { Button } from './Button';\nimport { Toggle } from './Toggle';\nimport { PluginPermissions } from './PluginPermissions';\n\nexport type InstalledPlugin = {\n id: string;\n name: string;\n version: string;\n description?: string;\n permissions?: string[];\n config?: Record<string, unknown>;\n methodCount?: number;\n invocations?: number;\n lastInvokedAt?: string | null;\n enabled?: boolean;\n};\n\nexport type PluginCardProps = {\n plugin: InstalledPlugin;\n onToggle: (id: string) => void;\n onUninstall: (id: string) => void;\n onConfigure: (id: string) => void;\n};\n\nexport function PluginCard({ plugin, onToggle, onUninstall, onConfigure }: PluginCardProps) {\n return (\n <Card>\n <div className=\"plugin-card-head\">\n <div>\n <CardTitle>{plugin.name}</CardTitle>\n <CardMeta>\n v{plugin.version} · {plugin.id}\n </CardMeta>\n </div>\n <Toggle\n checked={plugin.enabled ?? true}\n onChange={() => onToggle(plugin.id)}\n aria-label={`Toggle ${plugin.name} enabled`}\n />\n </div>\n {plugin.description && (\n <p className=\"plugin-description\">{plugin.description}</p>\n )}\n <PluginPermissions permissions={plugin.permissions ?? []} />\n <div className=\"plugin-card-actions\">\n <Button size=\"sm\" onClick={() => onConfigure(plugin.id)} aria-label={`Configure ${plugin.name}`}>\n Configure\n </Button>\n <Button size=\"sm\" variant=\"danger\" onClick={() => onUninstall(plugin.id)} aria-label={`Uninstall ${plugin.name}`}>\n Uninstall\n </Button>\n </div>\n <div className=\"plugin-card-stats\">\n {plugin.invocations ?? 0} invocations\n {plugin.lastInvokedAt\n ? ` · last used ${plugin.lastInvokedAt}`\n : ' · never used'}\n </div>\n </Card>\n );\n}\n","// src/views/Plugins.tsx — manage installed plugins and their permissions.\n\nimport { useEffect, useState } from 'react';\nimport { Puzzle, Store } from 'lucide-react';\nimport { PluginCard, type InstalledPlugin } from '../components/PluginCard';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { Button } from '../components/Button';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport type { Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nexport function Plugins({ setActiveTab }: Props) {\n const toast = useToast();\n const [plugins, setPlugins] = useState<InstalledPlugin[]>([]);\n const [loading, setLoading] = useState(true);\n const [filter, setFilter] = useState('');\n\n const load = async () => {\n try {\n const r = await api.get<{ plugins: InstalledPlugin[] }>('/plugins/installed');\n setPlugins(r.plugins);\n } catch (err) {\n toast.error(`Failed to load plugins: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void load();\n }, []);\n\n const toggle = async (id: string) => {\n try {\n // Toggle is handled by the backend via a toggle endpoint or we use update\n await api.post(`/plugins/${id}/toggle`).catch(() => {\n // Fallback: toggle is not a separate endpoint, may need PUT\n });\n await load();\n toast.success('Plugin toggled.');\n } catch (err) {\n toast.error(`Toggle failed: ${(err as Error).message}`);\n }\n };\n\n const uninstall = async (id: string) => {\n if (!confirm('Uninstall this plugin?')) return;\n try {\n await api.del(`/plugins/${id}`);\n await load();\n toast.success('Plugin uninstalled.');\n } catch (err) {\n toast.error(`Uninstall failed: ${(err as Error).message}`);\n }\n };\n\n const configure = (_id: string) => {\n // TODO: open config dialog\n };\n\n if (loading) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n const filtered = plugins.filter((p) =>\n p.name.toLowerCase().includes(filter.toLowerCase()),\n );\n\n return (\n <div className=\"view view-plugins\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Puzzle size={18} aria-hidden />\n Plugins ({plugins.length})\n </h2>\n <p className=\"view-subtitle\">\n Manage plugins installed via the marketplace.\n </p>\n </div>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setActiveTab('marketplace')}>\n <Store size={14} aria-hidden />\n Browse Marketplace\n </Button>\n </header>\n\n {plugins.length === 0 ? (\n <EmptyState\n icon={<Puzzle size={32} />}\n title=\"No plugins installed\"\n message=\"Browse the marketplace to discover and install plugins.\"\n />\n ) : (\n <>\n <div className=\"plugins-toolbar\">\n <input\n className=\"input\"\n type=\"search\"\n placeholder=\"Filter plugins…\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n aria-label=\"Filter plugins\"\n style={{ maxWidth: 320 }}\n />\n </div>\n <div className=\"plugin-grid\">\n {filtered.map((p) => (\n <PluginCard\n key={p.id}\n plugin={p}\n onToggle={toggle}\n onUninstall={uninstall}\n onConfigure={configure}\n />\n ))}\n </div>\n </>\n )}\n </div>\n );\n}\n","// src/views/ModView.tsx — render an installed mod's view (iframe or TSX tab).\n//\n// Mounted as a top-level tab in App.tsx when a mod contributes a view via\n// `entry.view` or `web/index.html`. Mods become first-class nav items\n// alongside Overview, Chat, Mods, etc.\n\nimport { Suspense, lazy, useEffect, useState } from 'react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Button } from '../components/Button';\nimport { Spinner } from '../components/Spinner';\nimport { ExternalLink, Globe, LayoutTemplate, RefreshCw, AlertTriangle } from 'lucide-react';\nimport { api } from '../lib/api';\nimport { useToast } from '../components/Toast';\n\nexport type ModView = {\n id: string;\n modId: string;\n kind: 'iframe' | 'tab';\n label: string;\n description?: string;\n path?: string;\n icon?: string;\n component?: string | null;\n};\n\ntype Props = {\n /** Mod view id, e.g. 'graphify:web'. */\n viewId: string;\n /** Force a refresh of the iframe key — bumped when the user clicks Reload. */\n reloadKey?: number;\n /** Currently active tab id — kept on the Props surface so the parent\n * (App.tsx) doesn't have to know which props the mod view consumes. */\n activeTab?: string;\n setActiveTab: (id: string) => void;\n};\n\nexport function ModView({ viewId, reloadKey, setActiveTab }: Props) {\n const toast = useToast();\n const [view, setView] = useState<ModView | null>(null);\n const [loading, setLoading] = useState(true);\n const [iframeReload, setIframeReload] = useState(0);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const r = await api.get<{ views: ModView[] }>('/mods/views');\n if (cancelled) return;\n const found = (r.views || []).find((v) => v.id === viewId);\n setView(found || null);\n } catch (err) {\n toast.error(`Failed to load mod view: ${(err as Error).message}`);\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => { cancelled = true; };\n }, [viewId, toast]);\n\n if (loading) {\n return <EmptyState title=\"Loading mod view…\" />;\n }\n\n if (!view) {\n return (\n <EmptyState\n title=\"Mod view not found\"\n message={`No view with id \"${viewId}\" is currently installed.`}\n action={<Button onClick={() => setActiveTab('mods')} variant=\"primary\" size=\"sm\">\n Open Mods\n </Button>}\n />\n );\n }\n\n // Iframe view: embed the mod's web/index.html in the dashboard.\n if (view.kind === 'iframe') {\n const src = `/api/mods/${view.modId}/web/index.html?t=${iframeReload + (reloadKey || 0)}`;\n return (\n <div className=\"mod-view-iframe-pane\">\n <div className=\"mod-view-iframe-header\">\n <span className=\"mod-view-iframe-label\">\n <Globe size={14} />\n {view.label}\n <span className=\"muted\" style={{ fontSize: 11, fontWeight: 400 }}>by {view.modId}</span>\n </span>\n <div className=\"mod-view-iframe-actions\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setIframeReload((n) => n + 1)}\n title=\"Reload this view\"\n >\n <RefreshCw size={11} /> Reload\n </Button>\n <a\n href={src}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"icon-btn\"\n title=\"Open in new tab\"\n >\n <ExternalLink size={12} />\n </a>\n </div>\n </div>\n <iframe\n key={iframeReload + (reloadKey || 0)}\n src={src}\n className=\"mod-view-iframe\"\n title={view.label}\n />\n </div>\n );\n }\n\n // v3.20.5 — Tab view (React component shipped with the mod). The\n // component is dynamically imported from /api/mods/<id>/views/<file>.\n // Mods ship a pre-built ES module (default export = React component).\n // If the registry declared a component path, we lazy-load it.\n if (view.component) {\n // Capture the narrowed values into locals so the lazy() closure\n // doesn't have to re-check nullability through `view`.\n const componentPath: string = view.component;\n const modId: string = view.modId;\n const ModComponent = lazy(() =>\n import(\n /* @vite-ignore */\n `/api/mods/${encodeURIComponent(modId)}/views/${encodeURIComponent(componentPath)}`\n ).then((m) => ({ default: m.default ?? (() => null) })),\n );\n return (\n <div className=\"mod-view-tab-pane\">\n <div className=\"mod-view-iframe-header\">\n <span className=\"mod-view-iframe-label\">\n <LayoutTemplate size={14} />\n {view.label}\n <span className=\"muted\" style={{ fontSize: 11, fontWeight: 400 }}>by {view.modId}</span>\n </span>\n </div>\n <div className=\"mod-view-tab-body\">\n <ErrorBoundary modId={view.modId} component={view.component}>\n <Suspense fallback={<div style={{ padding: 24 }}><Spinner size=\"md\" /> <span className=\"muted\">Loading mod view…</span></div>}>\n <ModComponent />\n </Suspense>\n </ErrorBoundary>\n </div>\n </div>\n );\n }\n\n // Tab kind with no component path — show a placeholder.\n return (\n <Card>\n <CardTitle>\n <LayoutTemplate size={14} /> {view.label}\n </CardTitle>\n <CardMeta>by {view.modId}</CardMeta>\n {view.description && <p className=\"muted\" style={{ marginTop: 8 }}>{view.description}</p>}\n <p className=\"muted\" style={{ fontSize: 12, marginTop: 12 }}>\n This mod declared a tab view but did not provide a component path in views/registry.json.\n Add a <code>component</code> field (e.g. <code>\"MyView.js\"</code>) and ship the file under <code>views/</code>.\n </p>\n <div style={{ marginTop: 12 }}>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setActiveTab('mods')}>\n Open Mods page\n </Button>\n </div>\n </Card>\n );\n}\n\n/**\n * Minimal error boundary for dynamically imported mod views. Catches\n * a failure to load the module (404, syntax error in the mod's code,\n * React.render-time throw) and renders a clean fallback instead of\n * crashing the dashboard shell.\n */\nimport { Component as ReactComponent, type ReactNode } from 'react';\n\nclass ErrorBoundary extends ReactComponent<\n { children: ReactNode; modId: string; component: string },\n { error: Error | null }\n> {\n state = { error: null as Error | null };\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n override componentDidCatch() {\n /* swallow — error surfaced via state */\n }\n override render() {\n if (this.state.error) {\n return (\n <div className=\"mod-view-error\">\n <AlertTriangle size={16} />\n <strong>Failed to render mod view</strong>\n <div className=\"muted\" style={{ fontSize: 12, marginTop: 6 }}>\n {this.props.modId} → {this.props.component}: {this.state.error.message}\n </div>\n </div>\n );\n }\n return this.props.children;\n }\n}\n","// src/components/ScheduleTemplateCard.tsx — template preview card for the Schedules Templates tab.\n\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { Button } from './Button';\n\nexport type ScheduleTemplate = {\n id: string;\n name: string;\n description: string;\n type: 'cron' | 'interval' | 'once' | 'webhook';\n schedule?: string;\n intervalMs?: number;\n action: {\n type: 'command' | 'agent' | 'webhook';\n target?: string;\n prompt?: string;\n method?: string;\n };\n tags?: string[];\n source?: string;\n templateFile?: string;\n};\n\ntype Props = {\n template: ScheduleTemplate;\n onUse: (template: ScheduleTemplate) => void;\n};\n\nfunction formatSchedule(template: ScheduleTemplate): string {\n if (template.type === 'cron' && template.schedule) {\n return `cron: ${template.schedule}`;\n }\n if (template.type === 'interval') {\n const ms = template.intervalMs || 0;\n const secs = ms / 1000;\n if (secs >= 3600) return `every ${secs / 3600}h`;\n if (secs >= 60) return `every ${secs / 60}m`;\n return `every ${secs}s`;\n }\n return template.type;\n}\n\nexport function ScheduleTemplateCard({ template, onUse }: Props) {\n return (\n <Card className=\"schedule-template-card\">\n <div className=\"schedule-template-header\">\n <CardTitle>{template.name}</CardTitle>\n {template.tags && template.tags.length > 0 && (\n <div className=\"schedule-template-tags\">\n {template.tags.map((tag) => (\n <span key={tag} className=\"tag\">{tag}</span>\n ))}\n </div>\n )}\n </div>\n <CardMeta>{template.description}</CardMeta>\n <div className=\"schedule-template-summary\">\n <code>{formatSchedule(template)}</code>\n {' · '}\n <code>{template.action.type}</code>\n </div>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => onUse(template)}\n aria-label={`Use template: ${template.name}`}\n >\n Use this template\n </Button>\n </Card>\n );\n}\n","// src/views/Schedules.tsx — list, create, edit, run, delete schedules for the active project.\n//\n// v3.9.0 — overhauled with structured DOW/time/TZ pickers, a reusable\n// ScheduleEditorModal that handles both create and edit, a human-readable\n// schedule label on every card, and a timezone-aware next-run display.\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Clock,\n Plus,\n PlayCircle,\n Pencil,\n Trash2,\n RefreshCw,\n History,\n ChevronDown,\n LayoutTemplate,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { api } from '../lib/api';\nimport { formatRelative } from '../lib/utils';\nimport type { Schedule, Settings, Snapshot } from '../lib/types';\nimport { ScheduleTemplateCard } from '../components/ScheduleTemplateCard';\nimport type { ScheduleTemplate } from '../components/ScheduleTemplateCard';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst TYPES = ['interval', 'cron', 'once'] as const;\nconst ACTIONS = ['command', 'agent', 'webhook'] as const;\n\n// v3.9.0 — Curated IANA timezone list. \"Other…\" lets the operator type\n// any zone croner accepts (the backend passes the string through).\nconst TIMEZONES: Array<{ value: string; label: string }> = [\n { value: 'UTC', label: 'UTC' },\n { value: 'America/New_York', label: 'America/New_York (ET)' },\n { value: 'America/Los_Angeles', label: 'America/Los_Angeles (PT)' },\n { value: 'America/Chicago', label: 'America/Chicago (CT)' },\n { value: 'Europe/London', label: 'Europe/London (UK)' },\n { value: 'Europe/Berlin', label: 'Europe/Berlin (CET)' },\n { value: 'Asia/Tokyo', label: 'Asia/Tokyo (JST)' },\n];\n\nconst MINUTE_OPTIONS = Array.from({ length: 12 }, (_, i) => i * 5); // 0,5,10,…55\nconst HOUR_OPTIONS = Array.from({ length: 24 }, (_, h) => ({\n value: h,\n label: h === 0 ? '12 AM' : h < 12 ? `${h} AM` : h === 12 ? '12 PM' : `${h - 12} PM`,\n}));\nconst DOW_OPTIONS: Array<{ value: string; label: string }> = [\n { value: '*', label: 'Every day' },\n { value: '0', label: 'Sunday' },\n { value: '1', label: 'Monday' },\n { value: '2', label: 'Tuesday' },\n { value: '3', label: 'Wednesday' },\n { value: '4', label: 'Thursday' },\n { value: '5', label: 'Friday' },\n { value: '6', label: 'Saturday' },\n];\n\nconst INTERVAL_UNITS: Array<{ value: string; label: string }> = [\n { value: 's', label: 'seconds' },\n { value: 'm', label: 'minutes' },\n { value: 'h', label: 'hours' },\n { value: 'd', label: 'days' },\n];\n\n/** Best-effort cron parser — used to pre-populate the structured form\n * when editing a schedule the user originally saved with raw cron text. */\nfunction parseCronFields(expr: string): { minute: number; hour: number; dow: string } | null {\n if (typeof expr !== 'string') return null;\n const parts = expr.trim().split(/\\s+/);\n if (parts.length !== 5) return null;\n const [m, h, , , dow] = parts;\n // We only pre-populate when every field is a literal — wildcards and\n // ranges (other than `*`) leave the form blank rather than guess.\n const minNum = parseInt(m, 10);\n const hourNum = parseInt(h, 10);\n if (!Number.isFinite(minNum) || !Number.isFinite(hourNum)) return null;\n if (m !== String(minNum) || h !== String(hourNum)) return null;\n const dowClean = dow === '*' ? '*' : parseInt(dow, 10);\n if (dowClean === null || (dow !== '*' && !Number.isFinite(dowClean))) return null;\n return { minute: minNum, hour: hourNum, dow: dow === '*' ? '*' : String(dowClean) };\n}\n\nfunction parseIntervalParts(s: string): { n: number; unit: string } | null {\n if (typeof s !== 'string') return null;\n const m = /^(\\d+)\\s*([smhd])$/i.exec(s.trim());\n if (!m) return null;\n return { n: parseInt(m[1], 10), unit: m[2].toLowerCase() };\n}\n\ntype EditorState = {\n name: string;\n type: 'cron' | 'interval' | 'once';\n cronMinute: number;\n cronHour: number;\n cronDow: string;\n showAdvanced: boolean;\n rawCron: string;\n intervalN: number;\n intervalUnit: string;\n onceAt: string; // datetime-local string\n timezone: string;\n customTimezone: string;\n actionType: 'command' | 'agent' | 'webhook';\n actionTarget: string;\n actionPrompt: string;\n skipIfBudgetLow: boolean;\n maxConcurrent: number;\n enabled: boolean;\n humanLabel: string;\n};\n\nfunction buildInitialState(initial?: Schedule): EditorState {\n if (!initial) {\n return {\n name: '',\n type: 'cron',\n cronMinute: 0,\n cronHour: 13,\n cronDow: '0',\n showAdvanced: false,\n rawCron: '0 13 * * 0',\n intervalN: 30,\n intervalUnit: 'm',\n onceAt: '',\n timezone: 'UTC',\n customTimezone: '',\n actionType: 'agent',\n actionTarget: '',\n actionPrompt: '',\n skipIfBudgetLow: false,\n maxConcurrent: 6,\n enabled: true,\n humanLabel: '',\n };\n }\n const parsed = initial.type === 'cron' ? parseCronFields(initial.schedule) : null;\n const parsedInterval = initial.type === 'interval' ? parseIntervalParts(initial.schedule) : null;\n const tz = initial.timezone || 'UTC';\n const tzKnown = TIMEZONES.some((t) => t.value === tz);\n return {\n name: initial.name || '',\n type: initial.type,\n cronMinute: parsed?.minute ?? 0,\n cronHour: parsed?.hour ?? 9,\n cronDow: parsed?.dow ?? '*',\n showAdvanced: !parsed,\n rawCron: initial.schedule,\n intervalN: parsedInterval?.n ?? 30,\n intervalUnit: parsedInterval?.unit ?? 'm',\n onceAt: initial.type === 'once' ? toDatetimeLocal(initial.schedule) : '',\n timezone: tzKnown ? tz : 'Other…',\n customTimezone: tzKnown ? '' : tz,\n actionType: initial.action.type,\n actionTarget: initial.action.target || '',\n actionPrompt: initial.action.prompt || '',\n skipIfBudgetLow: !!initial.budgetCheck?.skipIfBudgetLow,\n maxConcurrent: Number.isFinite(initial.budgetCheck?.maxConcurrent)\n ? initial.budgetCheck!.maxConcurrent!\n : 6,\n enabled: initial.enabled !== false,\n humanLabel: '',\n };\n}\n\nfunction toDatetimeLocal(iso: string): string {\n if (!iso) return '';\n try {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n // datetime-local needs YYYY-MM-DDTHH:mm in *local* time.\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n } catch {\n return '';\n }\n}\n\n/** Compose the cron / interval / once schedule string + a human label. */\nfunction composeSchedule(s: EditorState): { schedule: string; humanLabel: string } {\n if (s.type === 'cron') {\n if (s.showAdvanced) {\n return { schedule: s.rawCron.trim(), humanLabel: s.humanLabel || s.rawCron.trim() };\n }\n const cron = `${s.cronMinute} ${s.cronHour} * * ${s.cronDow}`;\n const dowName = DOW_OPTIONS.find((d) => d.value === s.cronDow)?.label || '';\n const hourLabel = HOUR_OPTIONS.find((h) => h.value === s.cronHour)?.label || `${s.cronHour}`;\n const minute = String(s.cronMinute).padStart(2, '0');\n const human =\n dowName === 'Every day'\n ? `Every day at ${hourLabel.replace(' ', '')} (min ${minute})`\n : `Every ${dowName} at ${hourLabel.replace(' ', '')} (min ${minute})`;\n return { schedule: cron, humanLabel: s.humanLabel || human };\n }\n if (s.type === 'interval') {\n const unit = INTERVAL_UNITS.find((u) => u.value === s.intervalUnit)?.label || s.intervalUnit;\n const schedule = `${s.intervalN}${s.intervalUnit}`;\n return {\n schedule,\n humanLabel: s.humanLabel || `Every ${s.intervalN} ${unit}`,\n };\n }\n // once\n if (!s.onceAt) return { schedule: '', humanLabel: s.humanLabel || '' };\n const iso = new Date(s.onceAt).toISOString();\n return {\n schedule: iso,\n humanLabel: s.humanLabel || new Date(s.onceAt).toLocaleString(),\n };\n}\n\nexport function Schedules({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const modal = useModal();\n const [schedules, setSchedules] = useState<Schedule[]>(snapshot.schedules || []);\n const [loading, setLoading] = useState(!snapshot.schedules);\n const [activeSection, setActiveSection] = useState<'schedules' | 'templates'>('schedules');\n const [templates, setTemplates] = useState<ScheduleTemplate[]>([]);\n const [templatesLoading, setTemplatesLoading] = useState(false);\n\n const reload = async () => {\n try {\n const r = await api.get<{ schedules: Schedule[]; projectId: string | null }>(\n '/projects/active/schedules',\n );\n setSchedules(r.schedules || []);\n } catch (err) {\n toast.error(`Schedules load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n const loadTemplates = async () => {\n setTemplatesLoading(true);\n try {\n const r = await api.get<{ templates: ScheduleTemplate[] }>('/schedules/templates');\n setTemplates(r.templates || []);\n } catch (err) {\n toast.error(`Templates load failed: ${(err as Error).message}`);\n } finally {\n setTemplatesLoading(false);\n }\n };\n\n useEffect(() => {\n if (snapshot.schedules?.length || snapshot.schedules) {\n setSchedules(snapshot.schedules || []);\n setLoading(false);\n return;\n }\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [snapshot.schedules]);\n\n useEffect(() => {\n if (activeSection === 'templates' && templates.length === 0) {\n loadTemplates();\n }\n }, [activeSection]);\n\n const openEditor = (initial?: Schedule) => {\n modal.open({\n title: initial ? `Edit schedule: ${initial.name}` : 'New schedule',\n width: 640,\n children: (\n <ScheduleEditorModal\n initial={initial}\n onClose={modal.close}\n onSubmitted={async (saved) => {\n setSchedules((cur) => {\n const idx = cur.findIndex((s) => s.id === saved.id);\n if (idx === -1) return [...cur, saved];\n const copy = cur.slice();\n copy[idx] = saved;\n return copy;\n });\n toast.success(initial ? 'Schedule updated.' : 'Schedule created.');\n modal.close();\n await refreshSnapshot();\n }}\n onError={(msg) => toast.error(msg)}\n />\n ),\n });\n };\n\n const onRun = async (s: Schedule) => {\n try {\n const r = await api.post<{ ok: boolean; schedule: Schedule; runResult: { error?: string; stdout?: string } }>(\n `/schedules/${encodeURIComponent(s.id)}/run`,\n );\n toast.success(r.ok ? 'Schedule ran.' : `Run failed: ${r.runResult?.error || 'unknown'}`);\n await reload();\n } catch (err) {\n toast.error(`Run failed: ${(err as Error).message}`);\n }\n };\n\n const onDelete = async (s: Schedule) => {\n if (!confirm(`Delete schedule \"${s.name}\"?`)) return;\n try {\n await api.del(`/schedules/${encodeURIComponent(s.id)}`);\n setSchedules((cur) => cur.filter((x) => x.id !== s.id));\n toast.success('Schedule deleted.');\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const onUseTemplate = async (template: ScheduleTemplate) => {\n try {\n const saved = await api.post<Schedule>('/schedules/from-template', {\n templateId: template.id,\n });\n setSchedules((cur) => [...cur, saved]);\n setActiveSection('schedules');\n toast.success(`Schedule \"${saved.name}\" created from template.`);\n await refreshSnapshot();\n } catch (err) {\n toast.error(`Failed to create schedule: ${(err as Error).message}`);\n }\n };\n\n if (loading) {\n return (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n );\n }\n\n return (\n <div className=\"view view-schedules\">\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <div className=\"view-title-row\">\n <h2 className=\"view-title\">\n <Clock size={18} /> Schedules\n </h2>\n <div className=\"view-section-tabs\">\n <button\n type=\"button\"\n className={`tab-btn ${activeSection === 'schedules' ? 'tab-btn-active' : ''}`}\n onClick={() => setActiveSection('schedules')}\n >\n Schedules ({schedules.length})\n </button>\n <button\n type=\"button\"\n className={`tab-btn ${activeSection === 'templates' ? 'tab-btn-active' : ''}`}\n onClick={() => setActiveSection('templates')}\n >\n <LayoutTemplate size={14} /> Templates\n </button>\n </div>\n </div>\n <p className=\"view-subtitle\">\n {activeSection === 'schedules'\n ? <>Recurring tasks for <strong>{snapshot.activeProject?.name || '(none)'}</strong>. Service daemon runs them at the right time.</>\n : 'Example schedules you can use as a starting point.'}\n </p>\n </div>\n <div className=\"view-actions\">\n {activeSection === 'schedules' && (\n <>\n <Button variant=\"secondary\" size=\"sm\" onClick={reload} aria-label=\"Refresh schedules\">\n <RefreshCw size={14} /> Refresh\n </Button>\n <Button variant=\"primary\" size=\"sm\" onClick={() => openEditor()}>\n <Plus size={14} /> New schedule\n </Button>\n </>\n )}\n {activeSection === 'templates' && (\n <Button variant=\"secondary\" size=\"sm\" onClick={loadTemplates} disabled={templatesLoading}>\n <RefreshCw size={14} /> Refresh\n </Button>\n )}\n </div>\n </header>\n\n {activeSection === 'templates' ? (\n templatesLoading ? (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n ) : templates.length === 0 ? (\n <EmptyState\n icon={<LayoutTemplate size={32} />}\n title=\"No templates\"\n message=\"No schedule templates found. Templates are loaded from templates/schedules/.\"\n />\n ) : (\n <div className=\"schedule-template-grid\">\n {templates.map((t) => (\n <ScheduleTemplateCard key={t.id} template={t} onUse={onUseTemplate} />\n ))}\n </div>\n )\n ) : schedules.length === 0 ? (\n <EmptyState\n icon={<Clock size={32} />}\n title=\"No schedules\"\n message={\n snapshot.activeProject\n ? 'Add a schedule to run commands, webhooks, or agent tasks on a cron / interval / one-shot basis.'\n : 'Activate a project first to scope schedules.'\n }\n />\n ) : (\n <div className=\"schedule-grid\">\n {schedules.map((s) => (\n <Card key={s.id} className=\"schedule-card\">\n <div className=\"schedule-card-head\">\n <div>\n <CardTitle>{s.name}</CardTitle>\n <CardMeta>\n <code>{s.type}</code> ·{' '}\n <span title={s.schedule}>{humanizeSchedule(s) || s.schedule}</span>\n {s.timezone && s.timezone !== 'UTC' ? <> · <code>{s.timezone}</code></> : null}\n {' · '}\n <span className={s.enabled ? 'status-on' : 'status-neutral'}>\n {s.enabled ? 'enabled' : 'disabled'}\n </span>\n </CardMeta>\n </div>\n <div className=\"schedule-card-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => openEditor(s)}>\n <Pencil size={12} /> Edit\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onRun(s)}>\n <PlayCircle size={12} /> Run now\n </Button>\n <button\n type=\"button\"\n className=\"icon-btn icon-btn-danger\"\n aria-label=\"Delete\"\n title=\"Delete\"\n onClick={() => onDelete(s)}\n >\n <Trash2 size={12} />\n </button>\n </div>\n </div>\n <div className=\"schedule-card-action\">\n <span className=\"muted\">action:</span>{' '}\n <code>\n {s.action.type} {s.action.target}\n </code>\n {s.action.type === 'agent' && s.action.prompt && (\n <div className=\"schedule-card-prompt\">\n <span className=\"muted\">prompt:</span> {s.action.prompt}\n </div>\n )}\n </div>\n {s.budgetCheck?.skipIfBudgetLow && (\n <div className=\"schedule-card-budget\">\n <span className=\"muted\">budget gate:</span>{' '}\n skip if concurrent ≥ {s.budgetCheck.maxConcurrent ?? 6}\n </div>\n )}\n <div className=\"schedule-card-times\">\n <div>\n <span className=\"muted\">last</span>{' '}\n {s.lastRun ? formatRelative(s.lastRun) : '—'}\n {s.lastResult && (\n <span className={`tag ${resultTagClass(s.lastResult)}`}>{s.lastResult}</span>\n )}\n {s.lastError && (\n <span className=\"muted schedule-card-error\" title={s.lastError}>\n {' '}— {truncate(s.lastError, 80)}\n </span>\n )}\n </div>\n <div>\n <span className=\"muted\">next</span>{' '}\n {s.nextRun ? (\n <span title={new Date(s.nextRun).toISOString()}>\n {formatNextRun(s.nextRun, s.timezone)}\n </span>\n ) : (\n '—'\n )}\n {s.nextRun && (\n <span className=\"muted\"> · {formatRelative(s.nextRun)}</span>\n )}\n </div>\n </div>\n {s.history && s.history.length > 0 && (\n <details className=\"schedule-card-history\">\n <summary>\n <History size={12} /> {s.history.length} run{s.history.length === 1 ? '' : 's'}\n </summary>\n <ul>\n {s.history.slice(-10).reverse().map((h, i) => (\n <li key={i}>\n <span className=\"tabular-nums muted\">{formatRelative(h.ts)}</span>{' '}\n <span className={`tag ${resultTagClass(h.result)}`}>{h.result}</span>\n {h.error && <span className=\"muted\"> — {truncate(h.error, 80)}</span>}\n </li>\n ))}\n </ul>\n </details>\n )}\n </Card>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Editor modal */\n/* ------------------------------------------------------------------ */\n\nfunction ScheduleEditorModal({\n initial,\n onClose,\n onSubmitted,\n onError,\n}: {\n initial?: Schedule;\n onClose: () => void;\n onSubmitted: (saved: Schedule) => void | Promise<void>;\n onError: (msg: string) => void;\n}) {\n const [state, setState] = useState<EditorState>(() => buildInitialState(initial));\n const [submitting, setSubmitting] = useState(false);\n const tzSelectValue = useMemo(() => {\n if (TIMEZONES.some((t) => t.value === state.timezone)) return state.timezone;\n return 'Other…';\n }, [state.timezone]);\n\n const update = <K extends keyof EditorState>(key: K, value: EditorState[K]) => {\n setState((cur) => ({ ...cur, [key]: value }));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const trimmedName = state.name.trim();\n if (!trimmedName) {\n onError('Name is required.');\n return;\n }\n const composed = composeSchedule(state);\n if (!composed.schedule) {\n onError('Schedule value is required.');\n return;\n }\n if (!state.actionTarget.trim()) {\n onError('Action target is required.');\n return;\n }\n const tz = state.timezone === 'Other…' ? state.customTimezone.trim() : state.timezone;\n const actionPayload: Record<string, unknown> = {\n type: state.actionType,\n target: state.actionTarget.trim(),\n };\n if (state.actionType === 'agent' && state.actionPrompt.trim()) {\n actionPayload.prompt = state.actionPrompt.trim();\n }\n const payload: Record<string, unknown> = {\n name: trimmedName,\n type: state.type,\n schedule: composed.schedule,\n timezone: tz || 'UTC',\n action: actionPayload,\n budgetCheck: {\n maxConcurrent: state.maxConcurrent,\n skipIfBudgetLow: state.skipIfBudgetLow,\n },\n enabled: state.enabled,\n };\n setSubmitting(true);\n try {\n const saved = initial\n ? await api.put<Schedule>(`/schedules/${encodeURIComponent(initial.id)}`, payload)\n : await api.post<Schedule>('/schedules', payload);\n await onSubmitted(saved);\n } catch (err) {\n onError(`${initial ? 'Update' : 'Create'} failed: ${(err as Error).message}`);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form className=\"schedule-form\" onSubmit={handleSubmit}>\n <label className=\"field-label\" htmlFor=\"schedule-name\">Name</label>\n <input\n id=\"schedule-name\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Weekly code review\"\n value={state.name}\n onChange={(e) => update('name', e.target.value)}\n autoFocus\n />\n\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-type\">Type</label>\n <select\n id=\"schedule-type\"\n className=\"select\"\n value={state.type}\n onChange={(e) => update('type', e.target.value as EditorState['type'])}\n >\n {TYPES.map((t) => (\n <option key={t} value={t}>{t}</option>\n ))}\n </select>\n </div>\n </div>\n\n {state.type === 'cron' && (\n <div className=\"schedule-cron-group\">\n {!state.showAdvanced && (\n <>\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-dow\">Day of week</label>\n <select\n id=\"schedule-dow\"\n className=\"select\"\n value={state.cronDow}\n onChange={(e) => update('cronDow', e.target.value)}\n >\n {DOW_OPTIONS.map((d) => (\n <option key={d.value} value={d.value}>{d.label}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-hour\">Hour</label>\n <select\n id=\"schedule-hour\"\n className=\"select\"\n value={String(state.cronHour)}\n onChange={(e) => update('cronHour', parseInt(e.target.value, 10))}\n >\n {HOUR_OPTIONS.map((h) => (\n <option key={h.value} value={String(h.value)}>{h.label}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-minute\">Minute</label>\n <select\n id=\"schedule-minute\"\n className=\"select\"\n value={String(state.cronMinute)}\n onChange={(e) => update('cronMinute', parseInt(e.target.value, 10))}\n >\n {MINUTE_OPTIONS.map((m) => (\n <option key={m} value={String(m)}>{String(m).padStart(2, '0')}</option>\n ))}\n </select>\n </div>\n </div>\n </>\n )}\n {state.showAdvanced && (\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-cron-expr\">Cron expression</label>\n <input\n id=\"schedule-cron-expr\"\n className=\"input\"\n type=\"text\"\n value={state.rawCron}\n onChange={(e) => update('rawCron', e.target.value)}\n placeholder=\"0 13 * * 0\"\n />\n </div>\n )}\n <button\n type=\"button\"\n className=\"link-btn\"\n onClick={() => update('showAdvanced', !state.showAdvanced)}\n aria-expanded={state.showAdvanced}\n >\n <ChevronDown\n size={12}\n style={{\n transform: state.showAdvanced ? 'rotate(180deg)' : 'none',\n transition: 'transform 0.15s',\n }}\n />\n {state.showAdvanced ? 'Hide advanced' : 'Advanced (raw cron)'}\n </button>\n </div>\n )}\n\n {state.type === 'interval' && (\n <div className=\"task-form-row\">\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"schedule-interval-n\">Every</label>\n <input\n id=\"schedule-interval-n\"\n className=\"input\"\n type=\"number\"\n min={1}\n value={state.intervalN}\n onChange={(e) => update('intervalN', parseInt(e.target.value, 10) || 1)}\n />\n </div>\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"schedule-interval-unit\">Unit</label>\n <select\n id=\"schedule-interval-unit\"\n className=\"select\"\n value={state.intervalUnit}\n onChange={(e) => update('intervalUnit', e.target.value)}\n >\n {INTERVAL_UNITS.map((u) => (\n <option key={u.value} value={u.value}>{u.label}</option>\n ))}\n </select>\n </div>\n </div>\n )}\n\n {state.type === 'once' && (\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-once-at\">Run at</label>\n <input\n id=\"schedule-once-at\"\n className=\"input\"\n type=\"datetime-local\"\n value={state.onceAt}\n onChange={(e) => update('onceAt', e.target.value)}\n />\n </div>\n )}\n\n <div className=\"task-form-row\">\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"schedule-timezone\">Timezone</label>\n <select\n id=\"schedule-timezone\"\n className=\"select\"\n value={tzSelectValue}\n onChange={(e) => update('timezone', e.target.value)}\n >\n {TIMEZONES.map((t) => (\n <option key={t.value} value={t.value}>{t.label}</option>\n ))}\n <option value=\"Other…\">Other…</option>\n </select>\n </div>\n {state.timezone === 'Other…' && (\n <div className=\"task-form-field\" style={{ flex: 1 }}>\n <label className=\"field-label\" htmlFor=\"schedule-custom-tz\">IANA name</label>\n <input\n id=\"schedule-custom-tz\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Europe/Paris\"\n value={state.customTimezone}\n onChange={(e) => update('customTimezone', e.target.value)}\n />\n </div>\n )}\n </div>\n\n <div className=\"task-form-row\">\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-action-type\">Action</label>\n <select\n id=\"schedule-action-type\"\n className=\"select\"\n value={state.actionType}\n onChange={(e) => update('actionType', e.target.value as EditorState['actionType'])}\n >\n {ACTIONS.map((t) => (\n <option key={t} value={t}>{t}</option>\n ))}\n </select>\n </div>\n <div className=\"task-form-field\" style={{ flex: 2 }}>\n <label className=\"field-label\" htmlFor=\"schedule-action-target\">Target</label>\n <input\n id=\"schedule-action-target\"\n className=\"input\"\n type=\"text\"\n placeholder={state.actionType === 'webhook' ? 'https://...' : state.actionType === 'agent' ? 'agent name or task ref' : 'echo hi'}\n value={state.actionTarget}\n onChange={(e) => update('actionTarget', e.target.value)}\n />\n </div>\n </div>\n\n {state.actionType === 'agent' && (\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-action-prompt\">Prompt (what to send the agent)</label>\n <textarea\n id=\"schedule-action-prompt\"\n className=\"input\"\n rows={3}\n placeholder=\"Review open PRs for stale code review comments and nudge reviewers.\"\n value={state.actionPrompt}\n onChange={(e) => update('actionPrompt', e.target.value)}\n />\n </div>\n )}\n\n <fieldset className=\"schedule-budget-card\">\n <legend>Budget pre-flight</legend>\n <label className=\"checkbox-row\">\n <input\n id=\"schedule-skip-budget\"\n type=\"checkbox\"\n checked={state.skipIfBudgetLow}\n onChange={(e) => update('skipIfBudgetLow', e.target.checked)}\n />\n <span>Skip this run when too many background tasks are already running.</span>\n </label>\n <div className=\"task-form-field\">\n <label className=\"field-label\" htmlFor=\"schedule-max-concurrent\">Max concurrent bg tasks</label>\n <input\n id=\"schedule-max-concurrent\"\n className=\"input\"\n type=\"number\"\n min={1}\n max={64}\n value={state.maxConcurrent}\n onChange={(e) => update('maxConcurrent', parseInt(e.target.value, 10) || 6)}\n disabled={!state.skipIfBudgetLow}\n />\n </div>\n </fieldset>\n\n <label className=\"checkbox-row\">\n <input\n id=\"schedule-enabled\"\n type=\"checkbox\"\n checked={state.enabled}\n onChange={(e) => update('enabled', e.target.checked)}\n />\n <span>Enabled</span>\n </label>\n\n <div className=\"modal-footer-actions\">\n <Button variant=\"ghost\" type=\"button\" onClick={onClose} disabled={submitting}>\n Cancel\n </Button>\n <Button variant=\"primary\" type=\"submit\" disabled={submitting}>\n {initial ? 'Save' : 'Create'}\n </Button>\n </div>\n </form>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction humanizeSchedule(s: Schedule): string {\n if (s.type !== 'cron') return s.schedule;\n const parsed = parseCronFields(s.schedule);\n if (!parsed) return s.schedule;\n const dowName = DOW_OPTIONS.find((d) => d.value === parsed.dow)?.label || '';\n const hourLabel = HOUR_OPTIONS.find((h) => h.value === parsed.hour)?.label || `${parsed.hour}`;\n const minute = String(parsed.minute).padStart(2, '0');\n if (dowName === 'Every day') return `Every day at ${hourLabel} :${minute}`;\n return `Every ${dowName} at ${hourLabel} :${minute}`;\n}\n\nfunction formatNextRun(iso: string, tz?: string | null): string {\n try {\n return new Date(iso).toLocaleString(undefined, {\n timeZone: tz || undefined,\n weekday: 'long',\n hour: 'numeric',\n minute: '2-digit',\n month: 'short',\n day: 'numeric',\n });\n } catch {\n return new Date(iso).toLocaleString();\n }\n}\n\nfunction resultTagClass(result: string): string {\n if (result === 'success') return 'tag-success';\n if (result === 'skipped') return 'tag-warning';\n return 'tag-error';\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return s.slice(0, max - 1) + '…';\n}","// src/views/Skills.tsx — v4.0.0 skills browser: scans all local SKILL.md sources.\nimport React, { useEffect, useMemo, useState } from 'react';\nimport {\n Sparkles,\n Search,\n RefreshCw,\n ExternalLink,\n XCircle,\n BookOpen,\n Folder,\n Users,\n Package,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { useModal } from '../components/Modal';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\nimport type { Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype Skill = {\n name: string;\n description: string;\n source: 'shipped' | 'user' | 'project';\n path: string;\n body?: string;\n};\n\ntype Tab = { id: 'all' | 'shipped' | 'user' | 'project'; label: string; icon: typeof Sparkles };\n\nconst TABS: Tab[] = [\n { id: 'all', label: 'All', icon: Sparkles },\n { id: 'shipped', label: 'Shipped', icon: Package },\n { id: 'user', label: 'User', icon: Users },\n { id: 'project', label: 'Project', icon: Folder },\n];\n\nconst SOURCE_LABEL: Record<string, string> = {\n shipped: 'Shipped',\n user: 'User',\n project: 'Project',\n};\n\nconst SOURCE_ICON: Record<string, typeof Package> = {\n shipped: Package,\n user: Users,\n project: Folder,\n};\n\nfunction SkillsInner({ snapshot, refreshSnapshot }: Props) {\n const toast = useToast();\n const modal = useModal();\n const [skills, setSkills] = useState<Skill[]>([]);\n const [counts, setCounts] = useState({ shipped: 0, user: 0, project: 0, all: 0 });\n const [loading, setLoading] = useState(true);\n const [activeTab, setActiveTab] = useState<'all' | 'shipped' | 'user' | 'project'>('all');\n const [searchQ, setSearchQ] = useState('');\n const [searchResults, setSearchResults] = useState<Skill[] | null>(null);\n const [searching, setSearching] = useState(false);\n\n const reload = async () => {\n setLoading(true);\n try {\n const d = await api.get<{ skills: Skill[]; counts: Record<string, number> }>('/skills');\n setSkills(d.skills || []);\n setCounts({ shipped: d.counts?.shipped ?? 0, user: d.counts?.user ?? 0, project: d.counts?.project ?? 0, all: (d.skills || []).length });\n } catch (err) {\n toast.error(`Skills load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => { reload(); }, []);\n\n // Debounced search\n useEffect(() => {\n if (!searchQ.trim()) {\n setSearchResults(null);\n return;\n }\n setSearching(true);\n const id = setTimeout(async () => {\n try {\n const d = await api.get<{ results: Skill[] }>(\n `/skills/search?q=${encodeURIComponent(searchQ.trim())}`,\n );\n setSearchResults(d.results || []);\n } catch (err) {\n toast.error(`Search failed: ${(err as Error).message}`);\n } finally {\n setSearching(false);\n }\n }, 280);\n return () => clearTimeout(id);\n }, [searchQ]);\n\n const displayed = useMemo<Skill[]>(() => {\n if (searchResults !== null) return searchResults;\n if (activeTab === 'all') return skills;\n return skills.filter((s) => s.source === activeTab);\n }, [skills, activeTab, searchResults]);\n\n const onRefresh = async () => {\n try {\n await api.post('/skills/refresh', {});\n toast.success('Skills refreshed.');\n await reload();\n } catch (err) {\n toast.error(`Refresh failed: ${(err as Error).message}`);\n }\n };\n\n const onShowDetail = async (skill: Skill) => {\n try {\n const full = await api.get<Skill>(\n `/skills/${encodeURIComponent(skill.source)}/${encodeURIComponent(skill.name)}`,\n );\n modal.open({\n title: full.name,\n width: 640,\n children: (\n <div className=\"skill-detail\">\n <div className=\"skill-detail-meta\">\n <span className=\"skill-source-badge\" data-source={full.source}>\n {SOURCE_LABEL[full.source] || full.source}\n </span>\n <code className=\"mono text-sm muted\">{full.path}</code>\n </div>\n {full.description && (\n <p className=\"skill-detail-desc\">{full.description}</p>\n )}\n {full.body && (\n <div className=\"skill-detail-body\">\n <pre className=\"skill-body-pre\">{full.body}</pre>\n </div>\n )}\n </div>\n ),\n footer: (\n <Button variant=\"ghost\" onClick={() => modal.close()}>Close</Button>\n ),\n });\n } catch {\n // Fallback: show what we already have\n modal.open({\n title: skill.name,\n width: 560,\n children: (\n <div className=\"skill-detail\">\n <div className=\"skill-detail-meta\">\n <span className=\"skill-source-badge\" data-source={skill.source}>\n {SOURCE_LABEL[skill.source] || skill.source}\n </span>\n <code className=\"mono text-sm muted\">{skill.path}</code>\n </div>\n {skill.description && (\n <p className=\"skill-detail-desc\">{skill.description}</p>\n )}\n </div>\n ),\n footer: (\n <Button variant=\"ghost\" onClick={() => modal.close()}>Close</Button>\n ),\n });\n }\n };\n\n return (\n <div className=\"view view-skills\">\n {/* ── Header ─────────────────────────────────────────────────────── */}\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Sparkles size={18} /> Skills\n </h2>\n <p className=\"view-subtitle\">\n Browse all available skills — shipped, user, and project-local.\n </p>\n </div>\n <div className=\"view-actions\">\n <div className=\"search-input\">\n <Search size={14} aria-hidden />\n <label htmlFor=\"skills-search\" className=\"sr-only\">Search skills</label>\n <input\n id=\"skills-search\"\n className=\"input\"\n type=\"text\"\n placeholder=\"Search skills…\"\n value={searchQ}\n onChange={(e) => setSearchQ(e.target.value)}\n aria-label=\"Search skills\"\n />\n {searchQ && (\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Clear search\"\n onClick={() => setSearchQ('')}\n >\n <XCircle size={12} />\n </button>\n )}\n </div>\n <Button variant=\"secondary\" size=\"sm\" onClick={onRefresh}>\n <RefreshCw size={14} /> Refresh\n </Button>\n </div>\n </header>\n\n {/* ── Source tabs ────────────────────────────────────────────────── */}\n {!searchQ.trim() && (\n <div className=\"skills-tabs\">\n {TABS.map((tab) => {\n const Icon = tab.icon;\n const count = tab.id === 'all'\n ? counts.all\n : counts[tab.id as keyof typeof counts] ?? 0;\n return (\n <button\n key={tab.id}\n type=\"button\"\n className={cn('skills-tab', activeTab === tab.id && 'skills-tab-active')}\n onClick={() => setActiveTab(tab.id)}\n >\n <Icon size={14} />\n <span>{tab.label}</span>\n <span className=\"skills-tab-count\">{count}</span>\n </button>\n );\n })}\n </div>\n )}\n\n {/* ── Search results ───────────────────────────────────────────── */}\n {searchQ.trim() && (\n <section className=\"skills-section\">\n <h3 className=\"skills-section-title\">\n <Search size={14} /> Search results\n {searching && <Spinner size=\"sm\" />}\n </h3>\n {searching ? (\n <div className=\"skills-grid\">\n {[0, 1, 2].map((i) => (\n <div key={i} className=\"skill-card skill-card-skeleton\" />\n ))}\n </div>\n ) : searchResults && searchResults.length === 0 ? (\n <EmptyState\n icon={<Search size={28} />}\n title=\"No matches\"\n message={`No skills match \"${searchQ}\".`}\n />\n ) : (\n <div className=\"skills-grid\">\n {(searchResults || []).map((s, i) => (\n <SkillCard\n key={`search-${i}`}\n skill={s}\n onShow={() => onShowDetail(s)}\n searchQ={searchQ}\n />\n ))}\n </div>\n )}\n </section>\n )}\n\n {/* ── Skills grid (tab view) ───────────────────────────────────── */}\n {!searchQ.trim() && (\n <section className=\"skills-section\">\n {loading ? (\n <div className=\"view-loading\"><Spinner size=\"lg\" /></div>\n ) : displayed.length === 0 ? (\n <EmptyState\n icon={<BookOpen size={28} />}\n title=\"No skills here\"\n message={\n activeTab === 'all'\n ? 'No skills found. Install skills with the skills CLI or add SKILL.md files to a skills directory.'\n : `No skills in the ${SOURCE_LABEL[activeTab]} tab.`\n }\n />\n ) : (\n <div className=\"skills-grid\">\n {displayed.map((s, i) => (\n <SkillCard\n key={`${s.source}-${s.name}-${i}`}\n skill={s}\n onShow={() => onShowDetail(s)}\n />\n ))}\n </div>\n )}\n </section>\n )}\n\n {/* ── Footer ────────────────────────────────────────────────────── */}\n {!searchQ.trim() && (\n <footer className=\"view-footer\">\n <span className=\"text-sm muted\">\n Skills are discovered from{' '}\n <code>~/.opencode/skills/</code>,{' '}\n <code>~/.agents/skills/</code>,{' '}\n <code>bizar-dash/skills/</code>, and project-local directories.\n </span>\n </footer>\n )}\n </div>\n );\n}\n\n// ── SkillCard ─────────────────────────────────────────────────────────────────\n\nfunction SkillCard({\n skill,\n onShow,\n searchQ = '',\n}: {\n skill: Skill;\n onShow: () => void;\n searchQ?: string;\n}) {\n const Icon = SOURCE_ICON[skill.source] || Package;\n const desc = skill.description\n ? skill.description.length > 200\n ? skill.description.slice(0, 200) + '…'\n : skill.description\n : 'No description.';\n\n return (\n <Card variant=\"elevated\" interactive className=\"skill-card\">\n <div className=\"skill-card-head\">\n <div\n className=\"skill-card-icon\"\n style={{ background: `color-mix(in srgb, var(--accent) 12%, transparent)` }}\n >\n <Icon size={18} />\n </div>\n <div className=\"skill-card-title-area\">\n <div className=\"skill-card-title\">\n {highlightMatch(skill.name, searchQ)}\n </div>\n <span className=\"skill-source-badge\" data-source={skill.source}>\n {SOURCE_LABEL[skill.source] || skill.source}\n </span>\n </div>\n </div>\n <p className=\"skill-card-desc\">{desc}</p>\n <div className=\"skill-card-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onShow}>\n <ExternalLink size={12} /> View\n </Button>\n </div>\n </Card>\n );\n}\n\n/** Simple substring highlight — wraps matched term in <mark>. */\nfunction highlightMatch(text: string, q: string): React.ReactNode {\n if (!q.trim()) return text;\n const idx = text.toLowerCase().indexOf(q.toLowerCase());\n if (idx < 0) return text;\n return (\n <>\n {text.slice(0, idx)}\n <mark className=\"skill-highlight\">{text.slice(idx, idx + q.length)}</mark>\n {text.slice(idx + q.length)}\n </>\n );\n}\nexport const Skills = React.memo(SkillsInner);\n","// src/web/views/memory/MemoryOverview.tsx — Memory tab overview panel (KPIs + sub-system pills).\nimport { useEffect, useState } from 'react';\nimport {\n Activity,\n Brain,\n CheckCircle2,\n Database,\n FileText,\n GitBranch,\n RefreshCw,\n Search,\n ShieldCheck,\n Sparkles,\n XCircle,\n AlertTriangle,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { formatTime, cn } from '../../lib/utils';\n\nexport type HealthResponse = {\n score: number;\n status: 'healthy' | 'degraded' | 'unhealthy' | 'unconfigured';\n checks: Array<{ name: string; pass: boolean; detail: string }>;\n message: string;\n};\n\nexport type VaultStats = {\n exists: boolean;\n vaultRoot: string;\n mode: string;\n noteCount: number;\n totalSize: number;\n folderCount: number;\n folders: string[];\n lastModified: number | null;\n gitClean: boolean | null;\n gitBranch: string | null;\n};\n\ntype MemoryStatus = {\n initialized: boolean;\n mode?: string;\n projectId?: string;\n vaultRoot?: string;\n branch?: string;\n gitClean?: boolean | null;\n noteCount?: number;\n lastSecretScan?: string | null;\n};\n\ntype LightragStats = {\n running: boolean;\n pid: number | null;\n host: string;\n port: number;\n indexedApprox: number;\n queryCountLast24h: number;\n lastReindexAt: string | null;\n avgResponseMs?: number | null;\n noteCount?: number;\n};\n\ntype StorageStats = {\n total: number;\n breakdown: Array<{ name: string; path: string; size: number }>;\n};\n\nexport type MemoryOverviewData = {\n health: HealthResponse;\n vault: VaultStats;\n lightrag: {\n running: boolean;\n pid: number | null;\n host: string;\n port: number;\n indexedApprox: number;\n queryCountLast24h: number;\n lastReindexAt: string | null;\n };\n storage: {\n total: number;\n breakdown: Array<{ name: string; path: string; size: number }>;\n };\n};\n\ntype Props = {\n refreshKey: number;\n onRefresh: () => void;\n setActiveSubPanel: (panel: 'overview' | 'lightrag' | 'obsidian' | 'git' | 'semantic' | 'config') => void;\n};\n\nexport function MemoryOverview({ refreshKey, onRefresh, setActiveSubPanel }: Props) {\n const toast = useToast();\n const [data, setData] = useState<MemoryOverviewData | null>(null);\n const [vaultPath, setVaultPath] = useState<string>('');\n const [loading, setLoading] = useState(true);\n\n const reload = async (signal?: AbortSignal) => {\n setLoading(true);\n try {\n const [health, status, lightrag, storage] = await Promise.all([\n api.get<HealthResponse>('/memory/health', signal).catch(() => null),\n api.get<MemoryStatus>('/memory/status', signal).catch(() => null),\n api.get<LightragStats>('/memory/lightrag/stats', signal).catch(() => null),\n api.get<StorageStats>('/memory/storage', signal).catch(() => null),\n ]);\n // v6.x — Surface the resolved vault path as a top-level piece of state\n // so the section header can display it instead of relying on\n // derived fields. Resolves the \"(loading…)\" UI bug in the Config panel.\n setVaultPath(status?.vaultRoot || '');\n setData({\n health: health || {\n score: 0,\n status: 'unconfigured',\n checks: [],\n message: 'memory not initialised',\n },\n vault: {\n exists: !!status?.initialized,\n vaultRoot: status?.vaultRoot || '',\n mode: status?.mode || 'local-only',\n noteCount: status?.noteCount || 0,\n totalSize: storage?.total || 0,\n folderCount: 0,\n folders: [],\n lastModified: null,\n gitClean: status?.gitClean ?? null,\n gitBranch: status?.branch || null,\n },\n lightrag: lightrag || {\n running: false,\n pid: null,\n host: '127.0.0.1',\n port: 9621,\n indexedApprox: 0,\n queryCountLast24h: 0,\n lastReindexAt: null,\n },\n storage: storage || { total: 0, breakdown: [] },\n });\n } catch (err) {\n toast.error(`Memory overview failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n const ctrl = new AbortController();\n void reload(ctrl.signal);\n return () => ctrl.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n if (loading && !data) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading memory overview…</p>\n </div>\n );\n }\n if (!data) {\n return <div className=\"muted\">No memory data available.</div>;\n }\n\n const { health, vault, lightrag, storage } = data;\n const scoreColor =\n health.score >= 80 ? 'var(--success)' :\n health.score >= 50 ? 'var(--warning)' :\n 'var(--error)';\n\n return (\n <div className=\"memory-overview\">\n {/* ── Health score hero ─────────────────────────────────────────── */}\n <Card variant=\"elevated\" className=\"memory-health-hero\">\n <div className=\"memory-health-score\" style={{ borderColor: scoreColor }}>\n <span className=\"memory-health-score-value\" style={{ color: scoreColor }}>\n {health.score}\n </span>\n <span className=\"memory-health-score-label\">/ 100</span>\n </div>\n <div className=\"memory-health-meta\">\n <h3 className=\"memory-health-title\">\n <Activity size={16} />\n Memory health ·{' '}\n <span style={{ color: scoreColor }}>{health.status}</span>\n </h3>\n <p className=\"memory-health-message\">{health.message}</p>\n {/* v6.x — Vault path surfaced as a top-level piece of context.\n Resolves the \"(loading…)\" stuck-state in the Config panel. */}\n <p className=\"memory-health-vault mono muted\" data-testid=\"memory-overview-vault-path\">\n <span className=\"memory-health-vault-label\">Vault:</span>{' '}\n {vaultPath || <em>not initialised</em>}\n </p>\n <Button variant=\"ghost\" size=\"sm\" onClick={onRefresh}>\n <RefreshCw size={12} /> Refresh\n </Button>\n </div>\n </Card>\n\n {/* ── Source pills ─────────────────────────────────────────────── */}\n <div className=\"memory-source-pills\">\n <button\n type=\"button\"\n className=\"memory-source-pill\"\n onClick={() => setActiveSubPanel('lightrag')}\n >\n <Brain size={14} />\n <span>LightRAG</span>\n <span className={cn('memory-source-pill-status', lightrag.running ? 'on' : 'off')}>\n {lightrag.running ? 'running' : 'stopped'}\n </span>\n </button>\n <button\n type=\"button\"\n className=\"memory-source-pill\"\n onClick={() => setActiveSubPanel('obsidian')}\n >\n <FileText size={14} />\n <span>Obsidian Vault</span>\n <span className={cn('memory-source-pill-status', vault.exists ? 'on' : 'off')}>\n {vault.noteCount} notes\n </span>\n </button>\n <button\n type=\"button\"\n className=\"memory-source-pill\"\n onClick={() => setActiveSubPanel('git')}\n >\n <GitBranch size={14} />\n <span>Git Sync</span>\n <span className={cn(\n 'memory-source-pill-status',\n vault.gitClean === null ? 'na' : vault.gitClean ? 'on' : 'warn',\n )}>\n {vault.gitClean === null ? '—' : vault.gitClean ? 'clean' : 'dirty'}\n </span>\n </button>\n <button\n type=\"button\"\n className=\"memory-source-pill\"\n onClick={() => setActiveSubPanel('semantic')}\n >\n <Search size={14} />\n <span>Semantic Search</span>\n <span className=\"memory-source-pill-status na\">cross-source</span>\n </button>\n </div>\n\n {/* ── KPI grid ─────────────────────────────────────────────────── */}\n <div className=\"memory-stat-grid\">\n <StatCard\n icon={<Brain size={16} />}\n label=\"LightRAG\"\n value={lightrag.running ? `running · ${lightrag.queryCountLast24h} q/24h` : 'stopped'}\n sub={lightrag.running ? `${lightrag.indexedApprox} indexed chunks` : 'start from the LightRAG panel'}\n onClick={() => setActiveSubPanel('lightrag')}\n />\n <StatCard\n icon={<FileText size={16} />}\n label=\"Obsidian\"\n value={`${vault.noteCount} notes`}\n sub={vault.folderCount > 0 ? `${vault.folderCount} folders` : 'no folders yet'}\n onClick={() => setActiveSubPanel('obsidian')}\n />\n <StatCard\n icon={<GitBranch size={16} />}\n label=\"Git\"\n value={vault.gitBranch ? `branch ${vault.gitBranch}` : 'local-only'}\n sub={\n vault.gitClean === null ? 'not configured' :\n vault.gitClean ? 'clean working tree' :\n 'dirty — commit or pull'\n }\n onClick={() => setActiveSubPanel('git')}\n />\n <StatCard\n icon={<Database size={16} />}\n label=\"Storage\"\n value={formatBytes(storage.total)}\n sub={storage.breakdown.length > 0\n ? `${storage.breakdown.length} dirs tracked`\n : 'no memory data on disk'}\n />\n <StatCard\n icon={<Sparkles size={16} />}\n label=\"Last reindex\"\n value={lightrag.lastReindexAt ? formatTime(lightrag.lastReindexAt) : 'never'}\n sub=\"lightrag ingest\"\n onClick={() => setActiveSubPanel('lightrag')}\n />\n <StatCard\n icon={<ShieldCheck size={16} />}\n label=\"Health\"\n value={`${health.score}/100`}\n sub={health.status}\n onClick={() => setActiveSubPanel('config')}\n />\n </div>\n\n {/* ── Health checks detail ─────────────────────────────────────── */}\n {health.checks.length > 0 && (\n <Card>\n <CardTitle>Health checks</CardTitle>\n <CardMeta>Composite score across all memory subsystems</CardMeta>\n <ul className=\"memory-check-list\">\n {health.checks.map((c) => (\n <li key={c.name} className=\"memory-check-row\">\n <span className=\"memory-check-icon\">\n {c.pass\n ? <CheckCircle2 size={14} style={{ color: 'var(--success)' }} />\n : c.name.includes('secrets') || c.name.includes('schema')\n ? <AlertTriangle size={14} style={{ color: 'var(--warning)' }} />\n : <XCircle size={14} style={{ color: 'var(--error)' }} />}\n </span>\n <span className=\"memory-check-name\">{c.name}</span>\n <span className=\"memory-check-detail muted\">{c.detail}</span>\n </li>\n ))}\n </ul>\n </Card>\n )}\n </div>\n );\n}\n\nfunction StatCard({\n icon,\n label,\n value,\n sub,\n onClick,\n}: {\n icon: React.ReactNode;\n label: string;\n value: string;\n sub: string;\n onClick?: () => void;\n}) {\n const Comp = onClick ? 'button' : 'div';\n return (\n <Comp\n type={onClick ? 'button' : undefined}\n onClick={onClick}\n className={cn('memory-stat-card', onClick && 'memory-stat-card-clickable')}\n >\n <div className=\"memory-stat-icon\">{icon}</div>\n <div className=\"memory-stat-body\">\n <div className=\"memory-stat-label\">{label}</div>\n <div className=\"memory-stat-value\">{value}</div>\n <div className=\"memory-stat-sub muted\">{sub}</div>\n </div>\n </Comp>\n );\n}\n\nfunction formatBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}","// src/web/views/memory/LightragPanel.tsx — LightRAG controls, stats, query.\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n Brain,\n CheckCircle2,\n Database,\n Loader2,\n Play,\n Power,\n PowerOff,\n RefreshCw,\n RotateCw,\n Search as SearchIcon,\n Sparkles,\n XCircle,\n Zap,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { formatTime, cn } from '../../lib/utils';\n\ntype Stats = {\n running: boolean;\n pid: number | null;\n host: string;\n port: number;\n workingDir: string;\n lastReindexAt: string | null;\n lastReindexOk: boolean | null;\n lastReindexInserted: number | null;\n lastReindexFailed: number | null;\n noteCount: number;\n indexedApprox: number;\n queryCountLast24h: number;\n avgResponseMs: number | null;\n};\n\ntype Config = {\n enabled: boolean;\n host: string;\n port: number;\n workingDir: string;\n llmBinding: string;\n embeddingBinding: string;\n llmModel: string;\n embeddingModel: string;\n};\n\ntype Props = { refreshKey: number };\n\nexport function LightragPanel({ refreshKey }: Props) {\n const toast = useToast();\n const [stats, setStats] = useState<Stats | null>(null);\n const [config, setConfig] = useState<Config | null>(null);\n const [logTail, setLogTail] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n const [busy, setBusy] = useState<string | null>(null);\n const [query, setQuery] = useState('');\n const [queryResult, setQueryResult] = useState<{ ok: boolean; text: string } | null>(null);\n\n const reload = async () => {\n setLoading(true);\n try {\n const [s, c, log] = await Promise.all([\n api.get<Stats>('/memory/lightrag/stats').catch(() => null),\n api.get<{ lightrag?: Config }>('/memory/config').then((r) => r?.lightrag || null).catch(() => null),\n api.get<{ lines: string[] }>('/memory/lightrag/log').catch(() => ({ lines: [] })),\n ]);\n setStats(s);\n setConfig(c);\n setLogTail(log?.lines || []);\n } catch (err) {\n toast.error(`LightRAG status failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n const runCommand = async (key: string, fn: () => Promise<unknown>, successMsg: string) => {\n setBusy(key);\n try {\n await fn();\n toast.success(successMsg);\n await reload();\n } catch (err) {\n toast.error(`${key} failed: ${(err as Error).message}`);\n } finally {\n setBusy(null);\n }\n };\n\n const onStart = () => runCommand('start', () => api.post('/memory/lightrag/start', {}), 'LightRAG starting…');\n const onStop = () => runCommand('stop', () => api.post('/memory/lightrag/stop', {}), 'LightRAG stopping…');\n const onRestart = async () => {\n setBusy('restart');\n try {\n await api.post('/memory/lightrag/stop', {}).catch(() => {});\n await new Promise((r) => setTimeout(r, 600));\n await api.post('/memory/lightrag/start', {});\n toast.success('LightRAG restarted.');\n await reload();\n } catch (err) {\n toast.error(`Restart failed: ${(err as Error).message}`);\n } finally {\n setBusy(null);\n }\n };\n const onReindex = () => runCommand('reindex', () => api.post('/memory/lightrag/reindex', {}), 'Reindex complete.');\n const onRebuild = () => runCommand('rebuild', () => api.post('/memory/lightrag/rebuild-graph', {}), 'Graph rebuilt.');\n\n const onQuery = async () => {\n if (!query.trim()) return;\n setBusy('query');\n try {\n const r = await api.get<{ ok: boolean; q: string; semantic?: { ok: boolean; response?: unknown; error?: string } }>(\n `/memory/query?q=${encodeURIComponent(query)}&topK=8`,\n );\n const text = r?.semantic?.response\n ? (typeof r.semantic.response === 'string'\n ? r.semantic.response\n : JSON.stringify(r.semantic.response))\n : (r?.semantic?.error || 'No response');\n setQueryResult({ ok: !!r?.semantic?.ok, text });\n } catch (err) {\n setQueryResult({ ok: false, text: (err as Error).message });\n } finally {\n setBusy(null);\n }\n };\n\n if (loading && !stats) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading LightRAG status…</p>\n </div>\n );\n }\n if (!stats) {\n return <div className=\"muted\">No LightRAG data available.</div>;\n }\n\n return (\n <div className=\"memory-panel-content\">\n {/* ── Status header ───────────────────────────────────────────── */}\n <Card variant=\"elevated\">\n <CardTitle>\n <Brain size={14} />\n LightRAG\n <span className={cn('memory-source-pill-status', stats.running ? 'on' : 'off')}>\n {stats.running ? 'running' : 'stopped'}\n </span>\n </CardTitle>\n <CardMeta>\n {stats.running\n ? <>PID <code>{stats.pid}</code> · {stats.host}:{stats.port}</>\n : <>Server is not running. Start it from the controls below.</>}\n </CardMeta>\n <div className=\"memory-action-row\">\n <Button variant=\"primary\" size=\"sm\" onClick={onStart} disabled={!!busy || stats.running}>\n {busy === 'start' ? <Loader2 size={12} className=\"memory-spin\" /> : <Play size={12} />}\n Start\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onStop} disabled={!!busy || !stats.running}>\n {busy === 'stop' ? <Loader2 size={12} className=\"memory-spin\" /> : <PowerOff size={12} />}\n Stop\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onRestart} disabled={!!busy}>\n {busy === 'restart' ? <Loader2 size={12} className=\"memory-spin\" /> : <Power size={12} />}\n Restart\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onReindex} disabled={!!busy}>\n {busy === 'reindex' ? <Loader2 size={12} className=\"memory-spin\" /> : <RefreshCw size={12} />}\n Reindex all\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onRebuild} disabled={!!busy} title=\"Wipe working dir + reindex from scratch\">\n {busy === 'rebuild' ? <Loader2 size={12} className=\"memory-spin\" /> : <RotateCw size={12} />}\n Rebuild graph\n </Button>\n </div>\n </Card>\n\n {/* ── Stat cards ─────────────────────────────────────────────── */}\n <div className=\"memory-stat-grid\">\n <StatBox icon={<Database size={14} />} label=\"Indexed chunks (approx)\" value={String(stats.indexedApprox)} />\n <StatBox icon={<FileTextCount n={stats.noteCount} />} label=\"Notes in vault\" value={String(stats.noteCount)} />\n <StatBox icon={<Zap size={14} />} label=\"Queries last 24h\" value={String(stats.queryCountLast24h)} />\n <StatBox\n icon={<Sparkles size={14} />}\n label=\"Avg response\"\n value={stats.avgResponseMs !== null ? `${stats.avgResponseMs} ms` : '—'}\n />\n <StatBox\n icon={stats.lastReindexOk ? <CheckCircle2 size={14} /> : stats.lastReindexOk === false ? <XCircle size={14} /> : <RefreshCw size={14} />}\n label=\"Last reindex\"\n value={stats.lastReindexAt ? formatTime(stats.lastReindexAt) : 'never'}\n sub={stats.lastReindexInserted !== null\n ? `${stats.lastReindexInserted} inserted${stats.lastReindexFailed ? `, ${stats.lastReindexFailed} failed` : ''}`\n : undefined}\n />\n </div>\n\n {/* ── Quick search ───────────────────────────────────────────── */}\n <Card>\n <CardTitle>\n <SearchIcon size={14} /> Quick search\n </CardTitle>\n <CardMeta>Send a natural-language query to the LightRAG index.</CardMeta>\n <div className=\"memory-search-row\">\n <label htmlFor=\"lightrag-query\" className=\"sr-only\">Search LightRAG</label>\n <input\n id=\"lightrag-query\"\n type=\"text\"\n className=\"input\"\n placeholder=\"e.g. how does the memory service write notes?\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onQuery();\n }}\n disabled={busy === 'query'}\n aria-label=\"Search LightRAG\"\n />\n <Button variant=\"primary\" onClick={onQuery} disabled={busy === 'query' || !query.trim()}>\n {busy === 'query' ? <Loader2 size={12} className=\"memory-spin\" /> : <SearchIcon size={12} />}\n Query\n </Button>\n </div>\n {queryResult && (\n <div className={cn('memory-query-result', queryResult.ok ? 'ok' : 'err')}>\n <pre className=\"mono text-sm\">{queryResult.text}</pre>\n </div>\n )}\n </Card>\n\n {/* ── Config snapshot ────────────────────────────────────────── */}\n {config && (\n <Card>\n <CardTitle>Configuration</CardTitle>\n <CardMeta>Effective values from <code>.bizar/memory.json</code> + env defaults.</CardMeta>\n <dl className=\"memory-config-row\">\n <dt>LLM binding</dt>\n <dd><code>{config.llmBinding}</code> · <code>{config.llmModel}</code></dd>\n <dt>Embedding</dt>\n <dd><code>{config.embeddingBinding}</code> · <code>{config.embeddingModel}</code></dd>\n <dt>Host</dt>\n <dd><code>{config.host}:{config.port}</code></dd>\n <dt>Working dir</dt>\n <dd className=\"mono ellipsis\" title={config.workingDir}>{config.workingDir}</dd>\n </dl>\n </Card>\n )}\n\n {/* ── Log tail ───────────────────────────────────────────────── */}\n {logTail.length > 0 && (\n <Card>\n <CardTitle>\n <RefreshCw size={14} /> Server log (tail)\n </CardTitle>\n <CardMeta>Last {logTail.length} lines from <code>lightrag.log</code></CardMeta>\n <pre className=\"memory-log-tail mono text-xs\">\n {logTail.join('\\n')}\n </pre>\n </Card>\n )}\n </div>\n );\n}\n\nfunction StatBox({\n icon,\n label,\n value,\n sub,\n}: {\n icon: React.ReactNode;\n label: string;\n value: string;\n sub?: string;\n}) {\n return (\n <div className=\"memory-stat-card\">\n <div className=\"memory-stat-icon\">{icon}</div>\n <div className=\"memory-stat-body\">\n <div className=\"memory-stat-label\">{label}</div>\n <div className=\"memory-stat-value\">{value}</div>\n {sub && <div className=\"memory-stat-sub muted\">{sub}</div>}\n </div>\n </div>\n );\n}\n\nfunction FileTextCount({ n }: { n: number }) {\n // Stable icon — use FileText with a small badge\n return (\n <span style={{ position: 'relative', display: 'inline-block' }}>\n <SearchIcon size={14} />\n <span className=\"memory-mini-badge\">{n}</span>\n </span>\n );\n}","// src/web/views/memory/ObsidianPanel.tsx — vault browser + note CRUD + backlinks.\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n ChevronDown,\n ChevronRight,\n FilePlus,\n FileText,\n Folder,\n Loader2,\n Pencil,\n RefreshCw,\n Search as SearchIcon,\n Trash2,\n X,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { useModal } from '../../components/Modal';\nimport { api } from '../../lib/api';\nimport { formatTime, formatRelative, cn } from '../../lib/utils';\n\ntype Note = {\n relPath: string;\n frontmatter: Record<string, unknown>;\n body: string;\n raw: string;\n mtime: number;\n size: number;\n schemaValid: boolean;\n};\n\ntype TreeNode = {\n name: string;\n path: string;\n type: 'folder' | 'note';\n size?: number;\n mtime?: number;\n children?: TreeNode[];\n};\n\ntype Backlink = {\n fromRelPath: string;\n fromTitle: string;\n snippet: string;\n mtime: number;\n};\n\ntype Props = { refreshKey: number };\n\nexport function ObsidianPanel({ refreshKey }: Props) {\n const toast = useToast();\n const modal = useModal();\n const [notes, setNotes] = useState<Note[]>([]);\n const [tree, setTree] = useState<TreeNode | null>(null);\n const [loading, setLoading] = useState(true);\n const [searchQ, setSearchQ] = useState('');\n const [searchResults, setSearchResults] = useState<Note[] | null>(null);\n const [searching, setSearching] = useState(false);\n const [selected, setSelected] = useState<string | null>(null);\n const [backlinks, setBacklinks] = useState<Backlink[]>([]);\n\n const reload = async () => {\n setLoading(true);\n try {\n const [n, t] = await Promise.all([\n api.get<{ notes: Note[] }>('/memory/notes').catch(() => ({ notes: [] })),\n api.get<{ tree: TreeNode | null }>('/memory/obsidian/tree').catch(() => ({ tree: null })),\n ]);\n setNotes(n.notes || []);\n setTree(t.tree);\n if (selected && !n.notes?.find((x) => x.relPath === selected)) {\n setSelected(null);\n setBacklinks([]);\n }\n } catch (err) {\n toast.error(`Vault load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n // Debounced search\n useEffect(() => {\n if (!searchQ.trim()) {\n setSearchResults(null);\n return;\n }\n setSearching(true);\n const t = setTimeout(async () => {\n try {\n const r = await api.get<{ results: Array<{ relPath: string; snippet: string; score: number }> }>(\n `/memory/search?q=${encodeURIComponent(searchQ)}&limit=50`,\n );\n const pathSet = new Set((r.results || []).map((x) => x.relPath));\n setSearchResults(notes.filter((n) => pathSet.has(n.relPath)));\n } catch (err) {\n toast.error(`Search failed: ${(err as Error).message}`);\n } finally {\n setSearching(false);\n }\n }, 240);\n return () => clearTimeout(t);\n }, [searchQ, notes, toast]);\n\n const onSelect = async (relPath: string) => {\n setSelected(relPath);\n try {\n const r = await api.get<{ backlinks: Backlink[] }>(\n `/memory/obsidian/backlinks?note=${encodeURIComponent(relPath)}`,\n );\n setBacklinks(r.backlinks || []);\n } catch {\n setBacklinks([]);\n }\n };\n\n const onCreate = () => {\n modal.open({\n title: 'New note',\n width: 720,\n children: (\n <NoteEditor\n mode=\"create\"\n onSave={async (relPath, frontmatter, body) => {\n try {\n await api.post('/memory/notes', { path: relPath, frontmatter, body });\n toast.success(`Created ${relPath}.`);\n modal.close();\n await reload();\n onSelect(relPath);\n } catch (err) {\n toast.error(`Create failed: ${(err as Error).message}`);\n }\n }}\n onCancel={() => modal.close()}\n />\n ),\n });\n };\n\n const onEdit = async (relPath: string) => {\n try {\n const note = await api.get<Note>(`/memory/notes/${relPath.split('/').map(encodeURIComponent).join('/')}`);\n modal.open({\n title: `Edit ${relPath}`,\n width: 720,\n children: (\n <NoteEditor\n mode=\"edit\"\n initial={{ relPath: note.relPath, frontmatter: note.frontmatter, body: note.body }}\n onSave={async (rp, frontmatter, body) => {\n try {\n await api.put(`/memory/notes/${rp.split('/').map(encodeURIComponent).join('/')}`, {\n frontmatter, body,\n });\n toast.success(`Saved ${rp}.`);\n modal.close();\n await reload();\n onSelect(rp);\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n }\n }}\n onCancel={() => modal.close()}\n />\n ),\n });\n } catch (err) {\n toast.error(`Load failed: ${(err as Error).message}`);\n }\n };\n\n const onDelete = async (relPath: string) => {\n if (!confirm(`Delete ${relPath}? This cannot be undone.`)) return;\n try {\n await api.del(`/memory/notes/${relPath.split('/').map(encodeURIComponent).join('/')}`);\n toast.success(`Deleted ${relPath}.`);\n if (selected === relPath) setSelected(null);\n await reload();\n } catch (err) {\n toast.error(`Delete failed: ${(err as Error).message}`);\n }\n };\n\n const sortedNotes = useMemo(() => {\n return [...notes].sort((a, b) => b.mtime - a.mtime);\n }, [notes]);\n\n const displayed = searchResults ?? sortedNotes;\n\n if (loading && !notes.length) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading vault…</p>\n </div>\n );\n }\n\n return (\n <div className=\"memory-panel-content memory-obsidian-grid\">\n {/* ── Folder tree (left) ─────────────────────────────────────── */}\n <Card variant=\"outlined\" className=\"memory-tree-card\">\n <CardTitle>\n <Folder size={14} /> Folders\n </CardTitle>\n <CardMeta>{tree ? `${countFolders(tree)} folder(s)` : 'no vault'}</CardMeta>\n <div className=\"memory-tree-body\">\n {tree ? <TreeView node={tree} depth={0} onSelect={onSelect} selected={selected} /> : null}\n </div>\n </Card>\n\n {/* ── Note list (center) ─────────────────────────────────────── */}\n <div className=\"memory-obsidian-list-col\">\n <div className=\"memory-list-toolbar\">\n <div className=\"search-input\">\n <SearchIcon size={14} aria-hidden />\n <label htmlFor=\"obsidian-search\" className=\"sr-only\">Search notes</label>\n <input\n id=\"obsidian-search\"\n type=\"text\"\n className=\"input\"\n placeholder=\"Search notes…\"\n value={searchQ}\n onChange={(e) => setSearchQ(e.target.value)}\n aria-label=\"Search notes\"\n />\n {searchQ && (\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => setSearchQ('')}\n aria-label=\"Clear search\"\n >\n <X size={12} />\n </button>\n )}\n </div>\n <Button variant=\"primary\" size=\"sm\" onClick={onCreate}>\n <FilePlus size={12} /> New note\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={reload} title=\"Refresh\">\n <RefreshCw size={12} />\n </Button>\n </div>\n {searching && <div className=\"muted text-sm\">Searching…</div>}\n {displayed.length === 0 ? (\n <EmptyState\n icon={<FileText size={28} />}\n title=\"No notes\"\n message={\n notes.length === 0\n ? 'No notes in this vault yet. Click \"New note\" to create one.'\n : `No notes match \"${searchQ}\".`\n }\n />\n ) : (\n <ul className=\"memory-note-list\">\n {displayed.map((n) => (\n <li\n key={n.relPath}\n className={cn('memory-note-card', selected === n.relPath && 'memory-note-card-active')}\n >\n <button\n type=\"button\"\n className=\"memory-note-card-main\"\n onClick={() => onSelect(n.relPath)}\n >\n <div className=\"memory-note-card-title\">\n <FileText size={12} />\n <span>{titleOf(n)}</span>\n </div>\n <div className=\"memory-note-card-meta\">\n <code className=\"muted\">{n.relPath}</code>\n <span className=\"muted\">· {formatRelative(n.mtime)}</span>\n {!n.schemaValid && <span className=\"memory-pill-warn\">schema</span>}\n </div>\n </button>\n <div className=\"memory-note-card-actions\">\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => onEdit(n.relPath)}\n aria-label={`Edit ${n.relPath}`}\n title=\"Edit\"\n >\n <Pencil size={12} />\n </button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => onDelete(n.relPath)}\n aria-label={`Delete ${n.relPath}`}\n title=\"Delete\"\n >\n <Trash2 size={12} />\n </button>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {/* ── Detail pane (right) ────────────────────────────────────── */}\n <div className=\"memory-obsidian-detail-col\">\n {selected ? (\n <NoteDetail relPath={selected} onClose={() => setSelected(null)} />\n ) : (\n <EmptyState\n icon={<FileText size={28} />}\n title=\"Pick a note\"\n message=\"Select a note from the list to view its content, frontmatter, and backlinks.\"\n />\n )}\n </div>\n </div>\n );\n}\n\n// ── Tree view ─────────────────────────────────────────────────────────────\n\n/**\n * Coerce a note's title to a renderable string. frontmatter.title is\n * `unknown` per the schema, so this guards against non-string values.\n */\nfunction titleOf(n: Note): string {\n const t = n.frontmatter?.title;\n if (typeof t === 'string' && t.trim()) return t;\n return n.relPath.replace(/\\.md$/i, '');\n}\n\nfunction TreeView({\n node,\n depth,\n onSelect,\n selected,\n}: {\n node: TreeNode;\n depth: number;\n onSelect: (path: string) => void;\n selected: string | null;\n}) {\n const [open, setOpen] = useState(depth < 2);\n if (node.type === 'note') {\n return (\n <button\n type=\"button\"\n className={cn('memory-tree-node memory-tree-node-note', selected === node.path && 'memory-tree-node-active')}\n style={{ paddingLeft: 6 + depth * 12 }}\n onClick={() => onSelect(node.path)}\n >\n <FileText size={11} />\n <span>{node.name}</span>\n </button>\n );\n }\n return (\n <div className=\"memory-tree-folder\">\n <button\n type=\"button\"\n className=\"memory-tree-node memory-tree-node-folder\"\n style={{ paddingLeft: 6 + depth * 12 }}\n onClick={() => setOpen((v) => !v)}\n >\n {open ? <ChevronDown size={11} /> : <ChevronRight size={11} />}\n <Folder size={11} />\n <span>{node.name || 'vault'}</span>\n {node.children && node.children.length > 0 && (\n <span className=\"muted text-xs\">{node.children.length}</span>\n )}\n </button>\n {open && node.children && (\n <div className=\"memory-tree-children\">\n {node.children.map((c, i) => (\n <TreeView key={`${c.path}-${i}`} node={c} depth={depth + 1} onSelect={onSelect} selected={selected} />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction countFolders(node: TreeNode): number {\n if (node.type === 'note') return 0;\n return 1 + (node.children || []).reduce((acc, c) => acc + countFolders(c), 0);\n}\n\n// ── Note detail ───────────────────────────────────────────────────────────\n\nfunction NoteDetail({ relPath, onClose }: { relPath: string; onClose: () => void }) {\n const [note, setNote] = useState<Note | null>(null);\n const [backlinks, setBacklinks] = useState<Backlink[]>([]);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n (async () => {\n try {\n const [n, b] = await Promise.all([\n api.get<Note>(`/memory/notes/${relPath.split('/').map(encodeURIComponent).join('/')}`),\n api.get<{ backlinks: Backlink[] }>(`/memory/obsidian/backlinks?note=${encodeURIComponent(relPath)}`),\n ]);\n if (cancelled) return;\n setNote(n);\n setBacklinks(b.backlinks || []);\n } catch {\n if (!cancelled) setNote(null);\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n return () => { cancelled = true; };\n }, [relPath]);\n\n if (loading) {\n return (\n <div className=\"view-loading\"><Spinner size=\"sm\" /></div>\n );\n }\n if (!note) return <div className=\"muted\">Note not found.</div>;\n\n const tags = Array.isArray(note.frontmatter?.tags) ? note.frontmatter.tags : [];\n const links = Array.isArray(note.frontmatter?.links) ? note.frontmatter.links : [];\n\n return (\n <div className=\"memory-note-detail\">\n <div className=\"memory-note-detail-head\">\n <h3>{titleOf(note)}</h3>\n <button type=\"button\" className=\"icon-btn\" onClick={onClose} aria-label=\"Close\">\n <X size={12} />\n </button>\n </div>\n <div className=\"memory-note-detail-meta\">\n <code>{relPath}</code>\n <span className=\"muted\">· modified {formatTime(note.mtime)}</span>\n </div>\n {tags.length > 0 && (\n <div className=\"memory-tag-row\">\n {tags.map((t, i) => (\n <span key={i} className=\"memory-tag\">{String(t)}</span>\n ))}\n </div>\n )}\n <pre className=\"memory-note-body mono text-sm\">{note.body}</pre>\n {backlinks.length > 0 && (\n <div className=\"memory-backlinks\">\n <h4>Backlinks</h4>\n <ul>\n {backlinks.map((b) => (\n <li key={b.fromRelPath}>\n <code>{b.fromRelPath}</code>\n <p className=\"muted text-sm\">{b.snippet}</p>\n </li>\n ))}\n </ul>\n </div>\n )}\n {links.length > 0 && (\n <div className=\"memory-backlinks\">\n <h4>Forward links</h4>\n <ul>\n {links.map((l, i) => (\n <li key={i}><code>{String(l)}</code></li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n\n// ── Note editor modal body ────────────────────────────────────────────────\n\nfunction NoteEditor({\n mode,\n initial,\n onSave,\n onCancel,\n}: {\n mode: 'create' | 'edit';\n initial?: { relPath: string; frontmatter: Record<string, unknown>; body: string };\n onSave: (relPath: string, frontmatter: Record<string, unknown>, body: string) => void | Promise<void>;\n onCancel: () => void;\n}) {\n const [relPath, setRelPath] = useState(initial?.relPath || 'untitled.md');\n const [frontmatterYaml, setFrontmatterYaml] = useState(\n initial?.frontmatter ? yamlStringify(initial.frontmatter) : 'title: \"\"\\ntags: []\\n',\n );\n const [body, setBody] = useState(initial?.body || '');\n const [busy, setBusy] = useState(false);\n const toast = useToast();\n\n const onSubmit = async () => {\n if (!relPath.endsWith('.md')) {\n toast.error('Path must end in .md');\n return;\n }\n let fm: Record<string, unknown>;\n try {\n fm = yamlParse(frontmatterYaml) || {};\n } catch (err) {\n toast.error(`Frontmatter parse failed: ${(err as Error).message}`);\n return;\n }\n setBusy(true);\n try {\n await onSave(relPath, fm, body);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"memory-editor-modal\">\n <label className=\"field-label\" htmlFor=\"obsidian-note-path\">Path</label>\n <input\n id=\"obsidian-note-path\"\n type=\"text\"\n className=\"input mono\"\n value={relPath}\n onChange={(e) => setRelPath(e.target.value)}\n disabled={mode === 'edit'}\n placeholder=\"notes/example.md\"\n />\n <label className=\"field-label\" htmlFor=\"obsidian-note-frontmatter\" style={{ marginTop: 12 }}>Frontmatter (YAML)</label>\n <textarea\n id=\"obsidian-note-frontmatter\"\n className=\"memory-editor-textarea mono text-sm\"\n rows={6}\n value={frontmatterYaml}\n onChange={(e) => setFrontmatterYaml(e.target.value)}\n aria-label=\"Frontmatter YAML\"\n />\n <label className=\"field-label\" htmlFor=\"obsidian-note-body\" style={{ marginTop: 12 }}>Body (Markdown)</label>\n <textarea\n id=\"obsidian-note-body\"\n className=\"memory-editor-textarea mono text-sm\"\n rows={14}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n aria-label=\"Body markdown\"\n />\n <div className=\"modal-footer-actions\" style={{ marginTop: 12 }}>\n <Button variant=\"ghost\" onClick={onCancel} disabled={busy}>Cancel</Button>\n <Button variant=\"primary\" onClick={onSubmit} disabled={busy}>\n {busy && <Loader2 size={12} className=\"memory-spin\" />}\n {mode === 'create' ? 'Create' : 'Save'}\n </Button>\n </div>\n </div>\n );\n}\n\n// ── Tiny YAML helpers (avoid pulling a 100kB lib into the bundle) ────────\n\nfunction yamlStringify(obj: Record<string, unknown>): string {\n // Best-effort: dump top-level scalar / list / nested-map fields.\n // Good enough for the note editor — the server re-validates anyway.\n const lines: string[] = [];\n for (const [k, v] of Object.entries(obj)) {\n if (v === null || v === undefined) continue;\n if (Array.isArray(v)) {\n if (v.length === 0) { lines.push(`${k}: []`); continue; }\n lines.push(`${k}:`);\n for (const item of v) lines.push(` - ${yamlScalar(item)}`);\n } else if (typeof v === 'object') {\n lines.push(`${k}:`);\n for (const [kk, vv] of Object.entries(v as Record<string, unknown>)) {\n lines.push(` ${kk}: ${yamlScalar(vv)}`);\n }\n } else {\n lines.push(`${k}: ${yamlScalar(v)}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction yamlScalar(v: unknown): string {\n if (typeof v === 'string') {\n if (/[:#\\n\"']/.test(v) || v === '') return JSON.stringify(v);\n return v;\n }\n if (typeof v === 'number' || typeof v === 'boolean') return String(v);\n return JSON.stringify(v);\n}\n\nfunction yamlParse(s: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n const lines = s.split(/\\r?\\n/);\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (!line.trim() || line.trim().startsWith('#')) { i++; continue; }\n const m = line.match(/^([A-Za-z_][\\w-]*):\\s*(.*)$/);\n if (!m) { i++; continue; }\n const [, key, rest] = m;\n if (rest === '') {\n // Nested mapping or list follows.\n const block: Record<string, unknown> = {};\n const list: unknown[] = [];\n let isList = false;\n let isMap = false;\n while (i + 1 < lines.length) {\n const next = lines[i + 1];\n if (!next.startsWith(' ')) break;\n if (next.startsWith(' - ')) {\n isList = true;\n list.push(parseScalar(next.slice(4)));\n i++;\n } else {\n isMap = true;\n const nm = next.match(/^ ([A-Za-z_][\\w-]*):\\s*(.*)$/);\n if (nm) {\n block[nm[1]] = parseScalar(nm[2]);\n }\n i++;\n }\n }\n out[key] = isList && !isMap ? list : (isMap ? block : {});\n } else {\n out[key] = parseScalar(rest);\n }\n i++;\n }\n return out;\n}\n\nfunction parseScalar(v: string): unknown {\n const t = v.trim();\n if (t === '') return '';\n if (t === 'true') return true;\n if (t === 'false') return false;\n if (t === 'null' || t === '~') return null;\n if (/^-?\\d+$/.test(t)) return parseInt(t, 10);\n if (/^-?\\d+\\.\\d+$/.test(t)) return parseFloat(t);\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\"))) {\n return t.slice(1, -1);\n }\n return t;\n}","// src/web/views/memory/GitSyncPanel.tsx — git status, pull/push/commit/fetch, diff viewer.\nimport { useEffect, useState } from 'react';\nimport {\n ArrowDown,\n ArrowUp,\n CheckCircle2,\n GitBranch,\n GitCommit,\n GitMerge,\n GitPullRequest,\n Loader2,\n RefreshCw,\n Settings,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { formatTime, cn } from '../../lib/utils';\n\ntype GitStatus = {\n ok: boolean;\n clean?: boolean;\n branch?: string;\n ahead?: number;\n behind?: number;\n modified?: string[];\n untracked?: string[];\n mode?: string;\n};\n\ntype GitDiff = {\n hasDiff: boolean;\n lines: string[];\n files: string[];\n mode: string;\n};\n\ntype Props = { refreshKey: number };\n\nexport function GitSyncPanel({ refreshKey }: Props) {\n const toast = useToast();\n const [status, setStatus] = useState<GitStatus | null>(null);\n const [diff, setDiff] = useState<GitDiff | null>(null);\n const [loading, setLoading] = useState(true);\n const [busy, setBusy] = useState<string | null>(null);\n const [config, setConfig] = useState<{ repoPath?: string; remoteUrl?: string; branch?: string; autoSync?: boolean } | null>(null);\n\n const reload = async () => {\n setLoading(true);\n try {\n const [s, d, g] = await Promise.all([\n api.get<GitStatus>('/memory/git/status').catch(() => null),\n api.get<GitDiff>('/memory/git/diff').catch(() => null),\n api.get<{ config?: { git?: { repoPath?: string; remoteUrl?: string; branch?: string; autoSync?: boolean } } }>(\n '/memory/config/global',\n ).catch(() => null),\n ]);\n setStatus(s);\n setDiff(d);\n setConfig(g?.config?.git || null);\n } catch (err) {\n toast.error(`Git status failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n const run = async (key: string, fn: () => Promise<unknown>, msg: string) => {\n setBusy(key);\n try {\n await fn();\n toast.success(msg);\n await reload();\n } catch (err) {\n toast.error(`${key} failed: ${(err as Error).message}`);\n } finally {\n setBusy(null);\n }\n };\n\n const onPull = () => run('pull', () => api.post('/memory/git/pull', {}), 'Pull complete.');\n const onPush = () => run('push', () => api.post('/memory/git/push', {}), 'Push complete.');\n const onCommit = () => {\n const message = prompt('Commit message:', `[memory-sync] ${new Date().toISOString().slice(0, 10)} vault sync`);\n if (!message) return;\n run('commit', () => api.post('/memory/git/commit', { message }), 'Committed.');\n };\n const onFetch = () => run('fetch', () => api.post('/memory/git/sync', { push: false }), 'Fetch complete.');\n\n if (loading && !status) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading git status…</p>\n </div>\n );\n }\n if (!status) {\n return <div className=\"muted\">No git data available.</div>;\n }\n\n const isLocal = status.mode === 'local-only';\n\n return (\n <div className=\"memory-panel-content\">\n {/* ── Status card ───────────────────────────────────────────── */}\n <Card variant=\"elevated\">\n <CardTitle>\n <GitBranch size={14} /> Git sync\n {isLocal ? (\n <span className=\"memory-source-pill-status na\">local-only</span>\n ) : (\n <span className={cn('memory-source-pill-status', status.clean ? 'on' : 'warn')}>\n {status.clean ? 'clean' : 'dirty'}\n </span>\n )}\n </CardTitle>\n <CardMeta>\n {isLocal\n ? 'Memory is in local-only mode. Configure a shared repo in Settings → Memory to enable git sync.'\n : <>Branch <code>{status.branch || '—'}</code>{status.ahead ? <> · ahead {status.ahead}</> : null}{status.behind ? <> · behind {status.behind}</> : null}</>}\n </CardMeta>\n\n {!isLocal && (\n <div className=\"memory-git-status-row\">\n <Pill ok={status.clean ?? false} label=\"Working tree\" />\n <Pill ok={(status.ahead ?? 0) === 0} label={`Ahead: ${status.ahead ?? 0}`} />\n <Pill ok={(status.behind ?? 0) === 0} label={`Behind: ${status.behind ?? 0}`} />\n <Pill ok={(status.modified?.length ?? 0) === 0} label={`Modified: ${status.modified?.length ?? 0}`} />\n <Pill ok={(status.untracked?.length ?? 0) === 0} label={`Untracked: ${status.untracked?.length ?? 0}`} />\n </div>\n )}\n\n <div className=\"memory-action-row\">\n <Button variant=\"secondary\" size=\"sm\" onClick={onPull} disabled={!!busy || isLocal}>\n {busy === 'pull' ? <Loader2 size={12} className=\"memory-spin\" /> : <ArrowDown size={12} />}\n Pull\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onPush} disabled={!!busy || isLocal}>\n {busy === 'push' ? <Loader2 size={12} className=\"memory-spin\" /> : <ArrowUp size={12} />}\n Push\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onCommit} disabled={!!busy || isLocal}>\n {busy === 'commit' ? <Loader2 size={12} className=\"memory-spin\" /> : <GitCommit size={12} />}\n Commit\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onFetch} disabled={!!busy || isLocal}>\n {busy === 'fetch' ? <Loader2 size={12} className=\"memory-spin\" /> : <GitPullRequest size={12} />}\n Fetch + sync\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={reload} disabled={!!busy}>\n <RefreshCw size={12} /> Refresh\n </Button>\n </div>\n </Card>\n\n {/* ── Repo config snapshot ──────────────────────────────────── */}\n {config && (\n <Card>\n <CardTitle>\n <Settings size={14} /> Repository\n </CardTitle>\n <CardMeta>Snapshot of <code>~/.config/bizar/memory-config.json</code> → git block.</CardMeta>\n <dl className=\"memory-config-row\">\n <dt>Path</dt>\n <dd className=\"mono ellipsis\" title={config.repoPath}>{config.repoPath || '—'}</dd>\n <dt>Remote</dt>\n <dd className=\"mono ellipsis\" title={config.remoteUrl}>{config.remoteUrl || '—'}</dd>\n <dt>Branch</dt>\n <dd><code>{config.branch || 'main'}</code></dd>\n <dt>Auto-sync</dt>\n <dd>{config.autoSync ? 'enabled' : 'disabled'}</dd>\n </dl>\n </Card>\n )}\n\n {/* ── Working-tree diff ─────────────────────────────────────── */}\n <Card>\n <CardTitle>\n <GitMerge size={14} /> Working-tree diff\n </CardTitle>\n <CardMeta>\n {diff?.hasDiff\n ? `${diff.files.length} file(s) changed`\n : 'no working-tree changes'}\n </CardMeta>\n {diff && diff.files.length > 0 && (\n <ul className=\"memory-diff-files\">\n {diff.files.map((f) => (\n <li key={f}>\n <code>{f}</code>\n </li>\n ))}\n </ul>\n )}\n {diff && diff.lines.length > 1 && (\n <pre className=\"memory-log-tail mono text-xs\">\n {diff.lines.slice(0, 400).join('\\n')}\n </pre>\n )}\n </Card>\n </div>\n );\n}\n\nfunction Pill({ ok, label }: { ok: boolean; label: string }) {\n return (\n <span className={cn('memory-git-status-pill', ok ? 'ok' : 'warn')}>\n {ok ? <CheckCircle2 size={11} /> : <Loader2 size={11} className=\"memory-spin\" />}\n {label}\n </span>\n );\n}","// src/web/views/memory/SemanticSearchPanel.tsx — cross-source search (LightRAG + Obsidian).\nimport { useEffect, useMemo, useState } from 'react';\nimport { Brain, FileText, Loader2, Search as SearchIcon, X } from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { cn } from '../../lib/utils';\n\ntype Result = {\n source: 'lightrag' | 'obsidian';\n relPath: string | null;\n snippet: string;\n score: number;\n mtime: number | null;\n raw?: unknown;\n error?: string;\n};\n\ntype Props = { refreshKey: number };\n\nexport function SemanticSearchPanel({ refreshKey }: Props) {\n const toast = useToast();\n const [q, setQ] = useState('');\n const [sources, setSources] = useState<{ lightrag: boolean; obsidian: boolean }>({ lightrag: true, obsidian: true });\n const [results, setResults] = useState<Result[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [lastQuery, setLastQuery] = useState('');\n\n const onSearch = async (query: string) => {\n if (!query.trim()) return;\n setLoading(true);\n setLastQuery(query);\n try {\n const activeSources = [\n ...(sources.lightrag ? ['lightrag' as const] : []),\n ...(sources.obsidian ? ['obsidian' as const] : []),\n ];\n const r = await api.post<{ query: string; count: number; results: Result[] }>(\n '/memory/semantic-search',\n { query, limit: 20, sources: activeSources },\n );\n setResults(r.results || []);\n } catch (err) {\n toast.error(`Search failed: ${(err as Error).message}`);\n setResults([]);\n } finally {\n setLoading(false);\n }\n };\n\n // Re-run when sources toggle (if there's a last query).\n useEffect(() => {\n if (lastQuery) onSearch(lastQuery);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sources]);\n\n // Re-run when the panel is re-mounted.\n useEffect(() => {\n if (lastQuery) onSearch(lastQuery);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n const grouped = useMemo(() => {\n const obs = (results || []).filter((r) => r.source === 'obsidian');\n const lr = (results || []).filter((r) => r.source === 'lightrag');\n return { obs, lr };\n }, [results]);\n\n return (\n <div className=\"memory-panel-content\">\n <Card variant=\"elevated\">\n <CardTitle>\n <SearchIcon size={14} /> Semantic search\n </CardTitle>\n <CardMeta>Query both LightRAG (graph-based) and the Obsidian vault in one shot.</CardMeta>\n <div className=\"memory-search-row\">\n <label htmlFor=\"semantic-search-input\" className=\"sr-only\">Semantic search</label>\n <input\n id=\"semantic-search-input\"\n type=\"text\"\n className=\"input\"\n placeholder=\"e.g. how are notes indexed?\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') onSearch(q);\n }}\n disabled={loading}\n aria-label=\"Semantic search query\"\n />\n <Button variant=\"primary\" onClick={() => onSearch(q)} disabled={loading || !q.trim()}>\n {loading ? <Loader2 size={12} className=\"memory-spin\" /> : <SearchIcon size={12} />}\n Search\n </Button>\n </div>\n <div className=\"memory-source-toggle-row\">\n <ToggleChip\n active={sources.obsidian}\n onToggle={() => setSources((s) => ({ ...s, obsidian: !s.obsidian }))}\n label=\"Obsidian\"\n icon={<FileText size={11} />}\n />\n <ToggleChip\n active={sources.lightrag}\n onToggle={() => setSources((s) => ({ ...s, lightrag: !s.lightrag }))}\n label=\"LightRAG\"\n icon={<Brain size={11} />}\n />\n {q && (\n <button type=\"button\" className=\"icon-btn\" onClick={() => { setQ(''); setResults(null); setLastQuery(''); }} aria-label=\"Clear\">\n <X size={12} />\n </button>\n )}\n </div>\n </Card>\n\n {loading && (\n <div className=\"view-loading\">\n <Spinner size=\"md\" />\n </div>\n )}\n\n {!loading && results && results.length === 0 && (\n <EmptyState\n icon={<SearchIcon size={28} />}\n title=\"No matches\"\n message={`Nothing in scope matched \"${lastQuery}\".`}\n />\n )}\n\n {grouped.obs.length > 0 && (\n <Card>\n <CardTitle>\n <FileText size={14} /> Obsidian ({grouped.obs.length})\n </CardTitle>\n <ul className=\"memory-search-result-list\">\n {grouped.obs.map((r, i) => (\n <li key={`obs-${i}`} className=\"memory-search-result\">\n <div className=\"memory-search-result-head\">\n <code>{r.relPath}</code>\n <span className=\"muted text-xs\">score {r.score.toFixed(1)}</span>\n </div>\n <p className=\"muted text-sm\">{r.snippet}</p>\n </li>\n ))}\n </ul>\n </Card>\n )}\n\n {grouped.lr.length > 0 && (\n <Card>\n <CardTitle>\n <Brain size={14} /> LightRAG ({grouped.lr.length})\n </CardTitle>\n <div className=\"memory-search-result-list\">\n {grouped.lr.map((r, i) => (\n <div key={`lr-${i}`} className=\"memory-search-result\">\n <div className=\"memory-search-result-head\">\n <span className=\"memory-source-pill\"><Brain size={11} /> LightRAG</span>\n {r.error && <span className=\"muted text-xs\">error: {r.error}</span>}\n </div>\n <p className=\"text-sm\">{r.snippet}</p>\n </div>\n ))}\n </div>\n </Card>\n )}\n </div>\n );\n}\n\nfunction ToggleChip({\n active,\n onToggle,\n label,\n icon,\n}: {\n active: boolean;\n onToggle: () => void;\n label: string;\n icon: React.ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n className={cn('memory-toggle-chip', active && 'memory-toggle-chip-active')}\n onClick={onToggle}\n aria-pressed={active}\n >\n {icon}\n <span>{label}</span>\n </button>\n );\n}","// src/web/views/memory/ConfigPanel.tsx — simplified memory config.\n// v6.x — Vault path is now fetched from /api/memory/status so the row\n// stops saying \"(loading…)\" forever. Users can change the vault path\n// inline and initialise the vault if it doesn't exist yet.\nimport { useEffect, useState } from 'react';\nimport {\n GitBranch,\n GitCommitHorizontal,\n Download,\n Upload,\n Loader2,\n Plug,\n Save,\n FolderInput,\n CheckCircle2,\n XCircle,\n} from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { cn } from '../../lib/utils';\n\ntype GitConfig = {\n remoteUrl?: string;\n};\n\ntype GlobalConfig = {\n git?: GitConfig;\n};\n\ntype SyncStatus = {\n clean?: boolean;\n branch?: string;\n modified?: number;\n untracked?: number;\n};\n\ntype MemoryStatus = {\n initialized: boolean;\n mode?: string | null;\n projectId?: string | null;\n vaultRoot?: string | null;\n branch?: string | null;\n gitClean?: boolean | null;\n noteCount?: number;\n lastSecretScan?: string | null;\n};\n\ntype Props = { refreshKey: number };\n\nexport function ConfigPanel({ refreshKey }: Props) {\n const toast = useToast();\n const [cfg, setCfg] = useState<GlobalConfig | null>(null);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [remoteUrl, setRemoteUrl] = useState('');\n const [memoryStatus, setMemoryStatus] = useState<MemoryStatus | null>(null);\n const [vaultPathDraft, setVaultPathDraft] = useState<string>('');\n const [pathInitialising, setPathInitialising] = useState(false);\n const [pathSaving, setPathSaving] = useState(false);\n const [syncStatus, setSyncStatus] = useState<SyncStatus | null>(null);\n const [actionLoading, setActionLoading] = useState<string | null>(null);\n const [tests, setTests] = useState<Array<{ name: string; pass: boolean; detail: string }> | null>(null);\n const [testing, setTesting] = useState(false);\n\n const reload = async () => {\n setLoading(true);\n try {\n const [cfgRes, statusRes] = await Promise.all([\n api.get<{ config: GlobalConfig }>('/memory/config/global').catch(() => null),\n api.get<MemoryStatus>('/memory/status').catch(() => null),\n ]);\n if (cfgRes) {\n setCfg(cfgRes.config);\n setRemoteUrl(cfgRes.config?.git?.remoteUrl || '');\n } else {\n setCfg({});\n }\n if (statusRes) {\n setMemoryStatus(statusRes);\n // Initialise the draft input from the server's current vaultRoot.\n // Only overwrite while the user hasn't started editing.\n setVaultPathDraft((cur) => cur || statusRes.vaultRoot || '');\n }\n // Also fetch git status from the per-project vault\n await loadSyncStatus();\n } catch (err) {\n toast.error(`Config load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n const loadSyncStatus = async () => {\n try {\n const r = await api.get<{ ok: boolean; clean?: boolean; branch?: string; modified?: number; untracked?: number }>('/memory/git/status');\n if (r.ok) {\n setSyncStatus({\n clean: r.clean,\n branch: r.branch,\n modified: r.modified,\n untracked: r.untracked,\n });\n }\n } catch {\n // git status is best-effort\n }\n };\n\n useEffect(() => {\n reload();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refreshKey]);\n\n // v6.x — Save the new vault path. If the folder doesn't exist, the\n // backend's /memory/init endpoint can be used to create it (handled\n // by ensureVaultExists()).\n const onSaveVaultPath = async () => {\n const target = vaultPathDraft.trim();\n if (!target) {\n toast.error('Vault path cannot be empty.');\n return;\n }\n setPathSaving(true);\n try {\n const status = await api.get<MemoryStatus & { exists?: boolean }>('/memory/status').catch(() => null);\n const initialised = status?.initialized;\n if (!initialised) {\n // Initialise the vault at the chosen path.\n await api.post('/memory/init', { vaultRoot: target });\n toast.success(`Vault initialised at ${target}.`);\n } else {\n // v6.x — Call the new vault config endpoint to persist the path.\n await api.post('/memory/config/vault', { vaultRoot: target });\n toast.success(`Vault path updated to ${target}.`);\n }\n setVaultPathDraft(target);\n await reload();\n } catch (err) {\n toast.error(`Vault path save failed: ${(err as Error).message}`);\n } finally {\n setPathSaving(false);\n }\n };\n\n const onInitVault = async () => {\n setPathInitialising(true);\n try {\n await api.post('/memory/init', {});\n toast.success('Vault initialised.');\n await reload();\n } catch (err) {\n toast.error(`Init failed: ${(err as Error).message}`);\n } finally {\n setPathInitialising(false);\n }\n };\n\n const onSave = async () => {\n if (!cfg) return;\n setSaving(true);\n try {\n await api.put('/memory/config/global', { git: { remoteUrl } });\n toast.success('Config saved.');\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n } finally {\n setSaving(false);\n }\n };\n\n const runAction = async (action: 'pull' | 'push' | 'commit') => {\n setActionLoading(action);\n try {\n if (action === 'pull') {\n const r = await api.post<{ ok: boolean; output?: string }>('/memory/git/pull', {});\n if (r.ok) toast.success('Pull successful.');\n else toast.error(`Pull failed: ${r.output || 'unknown error'}`);\n } else if (action === 'push') {\n const r = await api.post<{ ok: boolean }>('/memory/git/push', {});\n if (r.ok) toast.success('Push successful.');\n else toast.error('Push failed.');\n } else if (action === 'commit') {\n const r = await api.post<{ ok: boolean; message?: string }>('/memory/git/commit', {});\n if (r.ok) toast.success(`Committed: ${r.message}`);\n else toast.error('Commit failed.');\n }\n await loadSyncStatus();\n } catch (err) {\n toast.error(`${action} failed: ${(err as Error).message}`);\n } finally {\n setActionLoading(null);\n }\n };\n\n const onTest = async () => {\n setTesting(true);\n try {\n const r = await api.post<{ ok: boolean; checks: Array<{ name: string; pass: boolean; detail: string }> }>(\n '/memory/test-git',\n {},\n );\n setTests(r.checks);\n } catch (err) {\n toast.error(`Test failed: ${(err as Error).message}`);\n } finally {\n setTesting(false);\n }\n };\n\n if (loading && !cfg) {\n return (\n <div className=\"view-loading\">\n <Spinner size=\"md\" />\n <p>Loading config…</p>\n </div>\n );\n }\n if (!cfg) return <div className=\"muted\">No config available.</div>;\n\n const initialised = !!memoryStatus?.initialized;\n const currentVaultPath = memoryStatus?.vaultRoot ?? '';\n\n return (\n <div className=\"memory-panel-content\">\n {/* ── Vault path ──────────────────────────────────────────────────── */}\n <Card>\n <CardTitle>\n <FolderInput size={14} /> Vault location\n </CardTitle>\n <CardMeta>\n The on-disk folder where notes and memory metadata live. Default:{' '}\n <code>~/.bizar_memory</code>.\n </CardMeta>\n <div className=\"memory-config-form\">\n <Row label=\"Current path\" inline>\n <span className=\"memory-vault-path mono\" data-testid=\"memory-current-vault-path\">\n {currentVaultPath || <span className=\"muted\">not initialised</span>}\n </span>\n {initialised ? (\n <span\n className=\"memory-pill memory-pill-ok\"\n style={{ marginLeft: 8 }}\n title=\"Vault folder exists on disk\"\n >\n <CheckCircle2 size={10} /> initialised\n </span>\n ) : (\n <span\n className=\"memory-pill memory-pill-warn\"\n style={{ marginLeft: 8 }}\n title=\"Vault folder does not exist yet\"\n >\n <XCircle size={10} /> not initialised\n </span>\n )}\n </Row>\n <Row label=\"Set path\">\n <input\n type=\"text\"\n className=\"input mono\"\n value={vaultPathDraft}\n onChange={(e) => setVaultPathDraft(e.target.value)}\n placeholder=\"~/.bizar_memory\"\n aria-label=\"Vault path\"\n data-testid=\"memory-vault-path-input\"\n />\n <span className=\"field-hint\">\n {initialised\n ? 'Save to update the working path.'\n : 'Save and initialise will create this folder if it does not exist.'}\n </span>\n </Row>\n </div>\n <div className=\"memory-action-row\" style={{ marginTop: 12 }}>\n <Button\n variant=\"primary\"\n onClick={onSaveVaultPath}\n disabled={pathSaving || pathInitialising || !vaultPathDraft.trim()}\n data-testid=\"memory-save-vault-path\"\n >\n {pathSaving ? <Loader2 size={12} className=\"memory-spin\" /> : <Save size={12} />}\n {initialised ? 'Save path' : 'Save and initialise'}\n </Button>\n {!initialised && (\n <Button\n variant=\"secondary\"\n onClick={onInitVault}\n disabled={pathInitialising || pathSaving}\n data-testid=\"memory-init-vault\"\n >\n {pathInitialising ? <Loader2 size={12} className=\"memory-spin\" /> : <FolderInput size={12} />}\n Initialise default\n </Button>\n )}\n </div>\n </Card>\n\n {/* ── Git sync ───────────────────────────────────────────────────── */}\n <Card>\n <CardTitle><GitBranch size={14} /> Git sync</CardTitle>\n <CardMeta>Configure the git remote and sync your memory vault.</CardMeta>\n <div className=\"memory-config-form\">\n <Row label=\"Remote URL\">\n <input\n type=\"text\"\n className=\"input mono\"\n value={remoteUrl}\n onChange={(e) => setRemoteUrl(e.target.value)}\n placeholder=\"git@github.com:org/repo.git\"\n />\n </Row>\n {syncStatus && (\n <Row label=\"Status\" inline>\n <span className={cn('memory-pill', syncStatus.clean ? 'memory-pill-ok' : 'memory-pill-warn')}>\n {syncStatus.clean ? 'clean' : 'dirty'}\n </span>\n {syncStatus.branch && (\n <span className=\"muted\" style={{ marginLeft: 8 }}>\n <GitBranch size={12} style={{ display: 'inline' }} /> {syncStatus.branch}\n </span>\n )}\n {!syncStatus.clean && syncStatus.modified !== undefined && (\n <span className=\"muted\" style={{ marginLeft: 8 }}>\n {syncStatus.modified} modified, {syncStatus.untracked} untracked\n </span>\n )}\n </Row>\n )}\n </div>\n <div className=\"memory-action-row\" style={{ marginTop: 12 }}>\n <Button\n variant=\"secondary\"\n onClick={() => runAction('pull')}\n disabled={actionLoading !== null}\n >\n {actionLoading === 'pull' ? <Loader2 size={12} className=\"memory-spin\" /> : <Download size={12} />}\n Pull\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => runAction('commit')}\n disabled={actionLoading !== null}\n >\n {actionLoading === 'commit' ? <Loader2 size={12} className=\"memory-spin\" /> : <GitCommitHorizontal size={12} />}\n Commit\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => runAction('push')}\n disabled={actionLoading !== null}\n >\n {actionLoading === 'push' ? <Loader2 size={12} className=\"memory-spin\" /> : <Upload size={12} />}\n Push\n </Button>\n </div>\n </Card>\n\n {/* ── Connection tests ─────────────────────────────────────────── */}\n <Card>\n <CardTitle>\n <Plug size={14} /> Connection tests\n </CardTitle>\n <CardMeta>Verify the configured git remote is reachable.</CardMeta>\n <div className=\"memory-action-row\">\n <Button variant=\"secondary\" onClick={onTest} disabled={testing}>\n {testing ? <Loader2 size={12} className=\"memory-spin\" /> : <Plug size={12} />}\n Test git connection\n </Button>\n <Button variant=\"primary\" onClick={onSave} disabled={saving}>\n {saving ? <Loader2 size={12} className=\"memory-spin\" /> : <Save size={12} />}\n Save config\n </Button>\n </div>\n {tests && tests.length > 0 && (\n <ul className=\"memory-check-list\" style={{ marginTop: 12 }}>\n {tests.map((t, i) => (\n <li key={i} className=\"memory-check-row\">\n <span className=\"memory-check-icon\">\n <span className={cn('memory-pill', t.pass ? 'memory-pill-ok' : 'memory-pill-warn')}>\n {t.pass ? 'OK' : 'FAIL'}\n </span>\n </span>\n <span className=\"memory-check-name\">{t.name}</span>\n <span className=\"memory-check-detail muted\">{t.detail}</span>\n </li>\n ))}\n </ul>\n )}\n </Card>\n </div>\n );\n}\n\nfunction Row({\n label,\n children,\n inline,\n}: {\n label: string;\n children: React.ReactNode;\n inline?: boolean;\n}) {\n if (inline) {\n return (\n <div className=\"memory-config-row-inline\">\n <div className=\"memory-config-row-label\" id={`cfg-${label.replace(/\\s+/g, '-').toLowerCase()}`}>{label}</div>\n <div\n className=\"memory-config-row-control\"\n role=\"group\"\n aria-labelledby={`cfg-${label.replace(/\\s+/g, '-').toLowerCase()}`}\n >\n {children}\n </div>\n </div>\n );\n }\n return (\n <label className=\"memory-config-row-stack\">\n <span>{label}</span>\n {children}\n </label>\n );\n}\n","// src/web/views/memory/MemoryGraphView.tsx — Interactive SVG knowledge graph.\n//\n// No external graph library. Hand-rolled force-directed layout + SVG rendering.\n// Pan: drag on canvas. Zoom: scroll wheel. Click node: onNodeClick callback.\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../lib/utils';\n\nexport type GraphNode = {\n id: string;\n label: string;\n type: string;\n size: number;\n group: string;\n};\n\nexport type GraphEdge = {\n source: string;\n target: string;\n type: string;\n weight: number;\n};\n\nexport type GraphData = {\n nodes: GraphNode[];\n edges: GraphEdge[];\n};\n\ntype Props = {\n data: GraphData;\n onNodeClick?: (node: GraphNode) => void;\n className?: string;\n};\n\ntype LayoutNode = GraphNode & {\n x: number;\n y: number;\n vx: number;\n vy: number;\n};\n\nconst CANVAS_SIZE = 800;\nconst ITERATIONS = 60;\n\nconst GROUP_COLORS: Record<string, string> = {\n default: '#8b5cf6',\n note: '#8b5cf6',\n entity: '#34d399',\n concept: '#fbbf24',\n root: '#f87171',\n};\n\nfunction getGroupColor(group: string, type: string): string {\n return GROUP_COLORS[group] || GROUP_COLORS[type] || GROUP_COLORS.default;\n}\n\nfunction nodeRadius(node: GraphNode): number {\n return 6 + Math.min(node.size * 2, 10);\n}\n\n/**\n * Simple force-directed layout.\n * - Repulsion between all node pairs\n * - Spring attraction along edges\n * - Center gravity\n */\nfunction layoutNodes(nodes: GraphNode[], edges: GraphEdge[]): LayoutNode[] {\n if (nodes.length === 0) return [];\n\n // Build adjacency list.\n const adj = new Map<string, Set<string>>();\n for (const n of nodes) adj.set(n.id, new Set());\n for (const e of edges) {\n adj.get(e.source)?.add(e.target);\n adj.get(e.target)?.add(e.source);\n }\n\n // Initialise positions in a circle.\n const layout: LayoutNode[] = nodes.map((n, i) => {\n const angle = (i / nodes.length) * Math.PI * 2;\n const r = CANVAS_SIZE * 0.28;\n return {\n ...n,\n x: CANVAS_SIZE / 2 + r * Math.cos(angle) + (Math.random() - 0.5) * 40,\n y: CANVAS_SIZE / 2 + r * Math.sin(angle) + (Math.random() - 0.5) * 40,\n vx: 0,\n vy: 0,\n };\n });\n\n const pos = new Map<string, LayoutNode>();\n for (const l of layout) pos.set(l.id, l);\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n const t = 1 - iter / ITERATIONS; // cooling\n\n // Repulsion (Coulomb's law).\n for (let i = 0; i < layout.length; i++) {\n for (let j = i + 1; j < layout.length; j++) {\n const a = layout[i];\n const b = layout[j];\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n const force = (400 * t) / (dist * dist);\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n a.vx -= fx;\n a.vy -= fy;\n b.vx += fx;\n b.vy += fy;\n }\n }\n\n // Spring attraction along edges.\n for (const e of edges) {\n const a = pos.get(e.source);\n const b = pos.get(e.target);\n if (!a || !b) continue;\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n const ideal = 80;\n const force = (dist - ideal) * 0.08 * t;\n const fx = (dx / dist) * force;\n const fy = (dy / dist) * force;\n a.vx += fx;\n a.vy += fy;\n b.vx -= fx;\n b.vy -= fy;\n }\n\n // Center gravity.\n const cx = CANVAS_SIZE / 2;\n const cy = CANVAS_SIZE / 2;\n for (const l of layout) {\n l.vx += (cx - l.x) * 0.01 * t;\n l.vy += (cy - l.y) * 0.01 * t;\n }\n\n // Apply velocity with damping.\n for (const l of layout) {\n l.vx *= 0.85;\n l.vy *= 0.85;\n l.x += l.vx;\n l.y += l.vy;\n // Clamp to canvas.\n l.x = Math.max(20, Math.min(CANVAS_SIZE - 20, l.x));\n l.y = Math.max(20, Math.min(CANVAS_SIZE - 20, l.y));\n }\n }\n\n return layout;\n}\n\nexport function MemoryGraphView({ data, onNodeClick, className }: Props) {\n const svgRef = useRef<SVGSVGElement>(null);\n\n // Pan/zoom state.\n const [transform, setTransform] = useState({ x: 0, y: 0, scale: 1 });\n const dragging = useRef(false);\n const dragStart = useRef({ x: 0, y: 0, tx: 0, ty: 0 });\n const lastTouchDist = useRef<number | null>(null);\n\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [hoveredId, setHoveredId] = useState<string | null>(null);\n\n // Compute layout once.\n const layout = useMemo(() => layoutNodes(data.nodes, data.edges), [data.nodes, data.edges]);\n\n const nodeMap = useMemo(() => {\n const m = new Map<string, LayoutNode>();\n for (const l of layout) m.set(l.id, l);\n return m;\n }, [layout]);\n\n // Pan handlers.\n const onMouseDown = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if ((e.target as Element).closest('.memory-graph-node')) return;\n dragging.current = true;\n dragStart.current = { x: e.clientX, y: e.clientY, tx: transform.x, ty: transform.y };\n }, [transform]);\n\n const onMouseMove = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if (!dragging.current) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setTransform((t) => ({ ...t, x: dragStart.current.tx + dx, y: dragStart.current.ty + dy }));\n }, []);\n\n const onMouseUp = useCallback(() => {\n dragging.current = false;\n }, []);\n\n // Zoom handlers.\n const onWheel = useCallback((e: React.WheelEvent<SVGSVGElement>) => {\n e.preventDefault();\n const factor = e.deltaY < 0 ? 1.1 : 0.9;\n const svg = svgRef.current;\n if (!svg) return;\n const rect = svg.getBoundingClientRect();\n const mx = e.clientX - rect.left;\n const my = e.clientY - rect.top;\n setTransform((t) => {\n const newScale = Math.max(0.2, Math.min(4, t.scale * factor));\n const scaleChange = newScale / t.scale;\n return {\n x: mx - (mx - t.x) * scaleChange,\n y: my - (my - t.y) * scaleChange,\n scale: newScale,\n };\n });\n }, []);\n\n // Touch zoom.\n const onTouchStart = useCallback((e: React.TouchEvent<SVGSVGElement>) => {\n const touches = Array.from(e.touches);\n if (touches.length === 2) {\n const [t0, t1] = touches;\n lastTouchDist.current = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);\n } else if (touches.length === 1) {\n dragging.current = true;\n dragStart.current = { x: touches[0].clientX, y: touches[0].clientY, tx: transform.x, ty: transform.y };\n }\n }, [transform]);\n\n const onTouchMove = useCallback((e: React.TouchEvent<SVGSVGElement>) => {\n const touches = Array.from(e.touches);\n if (touches.length === 2 && lastTouchDist.current !== null) {\n const [t0, t1] = touches;\n const dist = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);\n const factor = dist / lastTouchDist.current;\n lastTouchDist.current = dist;\n setTransform((t) => ({ ...t, scale: Math.max(0.2, Math.min(4, t.scale * factor)) }));\n } else if (touches.length === 1 && dragging.current) {\n const dx = touches[0].clientX - dragStart.current.x;\n const dy = touches[0].clientY - dragStart.current.y;\n setTransform((t) => ({ ...t, x: dragStart.current.tx + dx, y: dragStart.current.ty + dy }));\n }\n }, []);\n\n const onTouchEnd = useCallback(() => {\n dragging.current = false;\n lastTouchDist.current = null;\n }, []);\n\n const handleNodeClick = useCallback((node: LayoutNode) => {\n setSelectedId(node.id === selectedId ? null : node.id);\n onNodeClick?.(node);\n }, [selectedId, onNodeClick]);\n\n const strokeWidth = Math.max(0.5, 1 / Math.log2(transform.scale + 1));\n\n return (\n <svg\n ref={svgRef}\n className={cn('memory-graph-canvas', className)}\n viewBox={`0 0 ${CANVAS_SIZE} ${CANVAS_SIZE}`}\n style={{ width: '100%', height: '100%', minHeight: 400, cursor: dragging.current ? 'grabbing' : 'grab' }}\n onMouseDown={onMouseDown}\n onMouseMove={onMouseMove}\n onMouseUp={onMouseUp}\n onMouseLeave={onMouseUp}\n onWheel={onWheel}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n onTouchEnd={onTouchEnd}\n >\n <g transform={`translate(${transform.x},${transform.y}) scale(${transform.scale})`}>\n {/* Edges */}\n {data.edges.map((edge, i) => {\n const src = nodeMap.get(edge.source);\n const tgt = nodeMap.get(edge.target);\n if (!src || !tgt) return null;\n const isHighlighted = hoveredId === edge.source || hoveredId === edge.target || selectedId === edge.source || selectedId === edge.target;\n return (\n <line\n key={`e-${i}`}\n x1={src.x} y1={src.y}\n x2={tgt.x} y2={tgt.y}\n stroke={isHighlighted ? '#8b5cf6' : '#2d3648'}\n strokeWidth={isHighlighted ? strokeWidth * 2 : strokeWidth}\n strokeOpacity={isHighlighted ? 0.9 : 0.5}\n />\n );\n })}\n\n {/* Nodes */}\n {layout.map((node) => {\n const r = nodeRadius(node);\n const color = getGroupColor(node.group, node.type);\n const isSelected = selectedId === node.id;\n const isHovered = hoveredId === node.id;\n return (\n <g\n key={node.id}\n className=\"memory-graph-node\"\n transform={`translate(${node.x},${node.y})`}\n onClick={() => handleNodeClick(node)}\n onMouseEnter={() => setHoveredId(node.id)}\n onMouseLeave={() => setHoveredId(null)}\n style={{ cursor: 'pointer' }}\n >\n {/* Hit area */}\n <circle r={r + 6} fill=\"transparent\" />\n {/* Glow when selected/hovered */}\n {(isSelected || isHovered) && (\n <circle r={r + 4} fill={color} fillOpacity={0.2} />\n )}\n {/* Main circle */}\n <circle\n r={r}\n fill={color}\n fillOpacity={isSelected ? 1 : 0.75}\n stroke={isSelected ? '#fff' : color}\n strokeWidth={isSelected ? 2 : 1}\n />\n {/* Label */}\n {transform.scale > 0.5 && (\n <text\n y={r + 12}\n textAnchor=\"middle\"\n fontSize={Math.max(8, Math.min(11, 10 / Math.sqrt(transform.scale)))}\n fill=\"var(--text-dim, #b4bcd0)\"\n style={{ pointerEvents: 'none', userSelect: 'none' }}\n >\n {node.label.length > 20 ? node.label.slice(0, 18) + '…' : node.label}\n </text>\n )}\n </g>\n );\n })}\n </g>\n </svg>\n );\n}\n","// src/web/views/memory/MemoryGraphLegend.tsx — color legend for node groups.\n\nimport React from 'react';\nimport { cn } from '../../lib/utils';\n\nconst LEGEND_ITEMS = [\n { color: '#8b5cf6', label: 'Note / Default' },\n { color: '#34d399', label: 'Entity (LightRAG)' },\n { color: '#fbbf24', label: 'Concept (LightRAG)' },\n { color: '#f87171', label: 'Root / Ungrouped' },\n];\n\ntype Props = { className?: string };\n\nexport function MemoryGraphLegend({ className }: Props) {\n return (\n <div className={cn('memory-graph-legend', className)}>\n {LEGEND_ITEMS.map((item) => (\n <span key={item.label} className=\"memory-graph-legend-item\">\n <span\n className=\"memory-graph-legend-dot\"\n style={{ background: item.color }}\n />\n {item.label}\n </span>\n ))}\n </div>\n );\n}\n","// src/web/views/memory/MemoryGraphPanel.tsx — Memory Graph panel (v4.9).\n//\n// Interactive SVG knowledge graph spanning LightRAG entities + Obsidian wikilinks.\n\nimport React, { useCallback, useEffect, useState } from 'react';\nimport { Network, RefreshCw } from 'lucide-react';\nimport { Card, CardMeta, CardTitle } from '../../components/Card';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\nimport { cn } from '../../lib/utils';\nimport { MemoryGraphView, type GraphNode, type GraphData } from './MemoryGraphView';\nimport { MemoryGraphLegend } from './MemoryGraphLegend';\n\ntype GraphResponse = {\n nodes: GraphNode[];\n edges: Array<{ source: string; target: string; type: string; weight: number }>;\n totalNodes: number;\n totalEdges: number;\n};\n\ntype Props = { refreshKey: number };\n\nexport function MemoryGraphPanel({ refreshKey }: Props) {\n const toast = useToast();\n const [data, setData] = useState<GraphData>({ nodes: [], edges: [] });\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [filter, setFilter] = useState('');\n const [depth, setDepth] = useState(2);\n const [root, setRoot] = useState('');\n const [stats, setStats] = useState<{ totalNodes: number; totalEdges: number } | null>(null);\n const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);\n\n const fetchGraph = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const params = new URLSearchParams({ limit: '200' });\n if (root) params.set('root', root);\n params.set('depth', String(depth));\n const res = await api.get<GraphResponse>(`/memory/graph?${params}`);\n setData({ nodes: res.nodes || [], edges: res.edges || [] });\n setStats({ totalNodes: res.totalNodes ?? res.nodes?.length ?? 0, totalEdges: res.totalEdges ?? res.edges?.length ?? 0 });\n } catch (err) {\n setError((err as Error).message);\n toast.error(`Graph load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n }, [root, depth, toast]);\n\n useEffect(() => {\n fetchGraph();\n }, [fetchGraph, refreshKey]);\n\n const onNodeClick = useCallback((node: GraphNode) => {\n setSelectedNode((prev) => (prev?.id === node.id ? null : node));\n }, []);\n\n // Filter nodes by label.\n const filteredData = filter.trim()\n ? {\n nodes: data.nodes.filter((n) => n.label.toLowerCase().includes(filter.toLowerCase())),\n edges: data.edges.filter(\n (e) =>\n data.nodes.some((n) => n.id === e.source && n.label.toLowerCase().includes(filter.toLowerCase())) ||\n data.nodes.some((n) => n.id === e.target && n.label.toLowerCase().includes(filter.toLowerCase())),\n ),\n }\n : data;\n\n return (\n <div className=\"memory-panel-content\">\n {/* ── Controls ─────────────────────────────────────────────── */}\n <Card>\n <CardTitle>\n <Network size={14} /> Memory Graph\n </CardTitle>\n <CardMeta>Interactive knowledge graph — LightRAG entities + Obsidian wikilinks. Drag to pan, scroll to zoom.</CardMeta>\n\n <div className=\"memory-graph-controls\">\n <div className=\"memory-graph-search-row\">\n <label htmlFor=\"graph-filter\" className=\"sr-only\">Filter nodes</label>\n <input\n id=\"graph-filter\"\n type=\"text\"\n className=\"input\"\n placeholder=\"Filter nodes…\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n style={{ maxWidth: 240 }}\n />\n <input\n type=\"text\"\n className=\"input\"\n placeholder=\"Root note id (optional)\"\n value={root}\n onChange={(e) => setRoot(e.target.value)}\n style={{ maxWidth: 240 }}\n title=\"Start from a specific note\"\n />\n <label htmlFor=\"graph-depth\" className=\"sr-only\">Depth</label>\n <span className=\"muted text-sm\" style={{ whiteSpace: 'nowrap' }}>\n Depth\n <input\n id=\"graph-depth\"\n type=\"range\"\n min={1}\n max={3}\n value={depth}\n onChange={(e) => setDepth(parseInt(e.target.value, 10))}\n style={{ marginLeft: 8, verticalAlign: 'middle' }}\n />\n {depth}\n </span>\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={fetchGraph}\n title=\"Refresh graph\"\n disabled={loading}\n >\n <RefreshCw size={14} className={loading ? 'memory-spin' : ''} />\n </button>\n </div>\n\n <MemoryGraphLegend />\n </div>\n </Card>\n\n {/* ── Graph canvas ─────────────────────────────────────────── */}\n <Card>\n {loading && !data.nodes.length ? (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading graph…</p>\n </div>\n ) : error && !data.nodes.length ? (\n <div className=\"muted text-sm\">Failed to load graph: {error}</div>\n ) : data.nodes.length === 0 ? (\n <div className=\"muted text-sm\">\n No graph data available. Index some notes first with LightRAG or add wikilinks to your vault.\n </div>\n ) : (\n <div style={{ position: 'relative' }}>\n <MemoryGraphView\n data={filteredData}\n onNodeClick={onNodeClick}\n className=\"memory-graph-canvas-svg\"\n />\n {filter && (\n <div className=\"text-xs muted\" style={{ marginTop: 4 }}>\n Showing {filteredData.nodes.length} of {data.nodes.length} nodes\n </div>\n )}\n </div>\n )}\n </Card>\n\n {/* ── Node detail ──────────────────────────────────────────── */}\n {selectedNode && (\n <Card>\n <CardTitle>{selectedNode.label}</CardTitle>\n <CardMeta>\n <code>{selectedNode.id}</code>\n </CardMeta>\n <dl className=\"memory-config-row\">\n <dt>Type</dt>\n <dd><code>{selectedNode.type}</code></dd>\n <dt>Group</dt>\n <dd><code>{selectedNode.group}</code></dd>\n <dt>Size</dt>\n <dd>{selectedNode.size}</dd>\n </dl>\n </Card>\n )}\n\n {/* ── Stats footer ─────────────────────────────────────────── */}\n {stats && (\n <Card>\n <div className=\"memory-graph-stats\">\n <span>{stats.totalNodes} node{stats.totalNodes !== 1 ? 's' : ''}</span>\n <span className=\"muted\">·</span>\n <span>{stats.totalEdges} edge{stats.totalEdges !== 1 ? 's' : ''}</span>\n {filter && <span className=\"muted\">· {filteredData.nodes.length} shown</span>}\n </div>\n </Card>\n )}\n </div>\n );\n}\n","// src/web/components/ScreenshotCapture.tsx — v5.0.0\n//\n// Uses browser's getDisplayMedia() to capture a screen, window, or browser tab.\n// Returns a blob URL for preview and uploads to /api/ocr/process for text extraction.\n\nimport { useState, useCallback } from 'react';\nimport { Camera, Loader2 } from 'lucide-react';\nimport { Button } from './Button';\nimport { Card, CardTitle } from './Card';\nimport { useToast } from './Toast';\nimport { api } from '../lib/api';\n\nexport type ScreenshotCaptureProps = {\n onTextExtracted?: (text: string, notePath: string) => void;\n};\n\nexport function ScreenshotCapture({ onTextExtracted }: ScreenshotCaptureProps) {\n const toast = useToast();\n const [imageUrl, setImageUrl] = useState<string | null>(null);\n const [processing, setProcessing] = useState(false);\n const [capturing, setCapturing] = useState(false);\n\n const capture = useCallback(async () => {\n setCapturing(true);\n try {\n const stream = await navigator.mediaDevices.getDisplayMedia({\n video: { mediaSource: 'screen' } as MediaTrackConstraints,\n });\n const video = document.createElement('video');\n video.srcObject = stream;\n await video.play();\n\n const canvas = document.createElement('canvas');\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n toast.error('Failed to get canvas context');\n return;\n }\n ctx.drawImage(video, 0, 0);\n\n // Stop all tracks\n stream.getTracks().forEach((t) => t.stop());\n video.remove();\n\n canvas.toBlob(async (blob) => {\n if (!blob) {\n toast.error('Failed to capture screenshot');\n return;\n }\n const url = URL.createObjectURL(blob);\n setImageUrl(url);\n await processImage(blob);\n }, 'image/png');\n } catch (err) {\n if ((err as Error).name !== 'NotAllowedError') {\n toast.error(`Capture failed: ${(err as Error).message}`);\n }\n // NotAllowedError = user cancelled the picker — no toast needed\n } finally {\n setCapturing(false);\n }\n }, [toast]);\n\n const processImage = useCallback(async (blob: Blob) => {\n setProcessing(true);\n try {\n const reader = new FileReader();\n const base64 = await new Promise<string>((resolve, reject) => {\n reader.onload = () => {\n const result = reader.result as string;\n // Strip data:image/png;base64, prefix for API\n const b64 = result.includes(',') ? result.split(',')[1] : result;\n resolve(b64);\n };\n reader.onerror = () => reject(new Error('FileReader failed'));\n reader.readAsDataURL(blob);\n });\n\n const r = await api.post<{ ok: boolean; text: string; notePath: string }>('/ocr/process', {\n image: base64,\n lang: 'eng',\n });\n\n if (r.ok) {\n toast.success('Text extracted from screenshot');\n onTextExtracted?.(r.text, r.notePath);\n }\n } catch (err) {\n toast.error(`OCR failed: ${(err as Error).message}`);\n } finally {\n setProcessing(false);\n }\n }, [toast, onTextExtracted]);\n\n const dismiss = useCallback(() => {\n setImageUrl(null);\n }, []);\n\n return (\n <Card variant=\"outlined\" className=\"screenshot-capture-card\">\n <CardTitle><Camera size={14} /> Screenshot Capture</CardTitle>\n\n <div className=\"screenshot-capture-body\">\n {!imageUrl ? (\n <div className=\"screenshot-capture-empty\">\n <Camera size={32} className=\"muted\" />\n <p className=\"muted text-sm\">Capture your screen to extract text via OCR.</p>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={capture}\n disabled={capturing}\n >\n {capturing ? <Loader2 size={12} className=\"spinner\" /> : <Camera size={12} />}\n {capturing ? 'Selecting…' : 'Capture Screen'}\n </Button>\n </div>\n ) : (\n <div className=\"screenshot-capture-preview\">\n <img src={imageUrl} alt=\"Captured screenshot\" className=\"screenshot-capture-img\" />\n <div className=\"screenshot-capture-actions\">\n {processing && (\n <span className=\"text-sm muted\">\n <Loader2 size={12} className=\"spinner\" /> Extracting text…\n </span>\n )}\n <Button variant=\"ghost\" size=\"sm\" onClick={dismiss} disabled={processing}>\n Dismiss\n </Button>\n </div>\n </div>\n )}\n </div>\n </Card>\n );\n}\n","// src/web/components/ScreenshotOCR.tsx — v5.0.0\n//\n// Combines ScreenshotCapture + extracted text display in one panel.\n// Shows the screenshot preview and the OCR-extracted text side by side.\n\nimport { useState } from 'react';\nimport { FileText } from 'lucide-react';\nimport { ScreenshotCapture } from './ScreenshotCapture';\nimport { Card, CardTitle, CardMeta } from './Card';\n\nexport function ScreenshotOCR() {\n const [ocrText, setOcrText] = useState<string | null>(null);\n const [notePath, setNotePath] = useState<string | null>(null);\n\n const handleTextExtracted = (text: string, path: string) => {\n setOcrText(text);\n setNotePath(path);\n };\n\n return (\n <div className=\"screenshot-ocr-panel\">\n <ScreenshotCapture onTextExtracted={handleTextExtracted} />\n\n {ocrText !== null && (\n <Card variant=\"outlined\" className=\"screenshot-ocr-result-card\">\n <CardTitle>\n <FileText size={14} /> Extracted Text\n </CardTitle>\n {notePath && <CardMeta>Saved to: {notePath}</CardMeta>}\n\n <div className=\"screenshot-ocr-text\">\n {ocrText ? (\n <pre className=\"screenshot-ocr-pre mono text-sm\">{ocrText}</pre>\n ) : (\n <p className=\"muted text-sm\">No text was found in the captured image.</p>\n )}\n </div>\n </Card>\n )}\n </div>\n );\n}\n","// src/web/views/memory/FromScreenshotPanel.tsx — v5.0.0\n//\n// Memory tab panel that wraps ScreenshotOCR for the three-column Memory layout.\n// Provides a self-contained screenshot → OCR → save workflow.\n\nimport { ScreenshotOCR } from '../../components/ScreenshotOCR';\nimport { Card } from '../../components/Card';\n\ntype Props = {\n refreshKey: number;\n};\n\nexport function FromScreenshotPanel({ refreshKey: _refreshKey }: Props) {\n return (\n <div className=\"memory-panel-content\">\n <Card variant=\"outlined\" className=\"memory-panel-card\">\n <div className=\"memory-panel-body\">\n <ScreenshotOCR />\n </div>\n </Card>\n </div>\n );\n}\n","// src/web/views/memory/VaultFromClipboardPanel.tsx — v5.0.0\n//\n// Memory tab panel for pasting content directly into the vault.\n// Accepts URL + title + content text, saves via /api/clipboard/save.\n\nimport { useState } from 'react';\nimport { Clipboard, Loader2 } from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardTitle } from '../../components/Card';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\n\ntype Props = {\n refreshKey: number;\n};\n\nexport function VaultFromClipboardPanel({ refreshKey: _refreshKey }: Props) {\n const toast = useToast();\n const [url, setUrl] = useState('');\n const [title, setTitle] = useState('');\n const [content, setContent] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleSave = async () => {\n if (!content.trim()) {\n toast.error('Content is required');\n return;\n }\n setSaving(true);\n try {\n const r = await api.post<{ ok: boolean; notePath: string }>('/clipboard/save', {\n url: url.trim() || undefined,\n title: title.trim() || undefined,\n content: content,\n savedAt: new Date().toISOString(),\n });\n if (r.ok) {\n toast.success(`Saved to ${r.notePath}`);\n setUrl('');\n setTitle('');\n setContent('');\n }\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"memory-panel-content\">\n <Card variant=\"outlined\" className=\"memory-panel-card\">\n <div className=\"memory-panel-body\">\n <div className=\"vault-clipboard-panel\">\n <div className=\"vault-clipboard-header\">\n <Clipboard size={16} />\n <span>Paste Content</span>\n </div>\n\n <label className=\"field-label\" htmlFor=\"clip-url\">URL (optional)</label>\n <input\n id=\"clip-url\"\n type=\"text\"\n className=\"input\"\n placeholder=\"https://example.com\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n />\n\n <label className=\"field-label\" htmlFor=\"clip-title\" style={{ marginTop: 10 }}>Title (optional)</label>\n <input\n id=\"clip-title\"\n type=\"text\"\n className=\"input\"\n placeholder=\"Page title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n\n <label className=\"field-label\" htmlFor=\"clip-content\" style={{ marginTop: 10 }}>Content *</label>\n <textarea\n id=\"clip-content\"\n className=\"input vault-clipboard-textarea mono text-sm\"\n rows={12}\n placeholder=\"Paste or type content to save to your vault…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n />\n\n <div className=\"vault-clipboard-actions\" style={{ marginTop: 12 }}>\n <Button variant=\"primary\" size=\"sm\" onClick={handleSave} disabled={saving || !content.trim()}>\n {saving && <Loader2 size={12} className=\"spinner\" />}\n Save to Vault\n </Button>\n </div>\n </div>\n </div>\n </Card>\n </div>\n );\n}\n","// src/web/components/VoiceRecorder.tsx — v5.0.0\n//\n// MediaRecorder wrapper: records audio in webm/opus, uploads to /api/voice/upload\n// on stop, then calls onSaved(notePath, transcription) so the parent can refresh\n// the note list.\n\nimport { useState, useRef } from 'react';\nimport { Mic, Square, Loader2 } from 'lucide-react';\nimport { Button } from './Button';\n\nexport type VoiceRecorderProps = {\n /** Vault path to store the transcript under */\n vaultPath?: string;\n /** Called after the note is saved with the note path and transcription text */\n onSaved?: (notePath: string, transcription: string | null) => void;\n};\n\nexport function VoiceRecorder({ vaultPath, onSaved }: VoiceRecorderProps) {\n const [recording, setRecording] = useState(false);\n const [transcribing, setTranscribing] = useState(false);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n\n const startRecording = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n // Prefer webm/opus; fall back to whatever the browser offers\n const mimeType =\n MediaRecorder.isTypeSupported('audio/webm;codecs=opus')\n ? 'audio/webm;codecs=opus'\n : 'audio/webm';\n const recorder = new MediaRecorder(stream, { mimeType });\n\n recorder.ondataavailable = (e) => {\n if (e.data && e.data.size > 0) {\n chunksRef.current.push(e.data);\n }\n };\n\n recorder.onstop = async () => {\n const blob = new Blob(chunksRef.current, { type: 'audio/webm' });\n chunksRef.current = [];\n // Stop all tracks to release the microphone\n stream.getTracks().forEach((t) => t.stop());\n await uploadAndTranscribe(blob);\n };\n\n recorder.start(1000); // timeslice=1s for chunk delivery\n mediaRecorderRef.current = recorder;\n setRecording(true);\n } catch (err) {\n // getUserMedia not available or permission denied\n console.error('[VoiceRecorder] failed to start recording:', err);\n }\n };\n\n const stopRecording = () => {\n const rec = mediaRecorderRef.current;\n if (!rec) return;\n rec.stop();\n setRecording(false);\n setTranscribing(true);\n };\n\n const uploadAndTranscribe = async (blob: Blob) => {\n try {\n const form = new FormData();\n form.append('audio', blob, 'voice-note.webm');\n form.append('vaultPath', vaultPath || '');\n const res = await fetch('/api/voice/upload', { method: 'POST', body: form });\n if (!res.ok) {\n console.error('[VoiceRecorder] upload failed:', res.status, await res.text());\n setTranscribing(false);\n return;\n }\n const { notePath, transcription } = await res.json();\n onSaved?.(notePath, transcription);\n } catch (err) {\n console.error('[VoiceRecorder] upload error:', err);\n } finally {\n setTranscribing(false);\n }\n };\n\n return (\n <div className=\"voice-recorder\">\n {!recording && !transcribing && (\n <Button variant=\"accent\" size=\"sm\" onClick={startRecording} aria-label=\"Start recording\">\n <Mic size={14} /> Record\n </Button>\n )}\n {recording && (\n <Button variant=\"danger\" size=\"sm\" onClick={stopRecording} aria-label=\"Stop recording\">\n <Square size={14} /> Stop\n </Button>\n )}\n {transcribing && (\n <Button variant=\"secondary\" size=\"sm\" disabled>\n <Loader2 size={14} className=\"spinning\" /> Transcribing…\n </Button>\n )}\n </div>\n );\n}\n","// src/web/components/VoiceNotesPanel.tsx — v5.0.0\n//\n// List + record + playback for voice notes.\n// Wire into Memory tab as the \"Voice Notes\" source panel.\n\nimport { useEffect, useState } from 'react';\nimport { Play, Pause, Trash2, Search as SearchIcon, Mic } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { VoiceRecorder } from './VoiceRecorder';\nimport { Button } from './Button';\n\ntype VoiceNote = {\n id: string;\n audioPath: string;\n notePath: string | null;\n transcript: string | null;\n durationSec: number | null;\n vaultPath: string | null;\n createdAtMs: number;\n updatedAtMs: number;\n};\n\ntype Props = {\n /** Vault path to scope the panel to */\n vaultPath?: string;\n /** Key to force reload when parent refreshes */\n refreshKey?: number;\n};\n\nfunction NoteCard({ note, onDelete }: { note: VoiceNote; onDelete: (id: string) => void }) {\n const [playing, setPlaying] = useState(false);\n const [audio] = useState(() => {\n if (!note.audioPath) return null;\n const a = new Audio(`/api/voice/${note.id}/audio`);\n a.onended = () => setPlaying(false);\n return a;\n });\n\n const togglePlay = () => {\n if (!audio) return;\n if (playing) {\n audio.pause();\n audio.currentTime = 0;\n setPlaying(false);\n } else {\n audio.play();\n setPlaying(true);\n }\n };\n\n const created = new Date(note.createdAtMs).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n\n return (\n <div className=\"voice-note-card\">\n <div className=\"voice-note-card-head\">\n <div className=\"voice-note-card-meta\">\n <span className=\"voice-note-date\">{created}</span>\n {note.durationSec && (\n <span className=\"voice-note-duration\">{Math.round(note.durationSec)}s</span>\n )}\n </div>\n <div className=\"voice-note-card-actions\">\n {audio && (\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={togglePlay}\n aria-label={playing ? 'Pause' : 'Play'}\n title={playing ? 'Pause' : 'Play'}\n >\n {playing ? <Pause size={13} /> : <Play size={13} />}\n </button>\n )}\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => onDelete(note.id)}\n aria-label=\"Delete note\"\n title=\"Delete note\"\n >\n <Trash2 size={13} />\n </button>\n </div>\n </div>\n\n {note.transcript && (\n <p className=\"voice-note-transcript\">{note.transcript}</p>\n )}\n\n {!note.transcript && (\n <p className=\"voice-note-no-transcript muted text-sm\">No transcription available</p>\n )}\n </div>\n );\n}\n\nexport function VoiceNotesPanel({ vaultPath, refreshKey = 0 }: Props) {\n const [notes, setNotes] = useState<VoiceNote[]>([]);\n const [search, setSearch] = useState('');\n const [loading, setLoading] = useState(true);\n\n const loadNotes = async () => {\n setLoading(true);\n try {\n const vaultParam = vaultPath ? `?vaultPath=${encodeURIComponent(vaultPath)}` : '';\n const r = await fetch(`/api/voice/list${vaultParam}`);\n const data = await r.json();\n setNotes(data.notes || []);\n } catch (err) {\n console.error('[VoiceNotesPanel] failed to load notes:', err);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n loadNotes();\n \n // v5.2.0 — Listen for transcription worker updates\n const handleMessage = (e: MessageEvent) => {\n try {\n const msg = JSON.parse(e.data);\n if (msg.type === 'voice:updated' && msg.noteId) {\n // Update the matching note's transcript in place\n setNotes((prev) => prev.map((n) => \n n.id === msg.noteId \n ? { ...n, transcript: msg.patch?.transcript ?? n.transcript }\n : n\n ));\n }\n } catch { /* ignore parse errors */ }\n };\n \n // Connect to WS for real-time transcript updates\n const wsUrl = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`;\n let ws: WebSocket | null = null;\n try {\n ws = new WebSocket(wsUrl);\n ws.addEventListener('message', handleMessage);\n } catch { /* ignore */ }\n \n return () => {\n ws?.removeEventListener('message', handleMessage);\n ws?.close();\n };\n }, [vaultPath, refreshKey]);\n\n const handleDelete = async (id: string) => {\n try {\n const r = await fetch(`/api/voice/${id}`, { method: 'DELETE' });\n if (r.ok || r.status === 204) {\n setNotes((prev) => prev.filter((n) => n.id !== id));\n }\n } catch (err) {\n console.error('[VoiceNotesPanel] delete failed:', err);\n }\n };\n\n const filtered = notes.filter(\n (n) =>\n !search ||\n (n.transcript?.toLowerCase().includes(search.toLowerCase()) ?? false),\n );\n\n return (\n <Card>\n <CardTitle>\n <Mic size={14} /> Voice Notes\n </CardTitle>\n <CardMeta>Record and transcribe audio notes into your vault</CardMeta>\n\n {/* Search */}\n <div className=\"memory-search-row\">\n <input\n type=\"text\"\n className=\"input search-input\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search transcripts…\"\n aria-label=\"Search voice notes\"\n />\n </div>\n\n {/* Recorder */}\n <div className=\"voice-recorder-row\">\n <VoiceRecorder vaultPath={vaultPath} onSaved={loadNotes} />\n </div>\n\n {/* Note list */}\n {loading ? (\n <p className=\"muted text-sm\">Loading notes…</p>\n ) : filtered.length === 0 ? (\n <p className=\"muted text-sm\">\n {search ? 'No notes match your search.' : 'No voice notes yet. Hit Record to add one.'}\n </p>\n ) : (\n <div className=\"voice-note-list\">\n {filtered.map((n) => (\n <NoteCard key={n.id} note={n} onDelete={handleDelete} />\n ))}\n </div>\n )}\n </Card>\n );\n}\n","// src/web/views/Memory.tsx — v4.7.0 dedicated Memory tab.\n//\n// Three-column layout: left rail (source picker), main panel (per-source UI),\n// and a top stat row + a health hero at the top of every panel for context.\n//\n// The Memory subsystem has 4 sources (LightRAG, Obsidian vault, git sync,\n// semantic search) plus a config panel and a high-level overview. Each is a\n// standalone component under views/memory/.\n\nimport React, { useCallback, useState } from 'react';\nimport {\n Brain,\n Clipboard,\n FileText,\n GitBranch,\n LayoutDashboard,\n Mic,\n Network,\n RefreshCw,\n Scan,\n Search as SearchIcon,\n Sliders,\n} from 'lucide-react';\nimport { Card } from '../components/Card';\nimport { useToast } from '../components/Toast';\nimport { cn } from '../lib/utils';\nimport { MemoryOverview } from './memory/MemoryOverview';\nimport { LightragPanel } from './memory/LightragPanel';\nimport { ObsidianPanel } from './memory/ObsidianPanel';\nimport { GitSyncPanel } from './memory/GitSyncPanel';\nimport { SemanticSearchPanel } from './memory/SemanticSearchPanel';\nimport { ConfigPanel } from './memory/ConfigPanel';\nimport { MemoryGraphPanel } from './memory/MemoryGraphPanel';\nimport { FromScreenshotPanel } from './memory/FromScreenshotPanel';\nimport { VaultFromClipboardPanel } from './memory/VaultFromClipboardPanel';\nimport { VoiceNotesPanel } from '../components/VoiceNotesPanel';\n\ntype SubPanel = 'overview' | 'lightrag' | 'obsidian' | 'git' | 'semantic' | 'config' | 'graph' | 'webclip' | 'screenshot' | 'voice';\n\ntype Props = {\n snapshot: unknown;\n settings: unknown;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst SOURCES: Array<{\n id: SubPanel;\n label: string;\n icon: typeof LayoutDashboard;\n}> = [\n { id: 'overview', label: 'Overview', icon: LayoutDashboard },\n { id: 'lightrag', label: 'LightRAG', icon: Brain },\n { id: 'obsidian', label: 'Obsidian Vault', icon: FileText },\n { id: 'git', label: 'Git Sync', icon: GitBranch },\n { id: 'semantic', label: 'Semantic Search', icon: SearchIcon },\n { id: 'config', label: 'Config', icon: Sliders },\n { id: 'graph', label: 'Memory Graph', icon: Network },\n { id: 'webclip', label: 'Web Clip', icon: Clipboard },\n { id: 'screenshot', label: 'Screenshot OCR', icon: Scan },\n { id: 'voice', label: 'Voice Notes', icon: Mic },\n];\n\nfunction MemoryInner(_props: Props) {\n const toast = useToast();\n const [active, setActive] = useState<SubPanel>('overview');\n const [refreshKey, setRefreshKey] = useState(0);\n\n const refresh = useCallback(() => {\n setRefreshKey((k) => k + 1);\n }, []);\n\n const onRefreshAll = useCallback(async () => {\n refresh();\n toast.info('Refreshing memory…', 1200);\n }, [refresh, toast]);\n\n const renderPanel = () => {\n switch (active) {\n case 'overview':\n return <MemoryOverview refreshKey={refreshKey} onRefresh={refresh} setActiveSubPanel={setActive} />;\n case 'lightrag':\n return <LightragPanel refreshKey={refreshKey} />;\n case 'obsidian':\n return <ObsidianPanel refreshKey={refreshKey} />;\n case 'git':\n return <GitSyncPanel refreshKey={refreshKey} />;\n case 'semantic':\n return <SemanticSearchPanel refreshKey={refreshKey} />;\n case 'config':\n return <ConfigPanel refreshKey={refreshKey} />;\n case 'graph':\n return <MemoryGraphPanel refreshKey={refreshKey} />;\n case 'webclip':\n return <VaultFromClipboardPanel refreshKey={refreshKey} />;\n case 'screenshot':\n return <FromScreenshotPanel refreshKey={refreshKey} />;\n case 'voice':\n return <VoiceNotesPanel refreshKey={refreshKey} />;\n default:\n return <Card>Unknown panel: {active}</Card>;\n }\n };\n\n return (\n <div className=\"view view-memory memory-tab\">\n {/* ── Header ─────────────────────────────────────────────── */}\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <Brain size={18} /> Memory\n </h2>\n <p className=\"view-subtitle\">\n LightRAG, Obsidian vault, git sync, semantic search, web clips, and screenshot OCR — all in one place.\n </p>\n </div>\n <div className=\"view-actions\">\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={onRefreshAll}\n aria-label=\"Refresh memory\"\n title=\"Refresh\"\n >\n <RefreshCw size={14} />\n </button>\n </div>\n </header>\n\n <div className=\"memory-tab-body\">\n {/* ── Source rail ─────────────────────────────────────── */}\n <nav className=\"memory-source-rail\" aria-label=\"Memory sources\">\n {SOURCES.map((s) => {\n const Icon = s.icon;\n const isActive = active === s.id;\n return (\n <button\n key={s.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n className={cn('memory-source-button', isActive && 'memory-source-button-active')}\n onClick={() => setActive(s.id)}\n >\n <Icon size={16} aria-hidden />\n <span>{s.label}</span>\n </button>\n );\n })}\n </nav>\n\n {/* ── Main panel ─────────────────────────────────────── */}\n <div className=\"memory-main\" key={active}>\n {renderPanel()}\n </div>\n </div>\n </div>\n );\n}\nexport const Memory = React.memo(MemoryInner);\n","// src/views/History.tsx — v3.4.0: cross-project history view.\n// Shows per-project timelines (task events, plan events, project lifecycle)\n// aggregated from the activity log.\n\nimport React, { useEffect, useState } from 'react';\nimport {\n History as HistoryIcon,\n RefreshCw,\n Folder,\n CheckSquare,\n Filter,\n ChevronDown,\n ChevronRight,\n Download,\n FileText,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Spinner } from '../components/Spinner';\nimport { VirtualList } from '../components/VirtualList';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport { cn, formatRelative } from '../lib/utils';\nimport type { Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype HistoryEvent = {\n ts: string;\n kind: string;\n nodeId?: string;\n text?: string;\n author?: string;\n taskId?: string;\n [k: string]: unknown;\n};\n\ntype ProjectHistory = {\n id: string;\n name: string;\n path: string;\n status: string;\n lastAccessed?: string | null;\n tasks: { total: number; done: number; doing: number; blocked: number; queued: number };\n plans: number;\n};\n\ntype HistoryResponse = {\n events: HistoryEvent[];\n projects: ProjectHistory[];\n stats: { file: string; size: number; lines: number; lastTs: string | null; counts: Record<string, number> };\n generatedAt: string;\n};\n\nconst TIME_RANGES = [\n { id: '1h', label: 'Last hour', ms: 60 * 60 * 1000 },\n { id: '1d', label: 'Last day', ms: 24 * 60 * 60 * 1000 },\n { id: '7d', label: 'Last 7 days', ms: 7 * 24 * 60 * 60 * 1000 },\n { id: '30d', label: 'Last 30 days', ms: 30 * 24 * 60 * 60 * 1000 },\n { id: 'all', label: 'All time', ms: 0 },\n];\n\nfunction renderProjectCard(\n p: ProjectHistory,\n events: HistoryEvent[],\n expanded: Set<string>,\n toggleProject: (id: string) => void,\n): React.ReactNode {\n const isOpen = expanded.has(p.id);\n return (\n <Card key={p.id} className=\"history-project\" style={{ marginBottom: 4 }}>\n <div className=\"history-project-head\">\n <div style={{ display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0, flex: 1 }}>\n <div className=\"history-project-name\">\n <Folder size={16} /> {p.name}\n </div>\n <div className=\"history-project-meta\">{p.path}</div>\n </div>\n <div className=\"history-project-stats\">\n <span className=\"history-project-stat\">\n <span className=\"history-project-stat-num\">{p.tasks.done}</span>\n <span className=\"muted\">/ {p.tasks.total} done</span>\n </span>\n {p.tasks.doing > 0 && (\n <span className=\"history-project-stat\">\n <span className=\"history-project-stat-num\">{p.tasks.doing}</span>\n <span className=\"muted\">doing</span>\n </span>\n )}\n {p.tasks.blocked > 0 && (\n <span className=\"history-project-stat\">\n <span className=\"history-project-stat-num\">{p.tasks.blocked}</span>\n <span className=\"muted\">blocked</span>\n </span>\n )}\n <span className=\"history-project-stat\">\n <FileText size={11} /> <span className=\"history-project-stat-num\">{p.plans}</span>\n <span className=\"muted\"> plan{p.plans === 1 ? '' : 's'}</span>\n </span>\n {p.lastAccessed && (\n <span className=\"history-project-stat\">\n <span className=\"muted\">last opened {formatRelative(p.lastAccessed)}</span>\n </span>\n )}\n </div>\n <button\n type=\"button\"\n className=\"icon-btn\"\n onClick={() => toggleProject(p.id)}\n aria-label={isOpen ? 'Collapse' : 'Expand'}\n >\n {isOpen ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n </button>\n </div>\n\n {isOpen && (\n <div className=\"history-timeline-mini\">\n {events.length === 0 ? (\n <div className=\"muted\" style={{ padding: '12px 8px', fontSize: 12 }}>\n No events in this time range.\n </div>\n ) : (\n events.slice(-100).reverse().map((ev, i) => (\n <div key={i} className=\"history-timeline-row\">\n <span className=\"history-timeline-ts\">\n {new Date(ev.ts).toLocaleTimeString()}\n </span>\n <span className=\"history-timeline-kind\">{ev.kind || 'event'}</span>\n <span className=\"history-timeline-msg\" title={String(ev.text || ev.title || '')}>\n {ev.author ? `@${ev.author} ` : ''}\n {String(ev.text ?? ev.title ?? ev.name ?? '')}\n </span>\n </div>\n ))\n )}\n </div>\n )}\n </Card>\n );\n}\n\nexport function History({ snapshot }: Props) {\n const toast = useToast();\n const [data, setData] = useState<HistoryResponse | null>(null);\n const [loading, setLoading] = useState(true);\n const [rangeId, setRangeId] = useState<string>('1d');\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [tick, setTick] = useState(0);\n\n const load = async (since?: string) => {\n try {\n const q = since ? `?since=${encodeURIComponent(since)}&limit=1000` : '?limit=1000';\n const r = await api.get<HistoryResponse>(`/history${q}`);\n setData(r);\n setExpanded(\n new Set(\n r.projects\n .filter((project) => r.events.some((ev) => (ev as { projectId?: string }).projectId === project.id))\n .map((project) => project.id),\n ),\n );\n } catch (err) {\n toast.error(`History load failed: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setLoading(true);\n const range = TIME_RANGES.find((r) => r.id === rangeId) || TIME_RANGES[1];\n if (range.ms > 0) {\n const since = new Date(Date.now() - range.ms).toISOString();\n load(since);\n } else {\n load();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rangeId]);\n\n useEffect(() => {\n const id = setInterval(() => setTick((t) => t + 1), 30_000);\n return () => clearInterval(id);\n }, []);\n\n // Group events by project — use projectId where present, otherwise 'global'\n const eventsByProject = new Map<string, HistoryEvent[]>();\n for (const ev of data?.events || []) {\n const pid = (ev as { projectId?: string }).projectId || 'global';\n if (!eventsByProject.has(pid)) eventsByProject.set(pid, []);\n eventsByProject.get(pid)!.push(ev);\n }\n\n const toggleProject = (id: string) => {\n setExpanded((cur) => {\n const next = new Set(cur);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const onExportJson = () => {\n if (!data) return;\n const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `bizar-history-${new Date().toISOString().replace(/[:.]/g, '-')}.json`;\n a.click();\n URL.revokeObjectURL(url);\n toast.success('History exported.');\n };\n\n return (\n <div className=\"view view-history\" data-tick={tick}>\n <header className=\"view-header\">\n <div className=\"view-header-text\">\n <h2 className=\"view-title\">\n <HistoryIcon size={18} /> History\n </h2>\n <p className=\"view-subtitle\">\n Cross-project history of events, tasks, and plans.\n {data?.stats?.lastTs && (\n <> · last event {formatRelative(data.stats.lastTs)}</>\n )}\n </p>\n </div>\n <div className=\"view-actions\">\n <div className=\"tasks-toolbar-group\">\n <Filter size={14} style={{ color: 'var(--text-dim)' }} aria-hidden />\n <label htmlFor=\"history-range\" className=\"sr-only\">Time range</label>\n <select\n id=\"history-range\"\n className=\"select select-sm\"\n value={rangeId}\n onChange={(e) => setRangeId(e.target.value)}\n title=\"Time range\"\n aria-label=\"Time range\"\n >\n {TIME_RANGES.map((r) => (\n <option key={r.id} value={r.id}>{r.label}</option>\n ))}\n </select>\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n setLoading(true);\n const range = TIME_RANGES.find((r) => r.id === rangeId) || TIME_RANGES[1];\n if (range.ms > 0) {\n load(new Date(Date.now() - range.ms).toISOString());\n } else {\n load();\n }\n }}\n >\n <RefreshCw size={14} /> Refresh\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={onExportJson}>\n <Download size={14} /> Export\n </Button>\n </div>\n </header>\n\n {loading && (\n <div className=\"view-loading\">\n <Spinner size=\"lg\" />\n <p>Loading history…</p>\n </div>\n )}\n\n {!loading && data && (\n <div className=\"history-list\">\n {data.projects.length === 0 && (\n <Card>\n <CardTitle><Folder size={14} /> No projects</CardTitle>\n <CardMeta>Register a project in Overview to start tracking history.</CardMeta>\n </Card>\n )}\n\n {data.projects.length > 0 && (\n <VirtualList\n items={data.projects}\n itemHeight={70}\n height={Math.min(data.projects.length * 70, 500)}\n className=\"history-virtual-list\"\n renderItem={(p) => renderProjectCard(p, eventsByProject.get(p.id) || [], expanded, toggleProject)}\n />\n )}\n\n {/* Global / unassigned events */}\n {eventsByProject.has('global') && (\n <Card className=\"history-project\">\n <div className=\"history-project-head\">\n <div style={{ display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0, flex: 1 }}>\n <div className=\"history-project-name\">\n <HistoryIcon size={16} /> Global events\n </div>\n <div className=\"history-project-meta\">\n Activity not tied to a specific project\n </div>\n </div>\n </div>\n <div className=\"history-timeline-mini\">\n {(eventsByProject.get('global') || []).slice(-100).reverse().map((ev, i) => (\n <div key={i} className=\"history-timeline-row\">\n <span className=\"history-timeline-ts\">\n {new Date(ev.ts).toLocaleTimeString()}\n </span>\n <span className=\"history-timeline-kind\">{ev.kind || 'event'}</span>\n <span className=\"history-timeline-msg\" title={String(ev.text || ev.title || '')}>\n {ev.author ? `@${ev.author} ` : ''}\n {String(ev.text ?? ev.title ?? ev.name ?? '')}\n </span>\n </div>\n ))}\n </div>\n </Card>\n )}\n\n {data.stats?.counts && Object.keys(data.stats.counts).length > 0 && (\n <Card>\n <CardTitle>Event counts by kind</CardTitle>\n <CardMeta>{data.stats.lines} total lines in log</CardMeta>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 8 }}>\n {Object.entries(data.stats.counts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 30)\n .map(([kind, count]) => (\n <span\n key={kind}\n className={cn('tag', 'tag-neutral')}\n style={{ fontFamily: 'var(--font-mono)' }}\n >\n {kind}: {count}\n </span>\n ))}\n </div>\n </Card>\n )}\n </div>\n )}\n </div>\n );\n}\n","// src/web/components/UsageChart.tsx\n//\n// Hand-rolled SVG chart. No external chart library — keeps bundle small.\n//\n// Props:\n// series: { labels: string[]; requests: number[]; tokens: number[] }\n// height?: number (default 280)\n// onHover?: (index: number | null, x: number, y: number) => void\n\nimport { useCallback, useRef, useState } from 'react';\nimport { cn } from '../lib/utils';\n\ntype Props = {\n series: { labels: string[]; requests: number[]; tokens: number[] };\n height?: number;\n onHover?: (index: number | null, x: number, y: number) => void;\n className?: string;\n};\n\nconst PADDING = { top: 16, right: 20, bottom: 40, left: 52 };\n\nexport function UsageChart({ series, height = 280, onHover, className }: Props) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [tooltip, setTooltip] = useState<{ index: number; x: number; y: number } | null>(null);\n\n const { labels, requests, tokens } = series;\n const n = labels.length;\n if (n === 0) {\n return (\n <div className={cn('usage-chart-empty', className)} style={{ height }}>\n <span>No data for this range</span>\n </div>\n );\n }\n\n const innerW = 600 - PADDING.left - PADDING.right;\n const innerH = height - PADDING.top - PADDING.bottom;\n\n const maxReq = Math.max(...requests, 1);\n const maxTok = Math.max(...tokens, 1);\n // Two separate Y scales (left = requests, right = tokens)\n const barW = Math.max(4, Math.min(24, Math.floor(innerW / n) - 4));\n const gap = (innerW - barW * n) / (n + 1);\n\n function barX(i: number) {\n return PADDING.left + gap + i * (barW + gap);\n }\n\n function barH(v: number) {\n return (v / maxReq) * innerH * 0.75;\n }\n\n function lineY(v: number) {\n return PADDING.top + innerH - (v / maxTok) * innerH * 0.75;\n }\n\n // Build polyline points for the token line.\n const linePoints = tokens\n .map((v, i) => `${barX(i) + barW / 2},${lineY(v)}`)\n .join(' ');\n\n // Y-axis ticks (left, requests).\n const leftTicks = [0, 0.25, 0.5, 0.75, 1].map(t => ({\n y: PADDING.top + innerH - t * innerH * 0.75,\n label: t === 0 ? '0' : `${Math.round(maxReq * t).toLocaleString()}`,\n }));\n\n // Y-axis ticks (right, tokens).\n const rightTicks = [0, 0.25, 0.5, 0.75, 1].map(t => ({\n y: PADDING.top + innerH - t * innerH * 0.75,\n label: t === 0 ? '0' : `${Math.round(maxTok * t / 1000)}k`,\n }));\n\n // X-axis labels (show at most 7 to avoid crowding).\n const labelStep = Math.max(1, Math.floor(n / 7));\n const xLabels = labels.map((l, i) => ({ i, l, x: barX(i) + barW / 2 })).filter((_, i) => i % labelStep === 0);\n\n const handleMouseMove = useCallback(\n (e: React.MouseEvent<SVGSVGElement>) => {\n if (!containerRef.current) return;\n const rect = containerRef.current.getBoundingClientRect();\n const svgX = (e.clientX - rect.left) * (600 / rect.width);\n const svgY = (e.clientY - rect.top) * (height / rect.height);\n // Find closest bar.\n const relX = svgX - PADDING.left;\n const i = Math.round((relX - gap / 2) / (barW + gap));\n const clamped = Math.max(0, Math.min(n - 1, i));\n setTooltip({ index: clamped, x: e.clientX - rect.left, y: e.clientY - rect.top });\n onHover?.(clamped, svgX, svgY);\n },\n [n, barW, gap, onHover, height],\n );\n\n const handleMouseLeave = useCallback(() => {\n setTooltip(null);\n onHover?.(null, 0, 0);\n }, [onHover]);\n\n const tip = tooltip;\n\n return (\n <div ref={containerRef} className={cn('usage-chart', className)} style={{ position: 'relative' }}>\n <svg\n viewBox={`0 0 600 ${height}`}\n width=\"100%\"\n height={height}\n style={{ display: 'block', overflow: 'visible' }}\n onMouseMove={handleMouseMove}\n onMouseLeave={handleMouseLeave}\n >\n {/* Grid lines */}\n {leftTicks.map((tick, i) => (\n <line\n key={`grid-${i}`}\n x1={PADDING.left}\n y1={tick.y}\n x2={600 - PADDING.right}\n y2={tick.y}\n stroke=\"var(--border)\"\n strokeWidth={1}\n strokeDasharray=\"4,3\"\n opacity={0.5}\n />\n ))}\n\n {/* Left Y axis — requests */}\n {leftTicks.map((tick, i) => (\n <text\n key={`ly-${i}`}\n x={PADDING.left - 6}\n y={tick.y + 4}\n textAnchor=\"end\"\n fontSize={10}\n fill=\"var(--text-muted)\"\n fontFamily=\"var(--font-mono, ui-monospace, monospace)\"\n >\n {tick.label}\n </text>\n ))}\n\n {/* Right Y axis — tokens */}\n {rightTicks.map((tick, i) => (\n <text\n key={`ry-${i}`}\n x={600 - PADDING.right + 6}\n y={tick.y + 4}\n textAnchor=\"start\"\n fontSize={10}\n fill=\"var(--text-muted)\"\n fontFamily=\"var(--font-mono, ui-monospace, monospace)\"\n >\n {tick.label}\n </text>\n ))}\n\n {/* Bars — requests */}\n {requests.map((v, i) => {\n const bh = barH(v);\n const bx = barX(i);\n const by = PADDING.top + innerH - bh;\n return (\n <rect\n key={`bar-${i}`}\n x={bx}\n y={by}\n width={barW}\n height={bh}\n rx={2}\n fill={tip?.index === i ? 'var(--accent)' : 'var(--accent)'}\n opacity={tip?.index === i ? 1 : 0.75}\n style={{ transition: 'opacity 120ms ease' }}\n />\n );\n })}\n\n {/* Token line */}\n <polyline\n points={linePoints}\n fill=\"none\"\n stroke=\"var(--warning, #d29922)\"\n strokeWidth={2}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n opacity={0.9}\n />\n\n {/* Token dots */}\n {tokens.map((v, i) => (\n <circle\n key={`dot-${i}`}\n cx={barX(i) + barW / 2}\n cy={lineY(v)}\n r={tip?.index === i ? 5 : 3}\n fill=\"var(--warning, #d29922)\"\n opacity={tip?.index === i ? 1 : 0.7}\n style={{ transition: 'r 120ms ease' }}\n />\n ))}\n\n {/* X axis labels */}\n {xLabels.map(({ i, l, x }) => (\n <text\n key={`xl-${i}`}\n x={x}\n y={PADDING.top + innerH + 18}\n textAnchor=\"middle\"\n fontSize={10}\n fill=\"var(--text-muted)\"\n fontFamily=\"var(--font-mono, ui-monospace, monospace)\"\n >\n {l}\n </text>\n ))}\n\n {/* X axis line */}\n <line\n x1={PADDING.left}\n y1={PADDING.top + innerH}\n x2={600 - PADDING.right}\n y2={PADDING.top + innerH}\n stroke=\"var(--border)\"\n strokeWidth={1}\n />\n </svg>\n\n {/* Floating tooltip */}\n {tip !== null && (\n <div\n className=\"usage-chart-tooltip\"\n style={{\n left: Math.min(tip.x + 12, 600 - 140),\n top: tip.y - 60,\n }}\n >\n <div className=\"usage-tooltip-date\">{labels[tip.index]}</div>\n <div className=\"usage-tooltip-row\">\n <span className=\"usage-tooltip-dot\" style={{ background: 'var(--accent)' }} />\n <span>Requests:</span>\n <strong>{requests[tip.index].toLocaleString()}</strong>\n </div>\n <div className=\"usage-tooltip-row\">\n <span className=\"usage-tooltip-dot\" style={{ background: 'var(--warning, #d29922)' }} />\n <span>Tokens:</span>\n <strong>{tokens[tip.index].toLocaleString()}</strong>\n </div>\n </div>\n )}\n </div>\n );\n}\n","// src/web/components/UsageTable.tsx\n//\n// Sortable compact table for per-model usage breakdown.\n//\n// Props:\n// rows: PerModelRow[]\n// sortKey: string\n// sortDir: 'asc' | 'desc'\n// onSort: (key: string) => void\n\nimport { cn } from '../lib/utils';\n\nexport type PerModelRow = {\n providerId: string;\n modelId: string;\n requests: number;\n totalTokens: number;\n promptTokens: number;\n completionTokens: number;\n errors: number;\n avgLatencyMs: number;\n};\n\ntype Props = {\n rows: PerModelRow[];\n sortKey: string;\n sortDir: 'asc' | 'desc';\n onSort: (key: string) => void;\n};\n\nfunction SortHeader({ label, col, sortKey, sortDir, onSort }: {\n label: string; col: string; sortKey: string; sortDir: 'asc' | 'desc'; onSort: (k: string) => void;\n}) {\n const active = sortKey === col;\n return (\n <th\n className={cn('usage-sort-header', active && 'is-active')}\n onClick={() => onSort(col)}\n aria-sort={active ? (sortDir === 'asc' ? 'ascending' : 'descending') : 'none'}\n >\n <span>{label}</span>\n <span className=\"usage-sort-icon\">\n {active ? (sortDir === 'asc' ? ' ↑' : ' ↓') : ' ↕'}\n </span>\n </th>\n );\n}\n\nexport function UsageTable({ rows, sortKey, sortDir, onSort }: Props) {\n return (\n <div className=\"usage-table-wrap\">\n <table className=\"usage-table\">\n <thead>\n <tr>\n <SortHeader label=\"Model\" col=\"modelId\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Requests\" col=\"requests\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Prompt Tok\" col=\"promptTokens\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Compl Tok\" col=\"completionTokens\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Total Tok\" col=\"totalTokens\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Avg Latency\" col=\"avgLatencyMs\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n <SortHeader label=\"Errors\" col=\"errors\" sortKey={sortKey} sortDir={sortDir} onSort={onSort} />\n </tr>\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr>\n <td colSpan={7} className=\"usage-table-empty\">No data for this range</td>\n </tr>\n ) : (\n rows.map((row) => (\n <tr key={`${row.providerId}::${row.modelId}`}>\n <td className=\"usage-table-model\">\n <code>{row.modelId}</code>\n </td>\n <td className=\"mono\">{row.requests.toLocaleString()}</td>\n <td className=\"mono\">{row.promptTokens.toLocaleString()}</td>\n <td className=\"mono\">{row.completionTokens.toLocaleString()}</td>\n <td className=\"mono\">{row.totalTokens.toLocaleString()}</td>\n <td className=\"mono\">{row.avgLatencyMs}ms</td>\n <td className={cn('mono', row.errors > 0 && 'is-err')}>\n {row.errors > 0 ? row.errors : '—'}\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n );\n}\n","// src/views/MiniMaxUsage.tsx — v4.6.0\n//\n// Full rewrite with two tabs:\n// 1. Token Plan — existing 5h + weekly remaining quota (unchanged)\n// 2. Usage Analytics — charts, KPIs, per-model breakdown, per-key status\n//\n// The usage data comes from the JSONL store at ~/.local/share/bizar/usage.jsonl\n// (written by minimax.mjs after every chatCompletion / fetchRemains call).\n// The Usage Analytics tab is only shown when the key is configured.\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n Coins,\n RefreshCw,\n AlertTriangle,\n CheckCircle2,\n KeyRound,\n Send,\n Loader2,\n Calendar,\n Activity,\n Save,\n Eye,\n EyeOff,\n Sparkles,\n X,\n ExternalLink,\n ShieldCheck,\n CircleCheck,\n BarChart2,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Spinner } from '../components/Spinner';\nimport { UsageChart } from '../components/UsageChart';\nimport { UsageTable, type PerModelRow } from '../components/UsageTable';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\ntype Props = {\n snapshot: unknown;\n settings: unknown;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\ntype RemainsModel = {\n model_name: string;\n current_interval_remaining_percent: number;\n current_weekly_remaining_percent: number;\n current_interval_consumed_percent?: number;\n weekly_consumed_percent?: number;\n current_interval_status: number;\n current_weekly_status: number;\n current_interval_total_count: number;\n current_interval_usage_count: number;\n current_weekly_total_count: number;\n current_weekly_usage_count: number;\n endTimeISO?: string;\n weeklyEndTimeISO?: string;\n intervalResetInMs?: number;\n weeklyResetInMs?: number;\n intervalResetInHuman?: string;\n weeklyResetInHuman?: string;\n intervalUsed?: number;\n intervalTotal?: number;\n weeklyUsed?: number;\n weeklyTotal?: number;\n};\n\ntype RemainsSnapshot = {\n ok: boolean;\n cached?: boolean;\n fetchedAt?: number;\n apiKeyHint?: string;\n keySource?: string;\n groupId?: string;\n baseUrl?: string;\n models?: RemainsModel[];\n baseResp?: { status_code: number; status_msg: string };\n error?: string;\n message?: string;\n};\n\ntype Status = {\n configured: boolean;\n apiKeyHint: string;\n source: string;\n groupId: string;\n tokenBaseUrl: string;\n chatBaseUrl: string;\n knownModels: string[];\n keyPatternValid: boolean | null;\n cache: { fetchedAt: number; apiKeyHint: string; modelCount: number } | null;\n};\n\ntype OnboardingState = {\n dismissedAt: number | null;\n hiddenModels: string[];\n};\n\ntype TestResult = {\n ok: boolean;\n error?: string;\n message?: string;\n model?: string;\n content?: string;\n reasoning?: string;\n finishReason?: string;\n usage?: {\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n };\n status?: number;\n raw?: unknown;\n};\n\n// Usage analytics types.\ntype UsageTotals = {\n requests: number;\n errors: number;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n cachedTokens: number;\n reasoningTokens: number;\n avgLatencyMs: number;\n p95LatencyMs: number;\n costEstimate: number;\n};\n\ntype DailyBucket = {\n date: string;\n requests: number;\n totalTokens: number;\n promptTokens: number;\n completionTokens: number;\n errors: number;\n avgLatencyMs: number;\n};\n\ntype PerModelBucket = {\n providerId: string;\n modelId: string;\n requests: number;\n totalTokens: number;\n promptTokens: number;\n completionTokens: number;\n errors: number;\n avgLatencyMs: number;\n};\n\ntype PerKeyBucket = {\n keyEnvVar: string;\n isBackup: boolean;\n requests: number;\n errors: number;\n lastUsed: number | null;\n status: 'active' | 'backup';\n};\n\ntype UsageQueryResult = {\n totals: UsageTotals;\n daily: DailyBucket[];\n perModel: PerModelBucket[];\n perKey: PerKeyBucket[];\n errors: { code: string; message: string; count: number; lastOccurred: number | null }[];\n};\n\ntype RecentRecord = {\n ts: number;\n providerId: string;\n modelId: string;\n endpoint: string;\n requestId: string;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n cachedTokens: number;\n reasoningTokens: number;\n latencyMs: number;\n finishReason: string | null;\n error: { code: string; message: string } | null;\n keyEnvVar: string;\n isBackup: boolean;\n cached: boolean;\n};\n\ntype TimeRange = '24h' | '7d' | '30d' | 'custom';\n\n// ─── Main component ────────────────────────────────────────────────────\n\nfunction MiniMaxUsageInner({ activeTab, setActiveTab }: Props) {\n // Share state between tabs.\n const [view, setView] = useState<'quota' | 'analytics'>('quota');\n const toast = useToast();\n\n // Load based on active view.\n return (\n <div className=\"view-container view-minimax-usage\">\n {/* Sub-tab switcher */}\n <div className=\"minimax-sub-tabs\">\n <button\n className={cn('minimax-sub-tab', view === 'quota' && 'is-active')}\n onClick={() => setView('quota')}\n >\n <Coins size={13} /> Token Plan\n </button>\n <button\n className={cn('minimax-sub-tab', view === 'analytics' && 'is-active')}\n onClick={() => setView('analytics')}\n >\n <BarChart2 size={13} /> Usage Analytics\n </button>\n </div>\n\n {view === 'quota'\n ? <QuotaView activeTab={activeTab} setActiveTab={setActiveTab} />\n : <AnalyticsView toast={toast} />\n }\n </div>\n );\n}\n\n// ─── Token Plan view (existing functionality) ──────────────────────────\n\nfunction QuotaView({ activeTab, setActiveTab }: Pick<Props, 'activeTab' | 'setActiveTab'>) {\n const toast = useToast();\n const [status, setStatus] = useState<Status | null>(null);\n const [remains, setRemains] = useState<RemainsSnapshot | null>(null);\n const [onboarding, setOnboarding] = useState<OnboardingState | null>(null);\n const [loading, setLoading] = useState(true);\n const [refreshing, setRefreshing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [testResult, setTestResult] = useState<TestResult | null>(null);\n const [testing, setTesting] = useState(false);\n const [wizardStep, setWizardStep] = useState(0);\n const [wizardVerifying, setWizardVerifying] = useState(false);\n const [wizardVerifyResult, setWizardVerifyResult] = useState<TestResult | null>(null);\n const [keyDraft, setKeyDraft] = useState('');\n const [showKey, setShowKey] = useState(false);\n const [savingKey, setSavingKey] = useState(false);\n\n const load = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [s, r, o] = await Promise.all([\n api.get<Status>('/minimax/status'),\n api.get<RemainsSnapshot>('/minimax/remains'),\n api.get<OnboardingState>('/minimax/onboarding'),\n ]);\n setStatus(s);\n setRemains(r);\n setOnboarding(o);\n if (s.configured) setWizardStep(4);\n } catch (err) {\n setError((err as Error).message || 'Failed to load MiniMax data');\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => { load(); }, [load]);\n\n const dismissWizard = useCallback(async () => {\n try {\n await api.post('/minimax/onboarding', { dismissedAt: Date.now() });\n setOnboarding((o) => o ? { ...o, dismissedAt: Date.now() } : o);\n } catch { /* best-effort */ }\n }, []);\n\n const verifyKeyBeforeSave = useCallback(async () => {\n if (!keyDraft.trim()) { toast.error('Paste a Subscription Key first.'); return; }\n setWizardVerifying(true);\n setWizardVerifyResult(null);\n try {\n const r = await api.post<TestResult>('/minimax/test', {\n prompt: 'Reply with a single word: pong',\n model: 'MiniMax-M3',\n maxTokens: 16,\n });\n setWizardVerifyResult(r);\n if (r.ok) {\n setWizardStep(3);\n toast.success('Key works. Saving…');\n try {\n await api.post('/minimax/onboarding/save-key', { key: keyDraft.trim(), groupId: 'default' });\n clearRemainsCacheClient();\n toast.success('Subscription Key saved.');\n } catch (err) { toast.error(`Save failed: ${(err as Error).message}`); }\n void load();\n } else {\n toast.error(`Verification failed: ${r.message ?? r.error ?? 'unknown'}`);\n }\n } catch (err) { toast.error(`Test request failed: ${(err as Error).message}`); }\n finally { setWizardVerifying(false); }\n }, [keyDraft, toast, load]);\n\n const saveKey = useCallback(async () => {\n if (!keyDraft.trim()) { toast.error('Paste a Subscription Key first.'); return; }\n setSavingKey(true);\n try {\n const r = await api.post<{ ok: boolean; path?: string; apiKeyHint?: string; error?: string; message?: string }>(\n '/minimax/onboarding/save-key', { key: keyDraft.trim(), groupId: 'default' },\n );\n if (!r.ok) { toast.error(`Save failed: ${r.message ?? r.error ?? 'unknown'}`); return; }\n setKeyDraft('');\n clearRemainsCacheClient();\n toast.success('Subscription Key saved. Loading quota…');\n void load();\n } catch (err) { toast.error(`Save failed: ${(err as Error).message}`); }\n finally { setSavingKey(false); }\n }, [keyDraft, toast, load]);\n\n const clearRemainsCacheClient = useCallback(async () => {\n try { await api.del('/minimax/cache'); } catch { /* best-effort */ }\n }, []);\n\n const refresh = useCallback(async () => {\n setRefreshing(true);\n setError(null);\n try {\n await api.post('/minimax/remains/refresh');\n await load();\n toast.success('Refreshed');\n } catch (err) { toast.error(`Refresh failed: ${(err as Error).message}`); }\n finally { setRefreshing(false); }\n }, [load, toast]);\n\n const sendTest = useCallback(async () => {\n setTesting(true);\n setTestResult(null);\n try {\n const r = await api.post<TestResult>('/minimax/test', {\n prompt: 'Reply with a single word: pong',\n model: 'MiniMax-M3',\n maxTokens: 16,\n });\n setTestResult(r);\n if (r.ok) toast.success(`Test ok — used ${r.usage?.total_tokens ?? '?'} tokens`);\n else toast.error(`Test failed: ${r.message ?? r.error ?? 'unknown'}`);\n } catch (err) { toast.error(`Test request failed: ${(err as Error).message}`); }\n finally { setTesting(false); }\n }, [toast]);\n\n if (loading && !status) {\n return <div className=\"view-container\"><Spinner /> Loading MiniMax data…</div>;\n }\n if (!status) {\n return (\n <div className=\"view-container\">\n <div className=\"error-card\">\n <AlertTriangle size={20} />\n <div><strong>Couldn't load MiniMax status</strong><pre>{error ?? 'unknown error'}</pre></div>\n </div>\n </div>\n );\n }\n\n const showWizard = !status.configured && (onboarding?.dismissedAt == null) && wizardStep < 4;\n if (showWizard) {\n return <OnboardingWizard\n step={wizardStep} setStep={setWizardStep}\n keyDraft={keyDraft} setKeyDraft={setKeyDraft}\n showKey={showKey} setShowKey={setShowKey}\n verifying={wizardVerifying} verifyResult={wizardVerifyResult}\n onVerify={verifyKeyBeforeSave}\n onSkip={async () => { await dismissWizard(); toast.success(\"Skipped.\"); }}\n onManualKeySave={saveKey} savingKey={savingKey} status={status}\n />;\n }\n\n return (\n <>\n <header className=\"view-header\">\n <div className=\"view-header-titles\">\n <h1 className=\"view-title\">\n <Coins size={20} style={{ verticalAlign: 'text-bottom', marginRight: 6 }} />\n MiniMax Token Plan\n </h1>\n <p className=\"view-subtitle\">\n Remaining 5-hour + weekly quota per model. Fetches live from{' '}\n <code>www.minimax.io/v1/token_plan/remains</code>.\n </p>\n </div>\n <div className=\"view-header-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setActiveTab('settings')} title=\"Configure your Subscription Key\">\n <KeyRound size={14} /> {status.configured ? `Key ${status.apiKeyHint}` : 'Add key'}\n </Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={refresh} disabled={refreshing}>\n {refreshing ? <Loader2 size={14} className=\"spin\" /> : <RefreshCw size={14} />} Refresh\n </Button>\n </div>\n </header>\n\n {remains && !remains.ok && (\n <div className=\"banner banner-err\">\n <AlertTriangle size={16} />\n <span><strong>Couldn't load quota</strong>: {remains.message ?? remains.error ?? 'unknown error'}</span>\n </div>\n )}\n\n {remains?.ok && remains.models && (\n <>\n <div className=\"minimax-stats-row\">\n <Stat label=\"Models tracked\" value={String(remains.models.length)} hint=\"Distinct model quotas returned by the API\" />\n <Stat label=\"Last fetched\" value={remains.fetchedAt ? relativeTime(remains.fetchedAt) : '—'} hint=\"Refreshed on demand + every 60s\" />\n <Stat label=\"Group\" value={remains.groupId ?? '—'} hint=\"Usually 'default' for an individual team\" />\n <Stat label=\"API key\" value={remains.apiKeyHint ?? '—'} hint=\"Masked; the real key never leaves auth.json\" />\n </div>\n <div className=\"minimax-models-grid\">\n {remains.models.map((m) => <ModelQuotaCard key={m.model_name} model={m} />)}\n </div>\n </>\n )}\n\n {status.configured && (\n <Card id=\"minimax-test\">\n <CardTitle><Send size={14} /> Test the API key</CardTitle>\n <CardMeta>One-shot chat completion to <code>{status.chatBaseUrl}/chat/completions</code>.</CardMeta>\n <div className=\"minimax-test-actions\">\n <Button onClick={sendTest} disabled={testing} variant=\"primary\" size=\"sm\">\n {testing ? <Loader2 size={14} className=\"spin\" /> : <Send size={14} />} Send test prompt\n </Button>\n <code className=\"minimax-test-prompt\">\"Reply with a single word: pong\"</code>\n </div>\n {testResult && (\n <div className={cn('minimax-test-result', testResult.ok ? 'ok' : 'err')}>\n {testResult.ok ? <CheckCircle2 size={14} /> : <AlertTriangle size={14} />}\n <div className=\"minimax-test-body\">\n {testResult.ok ? (\n <>\n <div className=\"minimax-test-line\">\n <strong>model:</strong> <code>{testResult.model}</code> ·{' '}\n <strong>finish:</strong> {testResult.finishReason ?? '—'}\n </div>\n {testResult.content && (\n <div className=\"minimax-test-content\"><code>{testResult.content}</code></div>\n )}\n {testResult.usage && (\n <div className=\"minimax-test-usage\">\n <strong>usage:</strong> total <code>{testResult.usage.total_tokens ?? '?'}</code> · prompt{' '}\n <code>{testResult.usage.prompt_tokens ?? '?'}</code> · completion{' '}\n <code>{testResult.usage.completion_tokens ?? '?'}</code>\n {testResult.usage.prompt_tokens_details?.cached_tokens != null && (\n <> · cached <code>{testResult.usage.prompt_tokens_details.cached_tokens}</code></>\n )}\n </div>\n )}\n </>\n ) : (\n <pre>{testResult.message ?? testResult.error ?? 'unknown error'}</pre>\n )}\n </div>\n </div>\n )}\n </Card>\n )}\n </>\n );\n}\n\n// ─── Analytics view ────────────────────────────────────────────────────\n\nfunction AnalyticsView({ toast }: { toast: ReturnType<typeof useToast> }) {\n const [range, setRange] = useState<TimeRange>('24h');\n const [customFrom, setCustomFrom] = useState('');\n const [customTo, setCustomTo] = useState('');\n const [loading, setLoading] = useState(true);\n const [usage, setUsage] = useState<UsageQueryResult | null>(null);\n const [recent, setRecent] = useState<RecentRecord[]>([]);\n const [sortKey, setSortKey] = useState('requests');\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc');\n const [refreshing, setRefreshing] = useState(false);\n\n const load = useCallback(async (r: TimeRange, fromMs?: number, toMs?: number) => {\n setLoading(true);\n try {\n const params = new URLSearchParams({ range: r });\n if (r === 'custom' && fromMs && toMs) {\n params.set('from', String(fromMs));\n params.set('to', String(toMs));\n }\n const [u, rec] = await Promise.all([\n api.get<UsageQueryResult>(`/usage?${params.toString()}`),\n api.get<{ records: RecentRecord[]; total: number; returned: number }>('/usage/recent?limit=20'),\n ]);\n setUsage(u);\n setRecent(rec.records);\n } catch (err) {\n toast.error(`Failed to load usage data: ${(err as Error).message}`);\n } finally {\n setLoading(false);\n }\n }, [toast]);\n\n useEffect(() => {\n if (range === 'custom') {\n const from = customFrom ? new Date(customFrom).getTime() : Date.now() - 7 * 86_400_000;\n const to = customTo ? new Date(customTo).getTime() : Date.now();\n void load('custom', from, to);\n } else {\n void load(range);\n }\n }, [range, load]);\n\n const handleSort = useCallback((key: string) => {\n if (sortKey === key) setSortDir(d => d === 'asc' ? 'desc' : 'asc');\n else { setSortKey(key); setSortDir('desc'); }\n }, [sortKey]);\n\n const sortedModels = useMemo(() => {\n if (!usage?.perModel) return [];\n return [...usage.perModel].sort((a, b) => {\n const av = (a as Record<string, unknown>)[sortKey] ?? 0;\n const bv = (b as Record<string, unknown>)[sortKey] ?? 0;\n const cmp = typeof av === 'number' && typeof bv === 'number' ? av - bv : String(av).localeCompare(String(bv));\n return sortDir === 'asc' ? cmp : -cmp;\n });\n }, [usage?.perModel, sortKey, sortDir]);\n\n const chartSeries = useMemo(() => {\n if (!usage?.daily) return { labels: [] as string[], requests: [] as number[], tokens: [] as number[] };\n return {\n labels: usage.daily.map(d => d.date.slice(5)), // \"MM-DD\"\n requests: usage.daily.map(d => d.requests),\n tokens: usage.daily.map(d => d.totalTokens),\n };\n }, [usage?.daily]);\n\n const refresh = useCallback(async () => {\n setRefreshing(true);\n await load(range === 'custom' ? 'custom' : range,\n range === 'custom' && customFrom ? new Date(customFrom).getTime() : undefined,\n range === 'custom' && customTo ? new Date(customTo).getTime() : undefined);\n setRefreshing(false);\n }, [load, range, customFrom, customTo]);\n\n if (loading && !usage) {\n return <div className=\"view-container\"><Spinner /> Loading usage data…</div>;\n }\n\n const t = usage?.totals;\n const errors = usage?.errors ?? [];\n const perKey = usage?.perKey ?? [];\n\n return (\n <>\n {/* Header */}\n <header className=\"view-header\">\n <div className=\"view-header-titles\">\n <h1 className=\"view-title\">\n <BarChart2 size={20} style={{ verticalAlign: 'text-bottom', marginRight: 6 }} />\n Usage Analytics\n </h1>\n <p className=\"view-subtitle\">\n Aggregated from <code>~/.local/share/bizar/usage.jsonl</code> —\n every chatCompletion and fetchRemains call.\n </p>\n </div>\n <div className=\"view-header-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={refresh} disabled={refreshing}>\n {refreshing ? <Loader2 size={14} className=\"spin\" /> : <RefreshCw size={14} />} Refresh\n </Button>\n </div>\n </header>\n\n {/* Time range selector */}\n <div className=\"usage-time-range\">\n {(['24h', '7d', '30d', 'custom'] as TimeRange[]).map(r => (\n <button\n key={r}\n className={cn('usage-range-chip', range === r && 'is-active')}\n onClick={() => setRange(r)}\n >\n {r === 'custom' ? 'Custom' : r.toUpperCase()}\n </button>\n ))}\n {range === 'custom' && (\n <div className=\"usage-custom-dates\">\n <label htmlFor=\"usage-from-date\" className=\"sr-only\">From date</label>\n <input\n id=\"usage-from-date\"\n type=\"date\"\n className=\"usage-date-input\"\n value={customFrom}\n onChange={e => setCustomFrom(e.target.value)}\n aria-label=\"From date\"\n />\n <span style={{ color: 'var(--text-muted)', fontSize: 12 }} aria-hidden>to</span>\n <label htmlFor=\"usage-to-date\" className=\"sr-only\">To date</label>\n <input\n id=\"usage-to-date\"\n type=\"date\"\n className=\"usage-date-input\"\n value={customTo}\n onChange={e => setCustomTo(e.target.value)}\n aria-label=\"To date\"\n />\n </div>\n )}\n </div>\n\n {/* KPI row */}\n <div className=\"usage-kpi-row\">\n <KpiCard\n label=\"Total Requests\"\n value={t?.requests.toLocaleString() ?? '—'}\n sub={t ? `${t.errors} errors` : undefined}\n tone={t && t.errors > t.requests * 0.1 ? 'warn' : undefined}\n />\n <KpiCard\n label=\"Total Tokens\"\n value={t ? (t.totalTokens >= 1000 ? `${Math.round(t.totalTokens / 1000)}k` : String(t.totalTokens)) : '—'}\n sub={t ? `${t.promptTokens.toLocaleString()} prompt · ${t.completionTokens.toLocaleString()} completion` : undefined}\n />\n <KpiCard\n label=\"Errors\"\n value={String(t?.errors ?? '—')}\n sub={errors.length > 0 ? `${errors[0].code}: ${errors[0].count}` : undefined}\n tone={t && t.errors > 0 ? 'err' : undefined}\n />\n <KpiCard\n label=\"Avg Latency\"\n value={t?.avgLatencyMs != null ? `${t.avgLatencyMs}ms` : '—'}\n sub={t?.p95LatencyMs != null ? `p95 ${t.p95LatencyMs}ms` : undefined}\n />\n <KpiCard\n label=\"Est. Cost\"\n value={t?.costEstimate != null && t.costEstimate > 0 ? `$${t.costEstimate.toFixed(4)}` : '—'}\n sub=\"approximate USD\"\n tone={undefined}\n />\n </div>\n\n {/* Chart */}\n <Card className=\"usage-chart-card\">\n <div className=\"usage-chart-wrap\">\n <UsageChart series={chartSeries} height={280} />\n </div>\n <div className=\"usage-legend\">\n <div className=\"usage-legend-item\">\n <div className=\"usage-legend-bar\" style={{ background: 'var(--accent)' }} />\n <span>Requests (bar)</span>\n </div>\n <div className=\"usage-legend-item\">\n <div className=\"usage-legend-line\" style={{ background: 'var(--warning, #d29922)' }} />\n <span>Tokens (line)</span>\n </div>\n </div>\n </Card>\n\n {/* Per-model table */}\n <Card>\n <CardTitle>Per-model breakdown</CardTitle>\n <UsageTable\n rows={sortedModels as PerModelRow[]}\n sortKey={sortKey}\n sortDir={sortDir}\n onSort={handleSort}\n />\n </Card>\n\n {/* Per-key status */}\n {perKey.length > 0 && (\n <Card>\n <CardTitle>API Keys</CardTitle>\n <div className=\"usage-key-row\">\n {perKey.map(k => (\n <span\n key={k.keyEnvVar}\n className={cn('usage-key-badge', k.isBackup ? 'is-backup' : 'is-active')}\n >\n <span className=\"usage-key-dot\" />\n {k.keyEnvVar}\n {k.isBackup ? ' (backup)' : ' (active)'}\n {' · '}\n {k.requests} req\n </span>\n ))}\n </div>\n </Card>\n )}\n\n {/* Recent activity */}\n {recent.length > 0 && (\n <Card>\n <CardTitle>Recent activity</CardTitle>\n <div className=\"usage-recent-list\">\n {recent.map((r, i) => (\n <div key={`${r.requestId}-${i}`} className={cn('usage-recent-item', r.error && 'is-err')}>\n <span className=\"usage-recent-time\">\n {new Date(r.ts).toLocaleTimeString()}\n </span>\n <span className=\"usage-recent-model\">\n <code>{r.modelId}</code>\n </span>\n <span className=\"usage-recent-tokens\">\n {r.totalTokens.toLocaleString()} tok\n </span>\n <span className=\"usage-recent-latency\">\n {r.latencyMs}ms\n </span>\n <span className=\"usage-recent-endpoint\">{r.endpoint}</span>\n </div>\n ))}\n </div>\n </Card>\n )}\n </>\n );\n}\n\n// ─── Kpi card ──────────────────────────────────────────────────────────\n\nfunction KpiCard({ label, value, sub, tone }: { label: string; value: string; sub?: string; tone?: 'warn' | 'err' | 'ok' }) {\n return (\n <div className=\"usage-kpi-card\">\n <div className=\"usage-kpi-label\">{label}</div>\n <div className={cn('usage-kpi-value', tone && `is-${tone}`)}>{value}</div>\n {sub && <div className=\"usage-kpi-sub\">{sub}</div>}\n </div>\n );\n}\n\n// ─── Sub-components (quota view) ───────────────────────────────────────\n\nfunction Stat({ label, value, hint }: { label: string; value: string; hint?: string }) {\n return (\n <div className=\"stat\">\n <div className=\"stat-label\">{label}</div>\n <div className=\"stat-value\">{value}</div>\n {hint && <div className=\"stat-hint\">{hint}</div>}\n </div>\n );\n}\n\nfunction ModelQuotaCard({ model }: { model: RemainsModel }) {\n const fivePct = clamp(model.current_interval_remaining_percent ?? 0, 0, 100);\n const weekPct = clamp(model.current_weekly_remaining_percent ?? 0, 0, 100);\n const fiveConsumed = clamp(100 - fivePct, 0, 100);\n const weekConsumed = clamp(100 - weekPct, 0, 100);\n return (\n <Card id={`minimax-model-${model.model_name}`} className=\"minimax-model-card\">\n <div className=\"minimax-model-head\">\n <div className=\"minimax-model-name\">{model.model_name}</div>\n <div className={cn('minimax-model-status', fivePct < 25 || weekPct < 25 ? 'is-warn' : 'is-ok')}>\n {model.current_interval_status === 1 ? 'active' : 'idle'} ·{' '}\n {model.current_weekly_status === 1 ? 'week active' : 'week idle'}\n </div>\n </div>\n <div className=\"minimax-quota-rows\">\n <QuotaBar\n icon={<Activity size={12} />} label=\"5-hour rolling\"\n remainingPct={fivePct} consumedPct={fiveConsumed}\n used={model.current_interval_usage_count ?? 0} total={model.current_interval_total_count ?? 0}\n resetIn={model.intervalResetInHuman} resetISO={model.endTimeISO}\n />\n <QuotaBar\n icon={<Calendar size={12} />} label=\"Weekly\"\n remainingPct={weekPct} consumedPct={weekConsumed}\n used={model.current_weekly_usage_count ?? 0} total={model.current_weekly_total_count ?? 0}\n resetIn={model.weeklyResetInHuman} resetISO={model.weeklyEndTimeISO}\n />\n </div>\n </Card>\n );\n}\n\nfunction QuotaBar({ icon, label, remainingPct, consumedPct, used, total, resetIn, resetISO }: {\n icon: React.ReactNode; label: string; remainingPct: number; consumedPct: number;\n used: number; total: number; resetIn?: string; resetISO?: string;\n}) {\n const tone = remainingPct >= 75 ? 'good' : remainingPct >= 25 ? 'warn' : 'low';\n return (\n <div className={`minimax-quota-row is-${tone}`}>\n <div className=\"minimax-quota-head\">\n <span className=\"minimax-quota-label\">{icon} {label}</span>\n <span className=\"minimax-quota-remaining\">{remainingPct}% remaining</span>\n <span className=\"minimax-quota-consumed\">· {consumedPct}% used</span>\n </div>\n <div className=\"minimax-bar\">\n <div className=\"minimax-bar-fill\" style={{ width: `${consumedPct}%` }} aria-label={`${consumedPct}% consumed`} />\n </div>\n <div className=\"minimax-quota-meta\">\n <span><strong>{used}</strong> / {total || '—'} requests</span>\n <span title={resetISO}>{resetIn ? `resets in ${resetIn}` : '—'}</span>\n </div>\n </div>\n );\n}\n\nfunction clamp(n: number, lo: number, hi: number) {\n return Math.max(lo, Math.min(hi, n));\n}\n\nfunction relativeTime(ts: number): string {\n const ms = Date.now() - ts;\n if (ms < 5_000) return 'just now';\n if (ms < 60_000) return `${Math.floor(ms / 1000)}s ago`;\n if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m ago`;\n return `${Math.floor(ms / 3_600_000)}h ago`;\n}\n\n// ─── Onboarding wizard ─────────────────────────────────────────────────\n\ntype OnboardingProps = {\n step: number; setStep: (n: number) => void;\n keyDraft: string; setKeyDraft: (s: string) => void;\n showKey: boolean; setShowKey: React.Dispatch<React.SetStateAction<boolean>>;\n verifying: boolean; verifyResult: TestResult | null;\n onVerify: () => void; onSkip: () => void; onManualKeySave: () => void;\n savingKey: boolean; status: Status;\n};\n\nfunction OnboardingWizard({ step, setStep, keyDraft, setKeyDraft, showKey, setShowKey, verifying, verifyResult, onVerify, onSkip, onManualKeySave, savingKey, status }: OnboardingProps) {\n return (\n <div className=\"view-container view-minimax-onboarding\">\n <header className=\"view-header\">\n <div className=\"view-header-titles\">\n <h1 className=\"view-title\">\n <Sparkles size={20} style={{ verticalAlign: 'text-bottom', marginRight: 6 }} />\n Set up MiniMax Token Plan tracking\n </h1>\n <p className=\"view-subtitle\">We'll read your Subscription Key and show your remaining quota.</p>\n </div>\n <div className=\"view-header-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onSkip}><X size={14} /> Skip for now</Button>\n </div>\n </header>\n\n <div className=\"minimax-wizard-stepper\">\n {(['Welcome', 'Get a key', 'Paste & test', 'Done']).map((label, i) => (\n <div key={label} className={cn('minimax-wizard-step', i === step && 'is-current', i < step && 'is-done', i > step && 'is-todo')}>\n <div className=\"minimax-wizard-step-bullet\">{i < step ? <CircleCheck size={14} /> : i + 1}</div>\n <div className=\"minimax-wizard-step-label\">{label}</div>\n </div>\n ))}\n </div>\n\n <Card id=\"minimax-wizard-card\">\n {step === 0 && (\n <div className=\"minimax-wizard-body\">\n <h3 className=\"minimax-wizard-title\">Welcome</h3>\n <p className=\"minimax-wizard-prose\">\n BizarHarness shows you how much of your MiniMax Token Plan quota you have left —\n both the <strong>5-hour rolling</strong> and <strong>weekly</strong> windows.\n </p>\n <ul className=\"minimax-wizard-list\">\n <li>Stored in <code>~/.local/share/opencode/auth.json</code>.</li>\n <li>Read fresh on every dashboard load.</li>\n <li>Never logged in full.</li>\n </ul>\n <div className=\"minimax-wizard-actions\">\n <Button onClick={() => setStep(1)} variant=\"primary\" size=\"md\">Get started <span style={{ marginLeft: 6 }}>→</span></Button>\n </div>\n </div>\n )}\n\n {step === 1 && (\n <div className=\"minimax-wizard-body\">\n <h3 className=\"minimax-wizard-title\">Get your Subscription Key</h3>\n <p className=\"minimax-wizard-prose\">Go to the MiniMax console and copy your Subscription Key.</p>\n <ol className=\"minimax-wizard-list\">\n <li>Open <a href=\"https://platform.minimax.io/user-center/payment/token-plan\" target=\"_blank\" rel=\"noreferrer\" className=\"minimax-wizard-link\"><ExternalLink size={12} /> platform.minimax.io</a></li>\n <li>Click <strong>Copy Subscription Key</strong>.</li>\n <li>Come back here and paste it.</li>\n </ol>\n <div className=\"minimax-wizard-actions\">\n <Button variant=\"secondary\" size=\"md\" onClick={() => setStep(0)}>← Back</Button>\n <Button variant=\"primary\" size=\"md\" onClick={() => setStep(2)}>I have my key <span style={{ marginLeft: 6 }}>→</span></Button>\n </div>\n </div>\n )}\n\n {step === 2 && (\n <div className=\"minimax-wizard-body\">\n <h3 className=\"minimax-wizard-title\">Paste & test</h3>\n <p className=\"minimax-wizard-prose\">Paste your key below. We'll test it against the real API before saving.</p>\n <div className=\"minimax-key-row\">\n <div className=\"minimax-key-input-wrap\">\n <KeyRound size={12} className=\"minimax-key-icon\" aria-hidden />\n <label htmlFor=\"minimax-key-input\" className=\"sr-only\">Subscription Key</label>\n <input\n id=\"minimax-key-input\"\n type={showKey ? 'text' : 'password'}\n value={keyDraft}\n onChange={e => setKeyDraft(e.target.value)}\n placeholder=\"sk-cp-...\"\n spellCheck={false}\n autoComplete=\"off\"\n className=\"minimax-key-input\"\n autoFocus\n aria-label=\"Subscription Key\"\n />\n <button type=\"button\" onClick={() => setShowKey(v => !v)} className=\"minimax-key-toggle\" aria-label={showKey ? 'Hide key' : 'Show key'}>\n {showKey ? <EyeOff size={13} /> : <Eye size={13} />}\n </button>\n </div>\n </div>\n {verifyResult && !verifyResult.ok && (\n <div className=\"minimax-wizard-error\"><AlertTriangle size={14} /><span><strong>Verification failed:</strong> {verifyResult.message ?? verifyResult.error}</span></div>\n )}\n <div className=\"minimax-wizard-actions\">\n <Button variant=\"secondary\" size=\"md\" onClick={() => setStep(1)}>← Back</Button>\n <Button variant=\"primary\" size=\"md\" onClick={onVerify} disabled={verifying || !keyDraft.trim()}>\n {verifying ? <Loader2 size={14} className=\"spin\" /> : <ShieldCheck size={14} />}\n {verifying ? 'Testing…' : 'Test & save key'}\n </Button>\n </div>\n <p className=\"minimax-wizard-prose minimax-wizard-prose--muted\">\n Don't want to test first? <a href=\"#\" onClick={e => { e.preventDefault(); onManualKeySave(); }} className=\"minimax-wizard-link\">Save without testing</a>\n </p>\n </div>\n )}\n\n {step === 3 && (\n <div className=\"minimax-wizard-body\">\n <h3 className=\"minimax-wizard-title\"><CircleCheck size={18} style={{ verticalAlign: 'text-bottom', marginRight: 6 }} />All set</h3>\n <p className=\"minimax-wizard-prose\">The key works and is saved. Reloading so you can see your live quota.</p>\n <div className=\"minimax-wizard-actions\">\n <Button variant=\"primary\" size=\"md\" onClick={() => window.location.reload()}>View your quota →</Button>\n </div>\n </div>\n )}\n\n <div className=\"minimax-wizard-footer\">\n <ShieldCheck size={11} />\n <span>Key written to <code>~/.local/share/opencode/auth.json</code> with mode 0600.</span>\n </div>\n </Card>\n </div>\n );\n}\nexport const MiniMaxUsage = React.memo(MiniMaxUsageInner);\n","// src/components/BgStatusBadge.tsx — status pill for background agent instances.\n// Maps BackgroundStatus values to badge kinds from StatusBadge.\n\nimport { StatusBadge, type StatusBadgeProps } from './StatusBadge';\n\nconst STATUS_KIND: Record<string, StatusBadgeProps['kind']> = {\n pending: 'info',\n running: 'accent',\n done: 'success',\n failed: 'error',\n killed: 'neutral',\n timed_out: 'warning',\n};\n\nconst STATUS_LABELS: Record<string, string> = {\n pending: 'Pending',\n running: 'Running',\n done: 'Done',\n failed: 'Failed',\n killed: 'Killed',\n timed_out: 'Timed out',\n};\n\nexport function BgStatusBadge({ status, dot }: { status: string; dot?: boolean }) {\n const kind = STATUS_KIND[status] || 'neutral';\n const label = STATUS_LABELS[status] || status;\n return (\n <StatusBadge kind={kind} dot={dot}>\n {label}\n </StatusBadge>\n );\n}\n","// src/components/KillConfirmDialog.tsx — confirmation dialog for killing bg instances.\n// Provides both a JSX component and a convenience `openKillConfirmDialog` function.\n\nimport { Button } from './Button';\nimport type { ModalApi } from './Modal';\n\nexport type KillConfirmDialogProps = {\n instanceId: string;\n instanceName?: string;\n onConfirm: () => void | Promise<void>;\n onClose: () => void;\n};\n\n/**\n * Render inline inside a modal body. Usage:\n *\n * modal.open({\n * title: 'Kill background instance?',\n * children: (\n * <KillConfirmDialog\n * instanceId=\"bgr_abc\"\n * onConfirm={async () => { await killIt(); modal.close(); }}\n * onClose={() => modal.close()}\n * />\n * ),\n * });\n */\nexport function KillConfirmDialog({ instanceId, instanceName, onConfirm, onClose }: KillConfirmDialogProps) {\n return (\n <div>\n <p style={{ marginBottom: 16, lineHeight: 1.6 }}>\n Instance <code>{instanceId}</code>\n {instanceName ? <> ({instanceName})</> : null} will be terminated.\n This cannot be undone.\n </p>\n <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>\n <Button variant=\"ghost\" onClick={onClose}>Cancel</Button>\n <Button\n variant=\"danger\"\n onClick={async () => {\n await onConfirm();\n onClose();\n }}\n >\n Kill\n </Button>\n </div>\n </div>\n );\n}\n\n/**\n * Convenience wrapper: open a kill-confirmation modal programmatically.\n * Calls `DELETE /api/background/${instanceId}` on confirm and shows a toast.\n */\nexport function openKillConfirmDialog(\n modal: ModalApi,\n toast: { success: (msg: string, duration?: number) => void; error: (msg: string) => void },\n instanceId: string,\n instanceName?: string,\n onSuccess?: () => void,\n) {\n modal.open({\n title: `Kill instance?`,\n width: 400,\n children: (\n <KillConfirmDialog\n instanceId={instanceId}\n instanceName={instanceName}\n onConfirm={async () => {\n try {\n const r = await fetch(`/api/background/${encodeURIComponent(instanceId)}`, { method: 'DELETE' });\n const data = await r.json();\n if (data.ok) {\n toast.success(`Instance ${instanceId} killed.`);\n onSuccess?.();\n } else {\n toast.error(`Kill failed: ${data.error || 'unknown error'}`);\n }\n } catch (err) {\n toast.error(`Kill failed: ${(err as Error).message}`);\n }\n }}\n onClose={() => modal.close()}\n />\n ),\n });\n}\n","// src/components/background/TmuxAttachCard.tsx — per-instance tmux attach card\n// v3.22.0\n//\n// Shows the tmux session name, a \"Copy attach command\" button, and\n// an \"Open in terminal\" button that POSTs to /api/background/:id/open-terminal.\n// When tmux is missing on the host, shows a friendly warning instead.\n\nimport { useState } from 'react';\nimport { Copy, Terminal, AlertTriangle } from 'lucide-react';\nimport { Button } from '../Button';\nimport { Card } from '../Card';\nimport { useToast } from '../Toast';\nimport { api } from '../../lib/api';\nimport type { BgInstance } from '../../lib/types';\n\ntype TmuxAttachCardProps = {\n instance: BgInstance;\n};\n\nexport function TmuxAttachCard({ instance }: TmuxAttachCardProps) {\n const toast = useToast();\n const [opening, setOpening] = useState(false);\n\n const sessionName = instance.tmuxSession;\n const attachCommand = sessionName ? `tmux attach -t ${sessionName}` : null;\n\n const copyCommand = async () => {\n if (!attachCommand) return;\n try {\n await navigator.clipboard.writeText(attachCommand);\n toast.success('Attach command copied');\n } catch {\n toast.error('Could not copy to clipboard');\n }\n };\n\n const openTerminal = async () => {\n if (!instance.instanceId || !sessionName) return;\n setOpening(true);\n try {\n const result = await api.post<{ ok: boolean; command: string; error?: string }>(\n `/background/${encodeURIComponent(instance.instanceId)}/open-terminal`,\n { emulator: 'system' },\n );\n if (result.ok) {\n toast.success('Opening terminal…');\n } else {\n toast.error(result.error || 'Failed to open terminal');\n // Fallback: copy the command so the user can paste it manually.\n if (attachCommand) {\n try {\n await navigator.clipboard.writeText(attachCommand);\n toast.success('Command copied to clipboard');\n } catch { /* noop */ }\n }\n }\n } catch (err) {\n toast.error(`Failed: ${(err as Error).message}`);\n // Fallback: copy command on network error.\n if (attachCommand) {\n try {\n await navigator.clipboard.writeText(attachCommand);\n toast.success('Command copied to clipboard');\n } catch { /* noop */ }\n }\n } finally {\n setOpening(false);\n }\n };\n\n // Don't render anything if there's no tmux session to attach to.\n if (!sessionName) {\n return (\n <Card variant=\"outlined\" className=\"bg-tmux-card bg-tmux-card-warn\">\n <div className=\"bg-tmux-card-header\">\n <AlertTriangle size={14} />\n <span>No tmux session</span>\n </div>\n <p className=\"bg-tmux-hint muted\">\n This instance does not have a tmux session attached.\n Sessions are created automatically when a background agent starts.\n </p>\n </Card>\n );\n }\n\n return (\n <Card variant=\"outlined\" className=\"bg-tmux-card\">\n <div className=\"bg-tmux-card-header\">\n <Terminal size={14} />\n <span>tmux session</span>\n {instance.tmuxActive !== false ? (\n <span className=\"badge badge-success\">live</span>\n ) : (\n <span className=\"badge badge-warning\">inactive</span>\n )}\n </div>\n\n <code className=\"mono bg-tmux-session-name\">{sessionName}</code>\n\n <p className=\"muted bg-tmux-hint\">\n Attach to the agent's tmux session from a terminal on the host\n running the dashboard.\n </p>\n\n <div className=\"bg-tmux-card-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={copyCommand} title=\"Copy attach command\">\n <Copy size={14} /> Copy\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={openTerminal}\n loading={opening}\n title=\"Open in system terminal\"\n >\n <Terminal size={14} /> Open terminal\n </Button>\n </div>\n </Card>\n );\n}\n","// src/web/views/SpawnAgentModal.tsx — modal form to spawn a background\n// agent directly from the dashboard. Calls POST /api/background,\n// tracks the resulting instanceId, and on success closes the modal\n// while the parent navigates to the new instance's detail view.\n//\n// Fields mirror the API body shape:\n// agent (string, required) — agent name\n// prompt (string, required) — initial prompt\n// model (string, optional) — \"providerID/modelID\"\n// timeoutMs (number, slider) — 1min..4h, default 5min\n// persistent (boolean, toggle) — auto-restart on failure\n// tags (string[], optional)\nimport { useState, type FormEvent } from 'react';\nimport { Plus, X } from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\n\ntype AgentOption = { name: string; description?: string };\n\ntype Props = {\n open: boolean;\n onClose: () => void;\n onCreated?: (instanceId: string) => void;\n /** Available agents for the dropdown. Defaults to a small static set. */\n agents?: AgentOption[];\n};\n\nconst DEFAULT_AGENTS: AgentOption[] = [\n { name: 'mimir', description: 'Deep research & codebase exploration' },\n { name: 'frigg', description: 'Read-only codebase Q&A' },\n { name: 'thor', description: 'Moderate-complexity implementation' },\n { name: 'tyr', description: 'Complex feature implementation' },\n { name: 'heimdall', description: 'Quick edits & simple tasks' },\n { name: 'odin', description: 'Primary router agent' },\n];\n\nconst TIMEOUT_PRESETS = [\n { label: '1 min', value: 60_000 },\n { label: '5 min', value: 300_000 },\n { label: '15 min', value: 900_000 },\n { label: '30 min', value: 1_800_000 },\n { label: '1 hr', value: 3_600_000 },\n { label: '4 hr', value: 14_400_000 },\n];\n\nexport function SpawnAgentModal({ open, onClose, onCreated, agents = DEFAULT_AGENTS }: Props) {\n const toast = useToast();\n const [agent, setAgent] = useState<string>(agents[0]?.name || 'mimir');\n const [prompt, setPrompt] = useState<string>('');\n const [model, setModel] = useState<string>('');\n const [timeoutMs, setTimeoutMs] = useState<number>(300_000);\n const [persistent, setPersistent] = useState<boolean>(false);\n const [tagsRaw, setTagsRaw] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n\n if (!open) return null;\n\n const onSubmit = async (ev: FormEvent<HTMLFormElement>) => {\n ev.preventDefault();\n setError(null);\n if (!prompt.trim()) {\n setError('Prompt is required.');\n return;\n }\n setSubmitting(true);\n try {\n const tags = tagsRaw\n .split(',')\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n const body = {\n agent,\n prompt,\n ...(model.trim() ? { model: model.trim() } : {}),\n timeoutMs,\n persistent,\n maxRestarts: 3,\n ...(tags.length > 0 ? { tags } : {}),\n };\n const res = await api.post<{\n instanceId: string;\n status: string;\n sessionId?: string;\n error?: string;\n message?: string;\n }>('/background', body);\n if (res?.error) {\n throw new Error(res.message || res.error);\n }\n toast.success(`Spawned ${agent} (${res.instanceId.slice(0, 14)}…)`);\n onCreated?.(res.instanceId);\n // Reset the form for next time.\n setPrompt('');\n setModel('');\n setPersistent(false);\n setTagsRaw('');\n onClose();\n } catch (err) {\n setError((err as Error)?.message || 'Failed to spawn.');\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <div className=\"modal-backdrop\" role=\"dialog\" aria-modal=\"true\">\n <div className=\"modal-card spawn-modal\">\n <div className=\"spawn-modal-header\">\n <h3>\n <Plus size={18} /> Spawn background agent\n </h3>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose} title=\"Close\">\n <X size={14} />\n </Button>\n </div>\n <form onSubmit={onSubmit} className=\"spawn-modal-body\">\n <label className=\"field\">\n <span className=\"field-label\">Agent</span>\n <select\n className=\"field-input\"\n value={agent}\n onChange={(e) => setAgent(e.target.value)}\n required\n >\n {agents.map((a) => (\n <option key={a.name} value={a.name}>\n {a.name}{a.description ? ` — ${a.description}` : ''}\n </option>\n ))}\n </select>\n </label>\n\n <label className=\"field\">\n <span className=\"field-label\">Initial prompt</span>\n <textarea\n className=\"field-input spawn-modal-textarea\"\n rows={5}\n value={prompt}\n onChange={(e) => setPrompt(e.target.value)}\n placeholder=\"What do you want this agent to do?\"\n required\n />\n </label>\n\n <label className=\"field\">\n <span className=\"field-label\">Model (optional)</span>\n <input\n type=\"text\"\n className=\"field-input\"\n value={model}\n onChange={(e) => setModel(e.target.value)}\n placeholder=\"providerID/modelID (leave blank for agent default)\"\n />\n </label>\n\n <div className=\"field\">\n <span className=\"field-label\">Timeout</span>\n <div className=\"spawn-modal-timeouts\">\n {TIMEOUT_PRESETS.map((p) => (\n <button\n key={p.value}\n type=\"button\"\n className={\n 'spawn-modal-timeout-pill' +\n (p.value === timeoutMs ? ' spawn-modal-timeout-pill-active' : '')\n }\n onClick={() => setTimeoutMs(p.value)}\n >\n {p.label}\n </button>\n ))}\n </div>\n <input\n type=\"range\"\n min={60_000}\n max={14_400_000}\n step={60_000}\n value={timeoutMs}\n onChange={(e) => setTimeoutMs(Number(e.target.value))}\n className=\"spawn-modal-slider\"\n />\n <span className=\"muted\">{(timeoutMs / 60_000).toFixed(0)} min</span>\n </div>\n\n <label className=\"field-checkbox\">\n <input\n type=\"checkbox\"\n checked={persistent}\n onChange={(e) => setPersistent(e.target.checked)}\n />\n <span>Persistent — auto-restart on terminal failure (max 3 attempts)</span>\n </label>\n\n <label className=\"field\">\n <span className=\"field-label\">Tags (optional, comma-separated)</span>\n <input\n type=\"text\"\n className=\"field-input\"\n value={tagsRaw}\n onChange={(e) => setTagsRaw(e.target.value)}\n placeholder=\"e.g. refactor, urgent\"\n />\n </label>\n\n {error && <div className=\"spawn-modal-error\">{error}</div>}\n\n <div className=\"spawn-modal-actions\">\n <Button variant=\"ghost\" size=\"sm\" type=\"button\" onClick={onClose}>\n Cancel\n </Button>\n <Button variant=\"primary\" size=\"sm\" type=\"submit\" disabled={submitting}>\n {submitting ? 'Spawning…' : 'Spawn agent'}\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n","// src/views/BackgroundAgents.tsx — dashboard tab listing active background-agent\n// instances.\n//\n// v5.x — full UI redesign for the 7 background-agent integration gaps:\n// - \"+ Spawn\" button + `SpawnAgentModal` for direct dashboard spawns\n// - Pause / Resume / Steer actions per instance\n// - WebSocket-driven streaming output (`bg:output` events)\n// - Tool-call history collapsible list per instance\n// - Polling 5s safety net preserved\nimport { useCallback, useEffect, useRef, useState, type UIEvent } from 'react';\nimport {\n Activity as ActivityIcon,\n Copy,\n Eye,\n Loader2,\n Pause,\n PauseCircle,\n Play,\n Plus,\n RefreshCw,\n Send,\n Terminal,\n Trash2,\n} from 'lucide-react';\nimport { Button } from '../components/Button';\nimport { Card } from '../components/Card';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useModal } from '../components/Modal';\nimport { useToast } from '../components/Toast';\nimport { BgStatusBadge } from '../components/BgStatusBadge';\nimport { openKillConfirmDialog } from '../components/KillConfirmDialog';\nimport { TmuxAttachCard } from '../components/background/TmuxAttachCard';\nimport { SpawnAgentModal } from './SpawnAgentModal';\nimport { api } from '../lib/api';\nimport { Ws } from '../lib/ws';\nimport { cn, formatTime, truncate } from '../lib/utils';\nimport type {\n BackgroundListResponse,\n BackgroundOutputResponse,\n BackgroundTmuxResponse,\n BgInstance,\n BgToolCall,\n Settings,\n Snapshot,\n} from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst POLL_INTERVAL_MS = 5_000;\nconst OUTPUT_REFRESH_MS = 3_000; // fallback poll (used if WS is unavailable)\nconst PROMPT_TRUNCATE = 120;\nconst STREAM_BUFFER_LIMIT = 32_000; // chars\n\nfunction isActive(b: BgInstance): boolean {\n return b.status === 'pending' || b.status === 'running' || b.status === 'paused';\n}\n\nfunction isPaused(b: BgInstance): boolean {\n return b.status === 'paused';\n}\n\nfunction formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '—';\n const total = Math.floor(ms / 1000);\n const h = Math.floor(total / 3600);\n const m = Math.floor((total % 3600) / 60);\n const s = total % 60;\n if (h > 0) return `${h}h ${m}m ${s}s`;\n if (m > 0) return `${m}m ${s}s`;\n return `${s}s`;\n}\n\nexport function BackgroundAgents(_props: Props) {\n const toast = useToast();\n const modal = useModal();\n const [instances, setInstances] = useState<BgInstance[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [, setTick] = useState(0);\n const [showSpawn, setShowSpawn] = useState(false);\n\n const load = useCallback(async () => {\n try {\n const res = await api.get<BackgroundListResponse>('/background');\n setInstances(Array.isArray(res?.instances) ? res.instances : []);\n setError(null);\n } catch (err) {\n setError((err as Error)?.message || 'Failed to load background agents.');\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Initial load + polling safety net.\n useEffect(() => {\n load();\n const id = setInterval(load, POLL_INTERVAL_MS);\n return () => clearInterval(id);\n }, [load]);\n\n // 1s tick to keep the duration strings fresh.\n useEffect(() => {\n const id = setInterval(() => setTick((t) => (t + 1) % 1_000_000), 1000);\n return () => clearInterval(id);\n }, []);\n\n // WS subscription — refetch on any background:* event.\n useEffect(() => {\n const ws = new Ws();\n const off = ws.on((msg) => {\n const t = (msg as { type?: string }).type;\n if (\n t === 'background:change' ||\n t === 'background:cleanup' ||\n t === 'bg:progress' ||\n t === 'bg:tool-call'\n ) {\n load();\n }\n });\n return () => {\n off();\n ws.close();\n };\n }, [load]);\n\n const active = instances.filter(isActive);\n\n // ─── Handlers ─────────────────────────────────────────────────────────\n\n const onOpenOutput = (b: BgInstance) => {\n openOutputModal(modal, b);\n };\n\n const onOpenTmux = async (b: BgInstance) => {\n try {\n const info = await api.get<BackgroundTmuxResponse>(\n `/background/${encodeURIComponent(b.instanceId)}/tmux`,\n );\n openTmuxModal(modal, info);\n } catch (err) {\n toast.error(`Tmux info failed: ${(err as Error).message}`);\n }\n };\n\n const onKill = (b: BgInstance) => {\n openKillConfirmDialog(modal, toast, b.instanceId, b.agent || b.prompt, () => {\n setInstances((cur) => cur.filter((x) => x.instanceId !== b.instanceId));\n });\n };\n\n const onPause = async (b: BgInstance) => {\n try {\n const r = await api.post<{ ok: boolean; error?: string }>(\n `/background/${encodeURIComponent(b.instanceId)}/pause`,\n {},\n );\n if (!r?.ok) toast.error(r?.error || 'Pause failed.');\n else toast.info(`Paused ${b.instanceId.slice(0, 14)}…`);\n } catch (err) {\n toast.error(`Pause failed: ${(err as Error).message}`);\n }\n };\n\n const onResume = async (b: BgInstance) => {\n try {\n const r = await api.post<{ ok: boolean; error?: string }>(\n `/background/${encodeURIComponent(b.instanceId)}/resume`,\n {},\n );\n if (!r?.ok) toast.error(r?.error || 'Resume failed.');\n else toast.info(`Resumed ${b.instanceId.slice(0, 14)}…`);\n } catch (err) {\n toast.error(`Resume failed: ${(err as Error).message}`);\n }\n };\n\n const onSteer = (b: BgInstance) => {\n openSteerModal(modal, toast, b, load);\n };\n\n // ─── Render ───────────────────────────────────────────────────────────\n\n if (loading) {\n return (\n <div className=\"bg-active-view\">\n <div className=\"bg-active-loading\">\n <Spinner size=\"md\" />\n <span>Loading background agents…</span>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"bg-active-view\">\n <EmptyState\n icon={<ActivityIcon size={32} />}\n title=\"Couldn't load background agents\"\n message={error}\n action={\n <Button variant=\"primary\" onClick={load}>\n <RefreshCw size={14} /> Retry\n </Button>\n }\n />\n </div>\n );\n }\n\n return (\n <div className=\"bg-active-view\">\n <div className=\"bg-active-header\">\n <div className=\"bg-active-header-text\">\n <h2 className=\"bg-active-title\">Active Background Agents</h2>\n <p className=\"bg-active-subtitle muted\">\n {active.length} active · {instances.length} total in store\n </p>\n </div>\n <div className=\"bg-active-header-actions\">\n <Button variant=\"primary\" size=\"sm\" onClick={() => setShowSpawn(true)}>\n <Plus size={14} /> Spawn\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={load} title=\"Refresh now\">\n <RefreshCw size={14} /> Refresh\n </Button>\n </div>\n </div>\n\n <SpawnAgentModal\n open={showSpawn}\n onClose={() => setShowSpawn(false)}\n onCreated={() => {\n load();\n }}\n />\n\n {active.length === 0 ? (\n <EmptyState\n icon={<ActivityIcon size={32} />}\n title=\"No active background agents\"\n message=\"Use the Spawn button above or call bizar_spawn_background from an agent.\"\n action={\n <Button variant=\"primary\" onClick={() => setShowSpawn(true)}>\n <Plus size={14} /> Spawn your first agent\n </Button>\n }\n />\n ) : (\n <div className=\"bg-active-list\">\n {active.map((b) => (\n <BackgroundAgentCard\n key={b.instanceId}\n inst={b}\n onViewOutput={() => onOpenOutput(b)}\n onOpenTmux={() => onOpenTmux(b)}\n onKill={() => onKill(b)}\n onPause={isPaused(b) ? undefined : () => onPause(b)}\n onResume={isPaused(b) ? () => onResume(b) : undefined}\n onSteer={() => onSteer(b)}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Per-instance card ─────────────────────────────────────────────────────\n\nfunction BackgroundAgentCard({\n inst,\n onViewOutput,\n onOpenTmux,\n onKill,\n onPause,\n onResume,\n onSteer,\n}: {\n inst: BgInstance;\n onViewOutput: () => void;\n onOpenTmux: () => void;\n onKill: () => void;\n onPause?: () => void;\n onResume?: () => void;\n onSteer: () => void;\n}) {\n const startedMs = typeof inst.startedAt === 'number' ? inst.startedAt : 0;\n const startedLabel = startedMs ? formatTime(startedMs) : '—';\n const durationMs = startedMs ? Date.now() - startedMs : 0;\n const prompt = truncate(inst.prompt, PROMPT_TRUNCATE);\n const progress = typeof inst.progress === 'number' ? inst.progress : null;\n\n return (\n <Card className=\"bg-active-card\" variant=\"elevated\">\n <div className=\"bg-active-card-top\">\n <div className=\"bg-active-card-id\">\n <code className=\"mono\">{inst.instanceId}</code>\n <BgStatusBadge status={inst.status || 'pending'} dot />\n {isPaused(inst) && (\n <span className=\"bg-active-card-paused-tag\">\n <PauseCircle size={12} /> paused\n </span>\n )}\n </div>\n <div className=\"bg-active-card-agent\">\n <span className=\"bg-active-card-agent-label\">Agent</span>\n <span className=\"bg-active-card-agent-name\">{inst.agent || 'unknown'}</span>\n </div>\n </div>\n\n {prompt && <div className=\"bg-active-prompt\">{prompt}</div>}\n\n {inst.currentStep && (\n <div className=\"bg-active-step\">\n <span className=\"bg-active-step-label\">Step:</span>\n <span className=\"bg-active-step-value\">{inst.currentStep}</span>\n </div>\n )}\n\n {progress !== null && (\n <div className=\"progress-bar\" aria-label=\"Progress\">\n <div\n className=\"progress-fill\"\n style={{\n width: `${\n progress < 0\n ? 100\n : Math.max(0, Math.min(100, progress))\n }%`,\n }}\n />\n <span className=\"progress-label\">\n {progress < 0\n ? '…'\n : `${Math.round(progress)}%`}\n {inst.progressMessage ? ` · ${inst.progressMessage}` : ''}\n </span>\n </div>\n )}\n\n <div className=\"bg-active-meta\">\n <span title={startedLabel}>\n <strong>Started:</strong> {startedLabel}\n </span>\n <span>\n <strong>Duration:</strong> {formatDuration(durationMs)}\n </span>\n <span>\n <strong>Tool calls:</strong> {inst.toolCallCount ?? 0}\n </span>\n {inst.processId && (\n <span>\n <strong>PID:</strong> <code className=\"mono\">{inst.processId}</code>\n </span>\n )}\n {Array.isArray(inst.tags) && inst.tags.length > 0 && (\n <span>\n <strong>Tags:</strong>{' '}\n {inst.tags.map((t, i) => (\n <span key={t} className=\"tag-pill\">\n {t}\n {i < inst.tags!.length - 1 ? ' ' : ''}\n </span>\n ))}\n </span>\n )}\n {inst.tmuxSession && (\n <span className={cn(inst.tmuxActive && 'bg-active-meta-tmux-live')}>\n <strong>tmux:</strong> <code className=\"mono\">{inst.tmuxSession}</code>\n {inst.tmuxActive ? ' · live' : ''}\n </span>\n )}\n </div>\n\n <div className=\"bg-active-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={onViewOutput}>\n <Eye size={14} /> View output\n </Button>\n {onPause && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={onPause}\n title=\"Pause subprocess (POSIX)\"\n >\n <Pause size={14} /> Pause\n </Button>\n )}\n {onResume && (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={onResume}\n title=\"Resume subprocess (POSIX)\"\n >\n <Play size={14} /> Resume\n </Button>\n )}\n <Button variant=\"ghost\" size=\"sm\" onClick={onSteer} title=\"Steer with new instructions\">\n <Send size={14} /> Steer\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={onOpenTmux}>\n <Terminal size={14} /> Open in tmux\n </Button>\n <Button variant=\"danger\" size=\"sm\" onClick={onKill}>\n <Trash2 size={14} /> Kill\n </Button>\n </div>\n\n <TmuxAttachCard instance={inst} />\n </Card>\n );\n}\n\n// ─── Output modal (auto-refresh) ───────────────────────────────────────────\n\nfunction openOutputModal(\n modal: ReturnType<typeof useModal>,\n inst: BgInstance,\n) {\n modal.open({\n title: `Output — ${inst.agent || inst.instanceId}`,\n width: 720,\n children: <OutputModalBody instanceId={inst.instanceId} />,\n });\n}\n\nfunction OutputModalBody({ instanceId }: { instanceId: string }) {\n const toast = useToast();\n // Buffer of recent lines for streaming output.\n const bufRef = useRef<string[]>([]);\n const [output, setOutput] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [available, setAvailable] = useState(true);\n const [streamingActive, setStreamingActive] = useState(true);\n const [toolCalls, setToolCalls] = useState<BgToolCall[]>([]);\n const [showToolCalls, setShowToolCalls] = useState(true);\n const refBottom = useRef<HTMLDivElement | null>(null);\n const refAutoscroll = useRef(true);\n\n const recomputeOutput = useCallback(() => {\n setOutput(bufRef.current.join('\\n'));\n }, []);\n\n // Seed from /output, then optionally from disk. The endpoint is the\n // tmux `capture-pane` for legacy instances; for dashboard-spawned\n // ones it gracefully returns `available: false` and we rely on WS.\n const load = useCallback(async () => {\n try {\n const r = await api.get<BackgroundOutputResponse>(\n `/background/${encodeURIComponent(instanceId)}/output?lines=300`,\n );\n setAvailable(r?.available !== false);\n if (r?.output && bufRef.current.length === 0) {\n // Seed the buffer exactly once. Subsequent loads are no-ops\n // for the buffer (WS appends will keep it current).\n const lines = r.output.split(/\\r?\\n/);\n bufRef.current = lines.slice(-300);\n recomputeOutput();\n }\n setError(null);\n } catch (err) {\n setError((err as Error)?.message || 'Failed to load output.');\n } finally {\n setLoading(false);\n }\n }, [instanceId, recomputeOutput]);\n\n useEffect(() => {\n load();\n const id = setInterval(load, OUTPUT_REFRESH_MS);\n return () => clearInterval(id);\n }, [load]);\n\n // Subscribe to bg:output events for true streaming. Falls back to\n // polling if the WS never connects (we still render the seeded\n // text). The OutputModalBody owns its own WS so streams survive\n // modal re-opens and don't share state with the list WS.\n useEffect(() => {\n const ws = new Ws();\n let isOpen = false;\n const offStatus = ws.onStatus((s) => {\n isOpen = s === 'connected';\n setStreamingActive(isOpen);\n });\n const offMsg = ws.on((msg) => {\n const m = msg as { type?: string; instanceId?: string; line?: string };\n if (m.type === 'bg:output' && m.instanceId === instanceId && typeof m.line === 'string') {\n bufRef.current.push(m.line);\n // Cap buffer length; keep most recent N chars.\n let total = 0;\n for (let i = bufRef.current.length - 1; i >= 0; i--) {\n total += (bufRef.current[i]?.length ?? 0) + 1;\n if (total > STREAM_BUFFER_LIMIT) {\n bufRef.current = bufRef.current.slice(i + 1);\n break;\n }\n }\n setOutput(bufRef.current.join('\\n'));\n }\n });\n return () => {\n offStatus();\n offMsg();\n ws.close();\n };\n }, [instanceId]);\n\n // Fetch tool-call history once (and refresh on bg:tool-call events).\n useEffect(() => {\n let cancelled = false;\n const refresh = async () => {\n try {\n const r = await api.get<{ toolCalls: BgToolCall[] }>(\n `/background/${encodeURIComponent(instanceId)}/tool-calls`,\n );\n if (!cancelled && Array.isArray(r?.toolCalls)) {\n setToolCalls(r.toolCalls);\n }\n } catch {\n /* fall through; the list is optional */\n }\n };\n refresh();\n const ws = new Ws();\n const off = ws.on((msg) => {\n const m = msg as { type?: string; instanceId?: string };\n if (m.type === 'bg:tool-call' && m.instanceId === instanceId) refresh();\n });\n return () => {\n cancelled = true;\n off();\n ws.close();\n };\n }, [instanceId]);\n\n // Auto-scroll to bottom only if user is already near the bottom.\n useEffect(() => {\n if (!refAutoscroll.current) return;\n refBottom.current?.scrollIntoView({ behavior: 'auto', block: 'end' });\n }, [output]);\n\n const onScroll = (e: UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 24;\n refAutoscroll.current = atBottom;\n };\n\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(output);\n toast.success('Output copied.');\n } catch {\n // ignore — clipboard may be unavailable in some contexts\n }\n };\n\n return (\n <div className=\"bg-output-modal\">\n <div className=\"bg-output-toolbar\">\n <span className=\"muted\">\n {streamingActive\n ? `streaming · ${output.length} chars`\n : available\n ? `${output.length} chars · auto-refresh ${OUTPUT_REFRESH_MS / 1000}s (WS idle)`\n : 'Output unavailable (no tmux session)'}\n </span>\n <div className=\"bg-output-toolbar-actions\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setShowToolCalls((v) => !v)}\n title=\"Toggle tool-call history\"\n >\n {showToolCalls ? 'Hide tools' : 'Show tools'}\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={load} title=\"Refresh now\">\n <RefreshCw size={14} /> Refresh\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={copy} disabled={!output}>\n <Copy size={14} /> Copy\n </Button>\n </div>\n </div>\n {loading && !output ? (\n <div className=\"bg-output-loading\">\n <Loader2 size={16} className=\"spin\" /> Loading…\n </div>\n ) : error ? (\n <div className=\"bg-output-error\">{error}</div>\n ) : (\n <div className=\"bg-output-body\">\n <div className=\"bg-output-scroll\" onScroll={onScroll}>\n <pre className=\"bg-output-pre mono\">\n <code>\n {output || (\n <span className=\"muted\">No output captured yet — waiting for the agent to start…</span>\n )}\n </code>\n </pre>\n <div ref={refBottom} />\n </div>\n {showToolCalls && (\n <ToolCallHistory calls={toolCalls} />\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Tool-call history panel ───────────────────────────────────────────────\n\nfunction ToolCallHistory({ calls }: { calls: BgToolCall[] }) {\n return (\n <aside className=\"bg-tool-calls\" aria-label=\"Tool call history\">\n <h4 className=\"bg-tool-calls-title\">Tool calls ({calls.length})</h4>\n {calls.length === 0 ? (\n <p className=\"muted bg-tool-calls-empty\">No tool calls recorded yet.</p>\n ) : (\n <ol className=\"bg-tool-calls-list\">\n {calls.slice().reverse().map((c) => {\n const dur =\n c.endedAt && c.startedAt\n ? `${Math.max(0, c.endedAt - c.startedAt)}ms`\n : '…';\n return (\n <li key={c.id} className={`bg-tool-call bg-tool-call-${c.status}`}>\n <div className=\"bg-tool-call-head\">\n <code className=\"mono bg-tool-call-name\">{c.name}</code>\n <span className={`badge badge-${c.status === 'error' ? 'danger' : c.status === 'ok' ? 'success' : 'neutral'}`}>\n {c.status}\n </span>\n <span className=\"bg-tool-call-dur muted\">{dur}</span>\n </div>\n {c.args && (\n <pre className=\"bg-tool-call-args mono\">{c.args}</pre>\n )}\n {c.result && (\n <pre className=\"bg-tool-call-result mono\">{c.result.slice(0, 240)}</pre>\n )}\n {c.error && (\n <pre className=\"bg-tool-call-error mono\">{c.error}</pre>\n )}\n </li>\n );\n })}\n </ol>\n )}\n </aside>\n );\n}\n\n// ─── Tmux attach modal ─────────────────────────────────────────────────────\n\nfunction openTmuxModal(\n modal: ReturnType<typeof useModal>,\n info: BackgroundTmuxResponse,\n) {\n const cmd = info.attachCommand || info.session || '';\n modal.open({\n title: 'Attach to tmux',\n width: 520,\n children: <TmuxModalBody info={info} cmd={cmd} />,\n });\n}\n\n// ─── Steer modal ──────────────────────────────────────────────────────────\n\nfunction openSteerModal(\n modal: ReturnType<typeof useModal>,\n toast: ReturnType<typeof useToast>,\n inst: BgInstance,\n refresh: () => void,\n) {\n modal.open({\n title: `Steer ${inst.agent || inst.instanceId}`,\n width: 600,\n children: (\n <SteerModalBody\n instanceId={inst.instanceId}\n toast={toast}\n onCreated={refresh}\n onClose={() => modal.close()}\n />\n ),\n });\n}\n\nfunction SteerModalBody({\n instanceId,\n toast,\n onCreated,\n onClose,\n}: {\n instanceId: string;\n toast: ReturnType<typeof useToast>;\n onCreated: () => void;\n onClose: () => void;\n}) {\n const [message, setMessage] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const onSubmit = async () => {\n if (!message.trim()) {\n setError('Message is required.');\n return;\n }\n setSubmitting(true);\n try {\n const r = await api.post<{\n ok: boolean;\n newInstanceId?: string;\n error?: string;\n }>(`/background/${encodeURIComponent(instanceId)}/steer`, { message });\n if (!r?.ok) {\n setError(r?.error || 'Steer failed.');\n return;\n }\n toast.success(\n `Steered → new instance ${(r.newInstanceId ?? '').slice(0, 14)}…`,\n );\n onCreated();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <div className=\"bg-steer-modal\">\n <p className=\"muted\">\n Steer kills the current subprocess and spawns a new one with the\n original prompt + your message appended. The new instance is\n linked to this one as <code>parentInstanceId</code>.\n </p>\n <textarea\n className=\"field-input bg-steer-textarea\"\n rows={6}\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n placeholder=\"What do you want the agent to do differently?\"\n />\n {error && <div className=\"bg-steer-error\">{error}</div>}\n <div className=\"bg-steer-actions\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose}>\n Cancel\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={onSubmit}\n disabled={submitting || !message.trim()}\n >\n {submitting ? 'Steering…' : 'Steer'}\n </Button>\n </div>\n </div>\n );\n}\n\nfunction TmuxModalBody({ info, cmd }: { info: BackgroundTmuxResponse; cmd: string }) {\n const [copied, setCopied] = useState(false);\n const onCopy = async () => {\n try {\n await navigator.clipboard.writeText(cmd);\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1500);\n } catch {\n /* noop */\n }\n };\n\n return (\n <div className=\"bg-tmux-modal\">\n {!cmd ? (\n <p className=\"muted\">No tmux session attached to this instance.</p>\n ) : (\n <>\n <p className=\"bg-tmux-meta\">\n {info.exists ? (\n <span className=\"badge badge-success\">session live</span>\n ) : (\n <span className=\"badge badge-warning\">\n session not running{info.reason ? ` — ${info.reason}` : ''}\n </span>\n )}\n {info.session && (\n <span className=\"bg-tmux-session muted\">\n · session <code className=\"mono\">{info.session}</code>\n </span>\n )}\n </p>\n <label className=\"field-label\">Attach command</label>\n <div className=\"bg-tmux-command-row\">\n <code className=\"bg-tmux-command mono\">{cmd}</code>\n <Button variant=\"secondary\" size=\"sm\" onClick={onCopy}>\n <Copy size={14} /> {copied ? 'Copied' : 'Copy'}\n </Button>\n </div>\n <p className=\"muted bg-tmux-hint\">\n Paste this into a terminal on the host running the dashboard. The\n dashboard itself does not open terminals.\n </p>\n </>\n )}\n </div>\n );\n}","// src/components/DoctorPanel.tsx — v6.0.0 reusable Doctor panel.\n//\n// A Card-wrapped section of the Doctor page that renders a list of\n// `DoctorCheck` rows with status pills, plus an optional info list\n// (e.g. counts) below the checks. Each `category` carries a default\n// icon and title so callers only need to pass the data.\n\nimport React from 'react';\nimport {\n Activity,\n AlertOctagon,\n CheckCircle2,\n CircleDot,\n type LucideIcon,\n Server,\n Settings2,\n Wrench,\n Zap,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { StatusBadge } from './StatusBadge';\nimport { EmptyState } from './EmptyState';\nimport { cn } from '../lib/utils';\nimport type {\n DoctorCategory,\n DoctorCheck,\n DoctorPanelProps,\n} from '../lib/types';\n\nconst CATEGORY_DEFAULTS: Record<\n DoctorCategory,\n { title: string; icon: LucideIcon; emptyTitle: string; emptyMessage: string }\n> = {\n system: {\n title: 'System health',\n icon: Server,\n emptyTitle: 'No system checks',\n emptyMessage: 'System checks did not return any rows.',\n },\n services: {\n title: 'Services',\n icon: Zap,\n emptyTitle: 'No service probes',\n emptyMessage: 'Service probes did not return any rows.',\n },\n counts: {\n title: 'Counts',\n icon: Activity,\n emptyTitle: 'No counts',\n emptyMessage: 'No counts reported by the dashboard stores.',\n },\n errors: {\n title: 'Recent errors',\n icon: AlertOctagon,\n emptyTitle: 'No recent errors',\n emptyMessage: 'No error lines in the service log within the last hour.',\n },\n actions: {\n title: 'Actions',\n icon: Wrench,\n emptyTitle: 'No actions',\n emptyMessage: 'No actions available.',\n },\n};\n\nfunction statusIcon(status: DoctorCheck['status']) {\n if (status === 'ok') return CheckCircle2;\n if (status === 'warn') return CircleDot;\n return AlertOctagon;\n}\n\nfunction statusLabel(status: DoctorCheck['status']) {\n if (status === 'ok') return 'ok';\n if (status === 'warn') return 'warn';\n return 'fail';\n}\n\n/**\n * Reusable Doctor panel. Used by both the Doctor page and any future\n * settings sub-panels that want a consistent status-list render.\n *\n * When `children` is supplied, the default check-list render is\n * skipped — useful for the \"Actions\" category where the body is\n * a row of buttons, not a list of checks.\n */\nexport function DoctorPanel({\n category,\n title,\n icon,\n checks,\n info,\n meta,\n children,\n className,\n}: DoctorPanelProps) {\n const def = CATEGORY_DEFAULTS[category];\n const Icon = icon ?? def.icon;\n const heading = title ?? def.title;\n const hasContent = checks.length > 0 || (info && info.length > 0) || children;\n return (\n <Card className={cn('doctor-panel', `doctor-panel-${category}`, className)}>\n <CardTitle>\n <Icon size={14} aria-hidden />\n <span>{heading}</span>\n {meta ? <span className=\"card-meta-inline muted\">{meta}</span> : null}\n </CardTitle>\n {!hasContent ? (\n <EmptyState\n icon={<Icon size={28} aria-hidden />}\n title={def.emptyTitle}\n message={def.emptyMessage}\n />\n ) : (\n <div className=\"doctor-panel-body\">\n {children}\n {checks.length > 0 ? (\n <ul className=\"doctor-check-list\" role=\"list\">\n {checks.map((c) => {\n const CheckIcon = statusIcon(c.status);\n return (\n <li key={c.name} className={cn('doctor-check-row', `doctor-check-${c.status}`)}>\n <span className=\"doctor-check-icon\" aria-hidden>\n <CheckIcon\n size={14}\n className={cn(\n 'doctor-check-icon-svg',\n c.status === 'ok' && 'doctor-check-icon-ok',\n c.status === 'warn' && 'doctor-check-icon-warn',\n c.status === 'fail' && 'doctor-check-icon-fail',\n )}\n />\n </span>\n <span className=\"doctor-check-name mono\">{c.name}</span>\n <span className=\"doctor-check-message\">{c.message}</span>\n <StatusBadge kind={c.status} dot>\n {statusLabel(c.status)}\n </StatusBadge>\n </li>\n );\n })}\n </ul>\n ) : null}\n {info && info.length > 0 ? (\n <dl className=\"doctor-info-list\">\n {info.map((row) => (\n <React.Fragment key={row.label}>\n <dt>{row.label}</dt>\n <dd className=\"tabular-nums\">{row.value}</dd>\n </React.Fragment>\n ))}\n </dl>\n ) : null}\n </div>\n )}\n </Card>\n );\n}\n\n// Re-export the Settings icon so callers can override without an extra import.\nexport { Settings2 };","// src/views/Doctor.tsx — v6.0.0 Doctor page.\n//\n// Full-page Doctor view: shows system health, service health, counts,\n// recent errors, and action buttons. Refreshes every 30 seconds via\n// the cheap `/api/doctor/health` endpoint and re-fetches the full\n// snapshot on demand (initial mount, manual Refresh, or after a\n// single-check POST so the operator sees the immediate result).\n//\n// The page deliberately leans on the existing Card component and the\n// StatusBadge variants added in v6.0.0 (`ok`/`warn`/`fail`). Layout\n// is a single column on narrow viewports, two columns on desktop —\n// matching the rest of the dashboard's grid.\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n CheckCircle2,\n AlertTriangle,\n AlertOctagon,\n Download,\n FileText,\n RefreshCw,\n PlayCircle,\n Stethoscope,\n Clock,\n} from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { DoctorPanel } from '../components/DoctorPanel';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { api } from '../lib/api';\nimport { cn, formatTime } from '../lib/utils';\nimport type { DoctorSnapshot, DoctorCheck, Settings, Snapshot } from '../lib/types';\n\nconst REFRESH_INTERVAL_MS = 30_000;\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nfunction DoctorInner({\n setActiveTab,\n}: Props) {\n const toast = useToast();\n const [data, setData] = useState<DoctorSnapshot | null>(null);\n const [loading, setLoading] = useState(true);\n const [refreshing, setRefreshing] = useState(false);\n const [lastFetched, setLastFetched] = useState<number | null>(null);\n const [autoRefresh, setAutoRefresh] = useState(true);\n const cancelledRef = useRef(false);\n\n const fetchSnapshot = useCallback(async () => {\n setRefreshing(true);\n try {\n const r = await api.get<DoctorSnapshot>('/doctor');\n if (!cancelledRef.current) {\n setData(r);\n setLastFetched(Date.now());\n setLoading(false);\n }\n } catch (err) {\n if (!cancelledRef.current) {\n setLoading(false);\n toast.error(`Doctor refresh failed: ${(err as Error).message}`);\n }\n } finally {\n if (!cancelledRef.current) setRefreshing(false);\n }\n }, [toast]);\n\n // Initial fetch on mount\n useEffect(() => {\n cancelledRef.current = false;\n fetchSnapshot();\n return () => { cancelledRef.current = true; };\n }, [fetchSnapshot]);\n\n // 30s auto-refresh via the cheap health endpoint so the page\n // stays current without burning a full snapshot every tick. We\n // only trigger a full snapshot fetch if status changed.\n useEffect(() => {\n if (!autoRefresh) return;\n const tick = async () => {\n try {\n const r = await api.get<{ status: string; issues: DoctorCheck[] }>('/doctor/health');\n setData((cur) => {\n if (!cur) return cur;\n if (cur.health.status !== r.status || cur.health.issues.length !== r.issues.length) {\n // Status changed — re-fetch the full snapshot\n fetchSnapshot();\n }\n return cur;\n });\n } catch { /* non-fatal */ }\n };\n const id = setInterval(tick, REFRESH_INTERVAL_MS);\n return () => clearInterval(id);\n }, [autoRefresh, fetchSnapshot]);\n\n const onRunCheck = async (checkName: string) => {\n try {\n const r = await api.post<DoctorCheck>('/doctor/check', { checkName });\n toast.info(`${r.name}: ${r.message}`, 4000);\n // Re-fetch so the panel reflects the fresh result\n await fetchSnapshot();\n } catch (err) {\n const apiErr = err as { status?: number; data?: { message?: string } };\n toast.error(`Check failed: ${apiErr.data?.message ?? (err as Error).message}`);\n }\n };\n\n const onExportJson = () => {\n if (!data) return;\n try {\n const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `doctor-snapshot-${new Date().toISOString().replace(/[:.]/g, '-')}.json`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n } catch (err) {\n toast.error(`Export failed: ${(err as Error).message}`);\n }\n };\n\n const onViewLogs = () => {\n // Logs live on the Settings → Activity Log surface (already\n // implemented). Set the tab and let the user browse.\n setActiveTab('settings');\n };\n\n const counts = data?.counts;\n const countsInfo = useMemo(() => {\n if (!counts) return [];\n return [\n { label: 'Tasks', value: counts.tasks },\n { label: 'Schedules', value: counts.schedules },\n { label: 'Mods', value: counts.mods },\n { label: 'Providers', value: counts.providers },\n { label: 'MCPs', value: counts.mcps },\n { label: 'Agents', value: counts.agents },\n { label: 'Projects', value: counts.projects },\n { label: 'Workspaces', value: counts.workspaces },\n { label: 'Voice notes', value: counts.voiceNotes },\n { label: 'Eval runs', value: counts.evalRuns },\n { label: 'Backups', value: counts.backups },\n ];\n }, [counts]);\n\n if (loading) {\n return (\n <div className=\"view view-doctor view-loading\">\n <Spinner size=\"lg\" />\n <p>Running health checks…</p>\n </div>\n );\n }\n\n if (!data) {\n return (\n <div className=\"view view-doctor\">\n <Card>\n <CardTitle>\n <AlertOctagon size={14} /> Doctor unavailable\n </CardTitle>\n <CardMeta>Could not reach /api/doctor.</CardMeta>\n <div className=\"doctor-fallback-actions\">\n <Button variant=\"primary\" onClick={fetchSnapshot}>\n <RefreshCw size={12} /> Retry\n </Button>\n </div>\n </Card>\n </div>\n );\n }\n\n const overall = data.health.status;\n const OverallIcon =\n overall === 'ok' ? CheckCircle2 : overall === 'warn' ? AlertTriangle : AlertOctagon;\n const overallLabel =\n overall === 'ok' ? 'Healthy' : overall === 'warn' ? 'Warning' : 'Failed';\n\n return (\n <div className=\"view view-doctor\" data-overall={overall}>\n <div className=\"doctor-header\">\n <div className=\"doctor-header-row\">\n <div className=\"doctor-header-title\">\n <Stethoscope size={20} aria-hidden />\n <h1>Doctor</h1>\n </div>\n <div className=\"doctor-header-status\">\n <span className={cn('doctor-overall-pill', `doctor-overall-${overall}`)}>\n <OverallIcon size={14} aria-hidden />\n <span className=\"doctor-overall-label\">{overallLabel}</span>\n <StatusBadge kind={overall} dot>\n {data.health.issues.length} issue{data.health.issues.length === 1 ? '' : 's'}\n </StatusBadge>\n </span>\n </div>\n </div>\n <div className=\"doctor-header-meta muted\">\n <Clock size={12} aria-hidden />\n <span aria-live=\"polite\" aria-atomic=\"true\">\n v{data.bizarVersion} · {data.platform}/{data.arch} ·{' '}\n up {Math.floor(data.uptime)}s\n {lastFetched ? ` · refreshed ${formatTime(new Date(lastFetched))}` : ''}\n </span>\n </div>\n </div>\n\n <div className=\"doctor-grid\">\n <DoctorPanel\n category=\"system\"\n checks={data.checks.system}\n meta={`${data.platform}/${data.arch}`}\n />\n <DoctorPanel\n category=\"services\"\n checks={data.checks.services}\n meta={\n data.services.opencode?.reachable\n ? `opencode on ${data.services.opencode.port ?? '?'}`\n : 'opencode not connected'\n }\n />\n <DoctorPanel\n category=\"counts\"\n checks={[]}\n info={countsInfo}\n meta={counts?.activeProject ? `active: ${counts.activeProject}` : 'no active project'}\n />\n <Card className=\"doctor-errors-card\">\n <CardTitle>\n <AlertOctagon size={14} aria-hidden />\n <span>Recent errors (last hour)</span>\n <span className=\"card-meta-inline muted\">\n {data.recentErrors.length} line{data.recentErrors.length === 1 ? '' : 's'}\n </span>\n </CardTitle>\n {data.recentErrors.length === 0 ? (\n <div className=\"muted doctor-errors-empty\">No errors in the last hour. Nice.</div>\n ) : (\n <ul className=\"doctor-errors-list\" role=\"list\">\n {data.recentErrors.map((e, idx) => (\n <li key={`${e.tsMs ?? idx}-${idx}`} className=\"doctor-error-row\">\n <span className=\"doctor-error-ts mono\">\n {e.ts ? formatTime(new Date(e.ts)) : '??:??:??'}\n </span>\n <span className=\"doctor-error-line mono\">{e.line}</span>\n </li>\n ))}\n </ul>\n )}\n </Card>\n <Card className=\"doctor-actions-card\">\n <CardTitle>\n <PlayCircle size={14} aria-hidden /> Actions\n </CardTitle>\n <CardMeta>Run a check, view logs, or export the snapshot.</CardMeta>\n <div className=\"doctor-actions-row\">\n <Button variant=\"primary\" onClick={fetchSnapshot} disabled={refreshing} aria-label=\"Refresh diagnostics\">\n {refreshing ? <Spinner size=\"sm\" /> : <RefreshCw size={12} />}\n {refreshing ? 'Running…' : 'Run Health Check Now'}\n </Button>\n <Button variant=\"secondary\" onClick={onViewLogs}>\n <FileText size={12} /> View Full Logs\n </Button>\n <Button variant=\"secondary\" onClick={onExportJson}>\n <Download size={12} /> Export Diagnostics as JSON\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setAutoRefresh((v) => !v)}\n aria-label={autoRefresh ? 'Pause auto-refresh' : 'Resume auto-refresh'}\n >\n {autoRefresh ? 'Pause auto-refresh' : 'Resume auto-refresh'}\n </Button>\n </div>\n {data.checks.services.some((c) => c.status !== 'ok') ||\n data.checks.config.some((c) => c.status !== 'ok') ? (\n <div className=\"doctor-actions-rerun\">\n <span className=\"muted\">Rerun a single check:</span>\n <div className=\"doctor-actions-rerun-row\">\n {[\n ...data.checks.services,\n ...data.checks.config,\n ]\n .filter((c) => c.status !== 'ok')\n .map((c) => (\n <Button\n key={c.name}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onRunCheck(c.name)}\n title={`Run check: ${c.name}`}\n >\n <PlayCircle size={10} /> {c.name}\n </Button>\n ))}\n </div>\n </div>\n ) : null}\n </Card>\n </div>\n </div>\n );\n}\n\nexport const Doctor = React.memo(DoctorInner);","// src/components/EvalRunCard.tsx — v5.2.0\n//\n// Compact card summarizing a single eval run. Used in the EvalReport's\n// left rail to show the recent run history. Click selects the run.\n//\n// Status rules (per brief):\n// failed === 0 → pass\n// passed/total > 0.8 → warn\n// otherwise → fail\n\nimport type { ReactNode } from 'react';\nimport { Card, CardTitle, CardMeta } from './Card';\nimport { cn, formatTime } from '../lib/utils';\n\n/**\n * Summary of an eval run. The fields here are the subset returned by\n * GET /api/eval/runs (the list endpoint) — `results` lives on the full\n * run record returned by GET /api/eval/runs/:id and is not present here.\n */\nexport type EvalRunSummary = {\n id: string;\n startedAt: string;\n finishedAt?: string;\n suitePath: string;\n total: number;\n passed: number;\n failed: number;\n};\n\nexport type EvalRunCardProps = {\n run: EvalRunSummary;\n onClick?: () => void;\n /** v5.2.0 — Marks the card as the currently selected run. */\n selected?: boolean;\n /** Optional aria-label override; falls back to the run id. */\n ariaLabel?: string;\n};\n\nfunction pickStatus(run: EvalRunSummary): 'pass' | 'warn' | 'fail' {\n if (run.total <= 0) return 'fail';\n if (run.failed === 0) return 'pass';\n if (run.passed / run.total > 0.8) return 'warn';\n return 'fail';\n}\n\nexport function EvalRunCard({ run, onClick, selected, ariaLabel }: EvalRunCardProps): ReactNode {\n const status = pickStatus(run);\n // Pass-rate as a fixed-percent string. toFixed guards against locale\n // issues (e.g. some locales use \",\" as the decimal separator).\n const passRate = run.total > 0\n ? ((run.passed / run.total) * 100).toFixed(1)\n : '0.0';\n const interactive = Boolean(onClick);\n\n return (\n <Card\n onClick={onClick}\n interactive={interactive}\n aria-label={ariaLabel ?? `Eval run ${run.id}`}\n aria-pressed={interactive ? selected : undefined}\n className={cn(\n 'eval-run-card',\n selected && 'eval-run-card-selected',\n `eval-run-${status}`,\n )}\n >\n <div className=\"eval-run-head\">\n <CardTitle className=\"eval-run-title\">{run.id}</CardTitle>\n <span className={cn('eval-status', `is-${status}`)}>\n {run.passed}/{run.total} ({passRate}%)\n </span>\n </div>\n <CardMeta className=\"eval-run-meta\">\n {formatTime(run.startedAt)} · {run.suitePath}\n </CardMeta>\n </Card>\n );\n}","// src/views/Eval.tsx — v5.2.0\n//\n// Main \"Eval\" tab view. Acts as the entry point to the eval framework\n// UI: shows the recent runs summary at the top and links the user\n// into EvalReport for the full per-fixture breakdown and regression\n// diffing.\n//\n// The detailed comparison/diff lives in EvalReport.tsx; this view is\n// a lighter landing page that mirrors the existing Doctor-style\n// overview pattern (counts at top, recent history, call to action).\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { ClipboardCheck, ArrowRight, RefreshCw, ExternalLink, Clock, Plus, Trash2 } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { EvalRunCard, type EvalRunSummary } from '../components/EvalRunCard';\nimport { api } from '../lib/api';\nimport { cn } from '../lib/utils';\nimport type { Settings, Snapshot } from '../lib/types';\n\ntype EvalSchedule = {\n id: string;\n name: string;\n suitePath: string;\n cron: string;\n agent: string;\n};\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nconst RECENT_RUNS_LIMIT = 8;\n\nfunction AddScheduleForm({\n onAdded,\n onCancel,\n}: {\n onAdded: (schedule: EvalSchedule) => void;\n onCancel: () => void;\n}) {\n const toast = useToast();\n const [name, setName] = useState('');\n const [suitePath, setSuitePath] = useState('');\n const [cron, setCron] = useState('');\n const [agent, setAgent] = useState('thor');\n const [submitting, setSubmitting] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!name || !suitePath || !cron) {\n toast.error('name, suitePath, and cron are required');\n return;\n }\n setSubmitting(true);\n try {\n const result = await api.post<EvalSchedule>('/eval/schedules', { name, suitePath, cron, agent });\n onAdded(result);\n toast.success('Schedule created');\n } catch (err) {\n toast.error(`Failed to create schedule: ${(err as Error).message}`);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form className=\"eval-schedule-form\" onSubmit={handleSubmit}>\n <div className=\"form-row\">\n <label htmlFor=\"sched-name\">Name</label>\n <input\n id=\"sched-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Daily fixture check\"\n required\n />\n </div>\n <div className=\"form-row\">\n <label htmlFor=\"sched-suite\">Suite path</label>\n <input\n id=\"sched-suite\"\n type=\"text\"\n value={suitePath}\n onChange={(e) => setSuitePath(e.target.value)}\n placeholder=\"./fixtures\"\n required\n />\n </div>\n <div className=\"form-row\">\n <label htmlFor=\"sched-cron\">Cron</label>\n <input\n id=\"sched-cron\"\n type=\"text\"\n value={cron}\n onChange={(e) => setCron(e.target.value)}\n placeholder=\"0 8 * * *\"\n required\n />\n </div>\n <div className=\"form-row\">\n <label htmlFor=\"sched-agent\">Agent</label>\n <input\n id=\"sched-agent\"\n type=\"text\"\n value={agent}\n onChange={(e) => setAgent(e.target.value)}\n placeholder=\"thor\"\n />\n </div>\n <div className=\"form-actions\">\n <Button type=\"submit\" variant=\"primary\" size=\"sm\" disabled={submitting}>\n {submitting ? 'Creating…' : 'Create schedule'}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n </div>\n </form>\n );\n}\n\nfunction EvalInner({ setActiveTab }: Props) {\n const toast = useToast();\n const [runs, setRuns] = useState<EvalRunSummary[]>([]);\n const [loading, setLoading] = useState(true);\n const [subTab, setSubTab] = useState<'runs' | 'schedules'>('runs');\n const [schedules, setSchedules] = useState<EvalSchedule[]>([]);\n const [loadingSchedules, setLoadingSchedules] = useState(false);\n const [showAddSchedule, setShowAddSchedule] = useState(false);\n const cancelledRef = useRef(false);\n\n const load = useCallback(async () => {\n setLoading(true);\n try {\n const r = await api.get<{ runs: EvalRunSummary[] }>(`/eval/runs?limit=${RECENT_RUNS_LIMIT}`);\n if (!cancelledRef.current) setRuns(r.runs || []);\n } catch (err) {\n if (!cancelledRef.current) {\n toast.error(`Failed to load eval runs: ${(err as Error).message}`);\n }\n } finally {\n if (!cancelledRef.current) setLoading(false);\n }\n }, [toast]);\n\n const loadSchedules = useCallback(async () => {\n setLoadingSchedules(true);\n try {\n const r = await api.get<{ schedules: EvalSchedule[] }>('/eval/schedules');\n if (!cancelledRef.current) setSchedules(r.schedules || []);\n } catch (err) {\n if (!cancelledRef.current) {\n toast.error(`Failed to load eval schedules: ${(err as Error).message}`);\n }\n } finally {\n if (!cancelledRef.current) setLoadingSchedules(false);\n }\n }, [toast]);\n\n useEffect(() => {\n cancelledRef.current = false;\n load();\n if (subTab === 'schedules') loadSchedules();\n return () => { cancelledRef.current = true; };\n }, [load, loadSchedules, subTab]);\n\n const deleteSchedule = async (id: string) => {\n try {\n await api.del(`/eval/schedules/${id}`);\n setSchedules((prev) => prev.filter((s) => s.id !== id));\n toast.success('Schedule deleted');\n } catch (err) {\n toast.error(`Failed to delete schedule: ${(err as Error).message}`);\n }\n };\n\n const recent = runs.slice(0, RECENT_RUNS_LIMIT);\n const totals = runs.reduce(\n (acc, r) => {\n acc.total += r.total;\n acc.passed += r.passed;\n acc.failed += r.failed;\n if (r.failed === 0) acc.fullPass += 1;\n return acc;\n },\n { total: 0, passed: 0, failed: 0, fullPass: 0 },\n );\n const overallRate = totals.total > 0 ? ((totals.passed / totals.total) * 100).toFixed(1) : '—';\n\n return (\n <div className=\"view view-eval\" data-testid=\"eval-overview\">\n <div className=\"view-header\">\n <div className=\"view-header-text\">\n <h1 className=\"view-title\">\n <ClipboardCheck size={20} aria-hidden /> Eval\n </h1>\n <p className=\"view-subtitle muted\">\n Track golden-fixture runs, catch regressions, and compare run history.\n </p>\n </div>\n <div className=\"view-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={load} disabled={loading}>\n {loading ? <Spinner size=\"sm\" /> : <RefreshCw size={12} />}\n {loading ? 'Refreshing…' : 'Refresh'}\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => setActiveTab('evalReport')}\n title=\"Open the full eval report\"\n >\n <ExternalLink size={12} /> Open Eval Report\n </Button>\n </div>\n </div>\n\n <div className=\"eval-summary-grid\">\n <Card className=\"eval-summary-card\">\n <CardTitle>Recent runs</CardTitle>\n <div className=\"eval-summary-value\">{runs.length}</div>\n <CardMeta className=\"muted\">\n Latest {RECENT_RUNS_LIMIT} runs across all suites.\n </CardMeta>\n </Card>\n <Card className=\"eval-summary-card\">\n <CardTitle>Fixtures run</CardTitle>\n <div className=\"eval-summary-value\">{totals.total}</div>\n <CardMeta className=\"muted\">\n <span className={cn('eval-rate', totals.failed === 0 ? 'is-pass' : 'is-fail')}>\n {overallRate}% pass rate\n </span>\n </CardMeta>\n </Card>\n <Card className=\"eval-summary-card\">\n <CardTitle>Clean runs</CardTitle>\n <div className=\"eval-summary-value\">{totals.fullPass}</div>\n <CardMeta className=\"muted\">\n Runs where every fixture passed.\n </CardMeta>\n </Card>\n <Card className=\"eval-summary-card eval-summary-cta\">\n <CardTitle>Compare runs</CardTitle>\n <CardMeta>\n Open the detailed report to diff two runs side-by-side and\n spot regressions fixture by fixture.\n </CardMeta>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => setActiveTab('evalReport')}\n className=\"eval-summary-cta-btn\"\n >\n Open report <ArrowRight size={12} />\n </Button>\n </Card>\n </div>\n\n <div className=\"eval-recent-section\">\n <div className=\"eval-sub-tabs\">\n <button\n type=\"button\"\n className={cn('eval-sub-tab', subTab === 'runs' ? 'is-active' : '')}\n onClick={() => setSubTab('runs')}\n >\n <ClipboardCheck size={12} aria-hidden /> Runs\n </button>\n <button\n type=\"button\"\n className={cn('eval-sub-tab', subTab === 'schedules' ? 'is-active' : '')}\n onClick={() => { setSubTab('schedules'); if (schedules.length === 0) loadSchedules(); }}\n >\n <Clock size={12} aria-hidden /> Schedules\n </button>\n </div>\n\n {subTab === 'runs' ? (\n <>\n <h2 className=\"eval-section-title\">Recent runs</h2>\n {loading && recent.length === 0 ? (\n <div className=\"eval-runs-loading\">\n <Spinner size=\"sm\" />\n <span className=\"muted\">Loading runs…</span>\n </div>\n ) : recent.length === 0 ? (\n <EmptyState\n icon={<ClipboardCheck size={28} />}\n title=\"No eval runs yet\"\n message={\n <>\n Run a suite via the CLI:{' '}\n <code className=\"mono\">bizar eval run ./path/to/fixtures</code>.\n Results will appear here.\n </>\n }\n />\n ) : (\n <div className=\"eval-runs-list\">\n {recent.map((r) => (\n <EvalRunCard key={r.id} run={r} />\n ))}\n </div>\n )}\n </>\n ) : (\n <>\n <h2 className=\"eval-section-title\">Schedules</h2>\n {loadingSchedules ? (\n <div className=\"eval-runs-loading\">\n <Spinner size=\"sm\" />\n <span className=\"muted\">Loading schedules…</span>\n </div>\n ) : schedules.length === 0 ? (\n <EmptyState\n icon={<Clock size={28} />}\n title=\"No eval schedules\"\n message=\"Schedules let you run eval suites automatically on a cron. Add one below.\"\n />\n ) : (\n <div className=\"eval-schedules-list\">\n {schedules.map((s) => (\n <Card key={s.id} className=\"eval-schedule-card\">\n <div className=\"eval-schedule-row\">\n <div className=\"eval-schedule-info\">\n <CardTitle>{s.name}</CardTitle>\n <CardMeta className=\"muted\">\n {s.cron} · {s.suitePath} · agent:{s.agent || 'thor'}\n </CardMeta>\n </div>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => deleteSchedule(s.id)}\n title=\"Delete schedule\"\n >\n <Trash2 size={12} aria-hidden />\n </Button>\n </div>\n </Card>\n ))}\n </div>\n )}\n <div className=\"eval-schedule-add\">\n <AddScheduleForm\n onAdded={(newSchedule) => {\n setSchedules((prev) => [...prev, newSchedule]);\n setShowAddSchedule(false);\n }}\n onCancel={() => setShowAddSchedule(false)}\n />\n {!showAddSchedule && (\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setShowAddSchedule(true)}>\n <Plus size={12} aria-hidden /> Add schedule\n </Button>\n )}\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n\nexport const Eval = React.memo(EvalInner);","// src/components/EvalDiff.tsx — v5.2.0\n//\n// Side-by-side comparison of two eval runs. Categorizes each fixture\n// as improved / regressed / unchanged and renders a summary block plus\n// a list of changed fixtures.\n//\n// `runA` is the \"before\" run (typically an older baseline); `runB` is\n// the \"after\" run (typically the newer run under review).\n\nimport type { ReactNode } from 'react';\nimport { cn } from '../lib/utils';\n\n/** Per-fixture result row embedded in a run record. */\nexport type EvalFixtureResult = {\n fixtureId: string;\n ok: boolean;\n checks?: { kind: string; ok: boolean; message?: string }[];\n latencyMs?: number;\n};\n\nexport type EvalRunWithResults = {\n id: string;\n startedAt: string;\n finishedAt?: string;\n suitePath?: string;\n total: number;\n passed: number;\n failed: number;\n results: EvalFixtureResult[];\n};\n\nexport type EvalDiffEntry = {\n fixtureId: string;\n /** The fixture's pass/fail status in the \"before\" run, or null if absent. */\n before: boolean | null;\n /** The fixture's pass/fail status in the \"after\" run, or null if absent. */\n after: boolean | null;\n /** Bucket label derived from before/after. */\n change: 'same' | 'improved' | 'regressed' | 'added' | 'removed';\n};\n\nexport type EvalDiffProps = {\n runA: EvalRunWithResults;\n runB: EvalRunWithResults;\n /**\n * Optional override for the section heading. Defaults to\n * \"Regression Analysis\".\n */\n title?: string;\n};\n\n/**\n * Pure helper: compute the diff entries from two runs. Exported so\n * tests can exercise the categorization logic without rendering.\n */\nexport function computeEvalDiff(\n runA: EvalRunWithResults,\n runB: EvalRunWithResults,\n): EvalDiffEntry[] {\n const mapA = new Map(runA.results.map((r) => [r.fixtureId, r]));\n const mapB = new Map(runB.results.map((r) => [r.fixtureId, r]));\n const ids = new Set<string>([...mapA.keys(), ...mapB.keys()]);\n\n const out: EvalDiffEntry[] = [];\n for (const id of ids) {\n const a = mapA.get(id);\n const b = mapB.get(id);\n const before = a ? a.ok : null;\n const after = b ? b.ok : null;\n\n let change: EvalDiffEntry['change'];\n if (a && b) {\n if (before === after) change = 'same';\n else if (before === false && after === true) change = 'improved';\n else change = 'regressed';\n } else if (b && !a) {\n change = 'added';\n } else {\n change = 'removed';\n }\n\n out.push({ fixtureId: id, before, after, change });\n }\n // Stable sort: regressions first, then improvements, then others.\n const order: Record<EvalDiffEntry['change'], number> = {\n regressed: 0,\n improved: 1,\n added: 2,\n removed: 3,\n same: 4,\n };\n out.sort((x, y) => {\n const d = order[x.change] - order[y.change];\n if (d !== 0) return d;\n return x.fixtureId.localeCompare(y.fixtureId);\n });\n return out;\n}\n\nexport function EvalDiff({ runA, runB, title = 'Regression Analysis' }: EvalDiffProps): ReactNode {\n const diff = computeEvalDiff(runA, runB);\n\n const improved = diff.filter((d) => d.change === 'improved').length;\n const regressed = diff.filter((d) => d.change === 'regressed').length;\n const unchanged = diff.filter((d) => d.change === 'same').length;\n const changed = diff.filter((d) => d.change !== 'same');\n\n return (\n <div className=\"eval-diff\" data-testid=\"eval-diff\">\n <h3 className=\"eval-diff-title\">{title}</h3>\n <div className=\"eval-diff-subtitle muted\">\n Comparing <code className=\"mono\">{runA.id}</code> →{' '}\n <code className=\"mono\">{runB.id}</code>\n </div>\n\n <div className=\"eval-diff-stats\" aria-label=\"Diff summary\">\n <span className=\"eval-diff-stat improved\">\n <span className=\"eval-diff-stat-icon\" aria-hidden>+</span>\n {improved} improved\n </span>\n <span className=\"eval-diff-stat regressed\">\n <span className=\"eval-diff-stat-icon\" aria-hidden>−</span>\n {regressed} regressed\n </span>\n <span className=\"eval-diff-stat unchanged muted\">\n {unchanged} unchanged\n </span>\n </div>\n\n {changed.length === 0 ? (\n <p className=\"eval-diff-empty muted\">No fixture-level changes between these runs.</p>\n ) : (\n <ul className=\"eval-diff-list\" role=\"list\">\n {changed.map((d) => (\n <li\n key={d.fixtureId}\n data-fixture-id={d.fixtureId}\n className={cn('eval-diff-row', `is-${d.change}`)}\n >\n <span className=\"eval-diff-fixture mono\">{d.fixtureId}</span>\n <span className=\"eval-diff-arrow\" aria-hidden>→</span>\n <span className=\"eval-diff-states\">\n <span className={cn('eval-diff-state', d.before ? 'is-pass' : 'is-fail')}>\n {d.before === null ? '—' : d.before ? 'pass' : 'fail'}\n </span>\n <span className=\"eval-diff-arrow-small\" aria-hidden>→</span>\n <span className={cn('eval-diff-state', d.after ? 'is-pass' : 'is-fail')}>\n {d.after === null ? '—' : d.after ? 'pass' : 'fail'}\n </span>\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}","// src/components/EvalExportButton.tsx — v5.3.0\n// Export button for downloading eval run results as CSV.\n\nimport React from 'react';\nimport { Download } from 'lucide-react';\nimport { Button } from './Button';\nimport { api } from '../lib/api';\n\ntype Props = {\n runId: string;\n variant?: 'primary' | 'secondary' | 'ghost';\n size?: 'sm' | 'md' | 'lg';\n};\n\nexport function EvalExportButton({ runId, variant = 'secondary', size = 'sm' }: Props) {\n const onExport = () => {\n const token = api.getToken();\n window.open(`/api/eval/runs/${encodeURIComponent(runId)}/export.csv?_t=${encodeURIComponent(token)}`, '_blank');\n };\n\n return (\n <Button variant={variant} size={size} onClick={onExport} title=\"Export results as CSV\">\n <Download size={14} aria-hidden />\n Export CSV\n </Button>\n );\n}\n","// src/views/EvalReport.tsx — v5.2.0\n//\n// Eval report dashboard view. Two columns:\n//\n// ┌────────────────┬───────────────────────────────────┐\n// │ Runs list │ Detail panel │\n// │ (EvalRunCard) │ - Run metadata + summary │\n// │ │ - Per-fixture pass/fail table │\n// │ │ - Optional EvalDiff (when a │\n// │ │ baseline run is selected) │\n// └────────────────┴───────────────────────────────────┘\n//\n// Data sources:\n// GET /api/eval/runs — list of recent runs\n// GET /api/eval/runs/:id — full run record\n// GET /api/eval/runs/:id/compare/:otherId — diff between two runs\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { ClipboardCheck, RefreshCw, ArrowLeftRight, X } from 'lucide-react';\nimport { Card, CardTitle, CardMeta } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { EmptyState } from '../components/EmptyState';\nimport { Spinner } from '../components/Spinner';\nimport { useToast } from '../components/Toast';\nimport { EvalRunCard, type EvalRunSummary } from '../components/EvalRunCard';\nimport {\n EvalDiff,\n computeEvalDiff,\n type EvalRunWithResults,\n type EvalFixtureResult,\n} from '../components/EvalDiff';\nimport { EvalExportButton } from '../components/EvalExportButton';\nimport { api } from '../lib/api';\nimport { cn, formatTime } from '../lib/utils';\nimport type { Settings, Snapshot } from '../lib/types';\n\ntype Props = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n};\n\nfunction RunDetail({\n run,\n onClearCompare,\n compareRun,\n onClearSelection,\n runsForDiff,\n}: {\n run: EvalRunWithResults;\n onClearCompare: () => void;\n compareRun: string | null;\n onClearSelection: () => void;\n runsForDiff: EvalRunWithResults[];\n}) {\n const passRate = run.total > 0 ? ((run.passed / run.total) * 100).toFixed(1) : '0.0';\n const sortedResults = [...run.results].sort((a, b) => {\n // Failures first, then by fixture id\n if (a.ok !== b.ok) return a.ok ? 1 : -1;\n return a.fixtureId.localeCompare(b.fixtureId);\n });\n\n return (\n <div className=\"eval-run-detail\" data-testid=\"eval-run-detail\">\n <Card className=\"eval-run-detail-header\">\n <div className=\"eval-run-detail-header-row\">\n <CardTitle>\n <ClipboardCheck size={14} aria-hidden /> {run.id}\n </CardTitle>\n <div className=\"eval-run-detail-actions\">\n <EvalExportButton runId={run.id} />\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearSelection} title=\"Close detail\">\n <X size={12} /> Close\n </Button>\n </div>\n </div>\n <CardMeta>\n {formatTime(run.startedAt)}\n {run.finishedAt ? ` → ${formatTime(run.finishedAt)}` : ''} · {run.suitePath}\n </CardMeta>\n <div className=\"eval-run-detail-summary\">\n <span className={cn('eval-status', run.failed === 0 ? 'is-pass' : 'is-fail')}>\n {run.passed}/{run.total} ({passRate}%)\n </span>\n <span className=\"muted\">\n {run.failed} failed · {run.passed} passed\n </span>\n </div>\n </Card>\n\n {compareRun ? (\n <Card className=\"eval-diff-card\">\n {(() => {\n const baseRun = runsForDiff.find((r) => r.id === compareRun);\n if (!baseRun) {\n return (\n <div className=\"eval-diff-missing muted\">\n Baseline run <code>{compareRun}</code> not loaded. Pick another from the list.\n </div>\n );\n }\n // Show \"before\" as the baseline (older) and \"after\" as the\n // currently-selected run (newer). Re-derive before/after\n // from the diff helper to drive the heading.\n const diff = computeEvalDiff(baseRun, run);\n const improved = diff.filter((d) => d.change === 'improved').length;\n const regressed = diff.filter((d) => d.change === 'regressed').length;\n return (\n <>\n <div className=\"eval-diff-card-head\">\n <span className=\"eval-diff-card-title\">\n <ArrowLeftRight size={14} aria-hidden /> Comparing {baseRun.id} → {run.id}\n </span>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearCompare}>\n <X size={12} /> Clear baseline\n </Button>\n </div>\n <div className=\"eval-diff-stats\" aria-label=\"Diff summary\">\n <span className=\"eval-diff-stat improved\">+{improved} improved</span>\n <span className=\"eval-diff-stat regressed\">−{regressed} regressed</span>\n </div>\n <EvalDiff runA={baseRun} runB={run} />\n </>\n );\n })()}\n </Card>\n ) : (\n <Card className=\"eval-baseline-hint\">\n <CardMeta>\n Tip: click another run in the list to use it as a baseline for diffing.\n </CardMeta>\n </Card>\n )}\n\n <Card className=\"eval-fixtures-card\">\n <CardTitle>Fixtures ({run.results.length})</CardTitle>\n {sortedResults.length === 0 ? (\n <CardMeta className=\"muted\">No fixture results in this run.</CardMeta>\n ) : (\n <ul className=\"eval-fixtures-list\" role=\"list\">\n {sortedResults.map((r) => (\n <li\n key={r.fixtureId}\n className={cn('eval-fixture-row', r.ok ? 'is-pass' : 'is-fail')}\n >\n <span\n className={cn('eval-fixture-pill', r.ok ? 'is-pass' : 'is-fail')}\n aria-label={r.ok ? 'pass' : 'fail'}\n >\n {r.ok ? '✓' : '✗'}\n </span>\n <span className=\"eval-fixture-id mono\">{r.fixtureId}</span>\n {!r.ok && r.checks ? (\n <span className=\"eval-fixture-fails muted\">\n {r.checks\n .filter((c) => !c.ok)\n .map((c) => c.message)\n .filter(Boolean)\n .join(' · ')}\n </span>\n ) : null}\n {r.latencyMs != null ? (\n <span className=\"eval-fixture-latency muted\">{Math.round(r.latencyMs)}ms</span>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </Card>\n </div>\n );\n}\n\nfunction EvalReportInner({ setActiveTab }: Props) {\n const toast = useToast();\n const [runs, setRuns] = useState<EvalRunSummary[]>([]);\n const [loadingRuns, setLoadingRuns] = useState(true);\n const [selectedRunId, setSelectedRunId] = useState<string | null>(null);\n const [compareRunId, setCompareRunId] = useState<string | null>(null);\n const [detail, setDetail] = useState<EvalRunWithResults | null>(null);\n const [detailLoading, setDetailLoading] = useState(false);\n const [compareDetail, setCompareDetail] = useState<EvalRunWithResults | null>(null);\n const cancelledRef = useRef(false);\n\n const loadRuns = useCallback(async () => {\n setLoadingRuns(true);\n try {\n const r = await api.get<{ runs: EvalRunSummary[] }>('/eval/runs');\n if (!cancelledRef.current) setRuns(r.runs || []);\n } catch (err) {\n if (!cancelledRef.current) {\n toast.error(`Failed to load eval runs: ${(err as Error).message}`);\n }\n } finally {\n if (!cancelledRef.current) setLoadingRuns(false);\n }\n }, [toast]);\n\n const loadDetail = useCallback(\n async (id: string) => {\n setDetailLoading(true);\n try {\n const r = await api.get<EvalRunWithResults>(`/eval/runs/${encodeURIComponent(id)}`);\n if (!cancelledRef.current) setDetail(r);\n } catch (err) {\n if (!cancelledRef.current) {\n toast.error(`Failed to load run ${id}: ${(err as Error).message}`);\n setDetail(null);\n }\n } finally {\n if (!cancelledRef.current) setDetailLoading(false);\n }\n },\n [toast],\n );\n\n const loadCompareDetail = useCallback(\n async (id: string) => {\n try {\n const r = await api.get<EvalRunWithResults>(`/eval/runs/${encodeURIComponent(id)}`);\n if (!cancelledRef.current) setCompareDetail(r);\n } catch (err) {\n if (!cancelledRef.current) {\n toast.error(`Failed to load run ${id}: ${(err as Error).message}`);\n setCompareDetail(null);\n }\n }\n },\n [toast],\n );\n\n // Initial fetch\n useEffect(() => {\n cancelledRef.current = false;\n loadRuns();\n return () => { cancelledRef.current = true; };\n }, [loadRuns]);\n\n const selectRun = async (id: string) => {\n if (id === selectedRunId) return;\n setSelectedRunId(id);\n setCompareRunId(null);\n setCompareDetail(null);\n await loadDetail(id);\n };\n\n const useAsBaseline = async (id: string) => {\n if (id === selectedRunId) return;\n setCompareRunId(id);\n await loadCompareDetail(id);\n };\n\n // Build the runsForDiff array — only the full records we actually\n // have loaded (selected + baseline). Anything else is unavailable\n // and the detail panel will show a \"not loaded\" hint.\n const runsForDiff: EvalRunWithResults[] = [];\n if (compareDetail) runsForDiff.push(compareDetail);\n if (detail) runsForDiff.push(detail);\n\n return (\n <div className=\"view view-eval-report\" data-testid=\"eval-report\">\n <div className=\"view-header\">\n <div className=\"view-header-text\">\n <h1 className=\"view-title\">\n <ClipboardCheck size={20} aria-hidden /> Eval Reports\n </h1>\n <p className=\"view-subtitle muted\">\n Browse eval runs, inspect per-fixture results, and diff two runs to spot regressions.\n </p>\n </div>\n <div className=\"view-actions\">\n <Button variant=\"secondary\" size=\"sm\" onClick={loadRuns} disabled={loadingRuns}>\n {loadingRuns ? <Spinner size=\"sm\" /> : <RefreshCw size={12} />}\n {loadingRuns ? 'Refreshing…' : 'Refresh'}\n </Button>\n </div>\n </div>\n\n <div className=\"eval-grid\">\n <div className=\"eval-runs-list\">\n {loadingRuns && runs.length === 0 ? (\n <div className=\"eval-runs-loading\">\n <Spinner size=\"sm\" />\n <span className=\"muted\">Loading runs…</span>\n </div>\n ) : runs.length === 0 ? (\n <EmptyState\n icon={<ClipboardCheck size={28} />}\n title=\"No eval runs yet\"\n message={\n <>\n Run a suite via the CLI:{' '}\n <code className=\"mono\">bizar eval run ./path/to/fixtures</code>.\n </>\n }\n />\n ) : (\n runs.map((r) => (\n <div key={r.id} className=\"eval-run-card-wrap\">\n <EvalRunCard\n run={r}\n selected={r.id === selectedRunId}\n onClick={() => selectRun(r.id)}\n />\n {selectedRunId && r.id !== selectedRunId ? (\n <button\n type=\"button\"\n className=\"eval-baseline-btn\"\n onClick={() => useAsBaseline(r.id)}\n title=\"Use this run as a baseline for diffing\"\n >\n <ArrowLeftRight size={10} aria-hidden />\n Use as baseline\n </button>\n ) : null}\n </div>\n ))\n )}\n </div>\n\n <div className=\"eval-detail\">\n {detailLoading && !detail ? (\n <div className=\"eval-detail-loading\">\n <Spinner size=\"sm\" />\n <span className=\"muted\">Loading run details…</span>\n </div>\n ) : detail ? (\n <RunDetail\n run={detail}\n compareRun={compareRunId}\n runsForDiff={runsForDiff}\n onClearCompare={() => { setCompareRunId(null); setCompareDetail(null); }}\n onClearSelection={() => { setSelectedRunId(null); setDetail(null); setCompareRunId(null); setCompareDetail(null); }}\n />\n ) : (\n <Card className=\"eval-detail-empty\">\n <EmptyState\n icon={<ClipboardCheck size={28} />}\n title=\"Select a run\"\n message=\"Pick an eval run from the list to view fixture-by-fixture results, latency, and per-check failure details.\"\n />\n </Card>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const EvalReport = React.memo(EvalReportInner);\nexport type { EvalFixtureResult };","// src/App.tsx — root shell. Wires data + contexts + tab routing.\n\nimport { Component, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { Topbar, TABS } from './components/Topbar';\nimport { Sidebar } from './components/Sidebar';\nimport { ModalProvider, useModal } from './components/Modal';\nimport { ToastProvider, useToast } from './components/Toast';\nimport { SearchModal } from './components/SearchModal';\nimport { Notifications } from './components/Notifications';\nimport { api, ApiError } from './lib/api';\nimport { CommandDialog, type DialogDescriptor } from './components/CommandDialog';\nimport { Ws } from './lib/ws';\nimport {\n applyTheme,\n applyThemeTokens,\n type Artifact,\n type Settings,\n type SettingsResponse,\n type Snapshot,\n type WsMessage,\n type WsStatus,\n type ProjectRecord,\n type SearchResult,\n} from './lib/types';\nimport { Overview } from './views/Overview';\nimport { Chat } from './views/Chat';\nimport { Agents } from './views/Agents';\nimport { Artifacts } from './views/Artifacts';\nimport { Tasks } from './views/Tasks';\nimport { Activity } from './views/Activity';\nimport { Config } from './views/Config';\nimport { SettingsView } from './views/Settings';\nimport { Marketplace } from './views/Marketplace';\nimport { Mods } from './views/Mods';\nimport { Plugins } from './views/Plugins';\nimport { ModView, type ModView as ModViewType } from './views/ModView';\nimport { Schedules } from './views/Schedules';\nimport { Skills } from './views/Skills';\nimport { Memory } from './views/Memory';\nimport { History } from './views/History';\nimport { MiniMaxUsage } from './views/MiniMaxUsage';\nimport { BackgroundAgents } from './views/BackgroundAgents';\nimport { Doctor } from './views/Doctor';\nimport { Eval } from './views/Eval';\nimport { EvalReport } from './views/EvalReport';\nimport { SettingsNav } from './components/SettingsNav';\nimport { Spinner } from './components/Spinner';\nimport { Button } from './components/Button';\nimport { AlertTriangle, Globe, LayoutTemplate, X } from 'lucide-react';\nimport './styles/main.css';\nimport './styles/settings.css';\n\ntype ViewProps = {\n snapshot: Snapshot;\n settings: Settings;\n activeTab: string;\n setActiveTab: (id: string) => void;\n refreshSnapshot: () => Promise<void>;\n /**\n * v4.9.0 — When true, the sidebar shows the full settings navigation\n * instead of the normal tab rail. Toggled by clicking the Settings tab.\n */\n settingsMode: boolean;\n /**\n * v4.9.0 — The active settings section highlighted in the sidebar nav.\n * Null means \"show all\". Managed at App level so Sidebar can read it.\n */\n settingsActiveSection: string | null;\n setSettingsActiveSection: (id: string | null) => void;\n /**\n * v3.3.0 — Cross-view scratch state. The \"Open in chat\" button\n * on the Agents tab sets `pendingInitialAgent`, which the Chat\n * view reads on mount (and clears). Keeps the chat a true\n * one-click handoff without needing URL state.\n */\n crossState?: CrossViewState;\n setCrossState?: (patch: Partial<CrossViewState>) => void;\n};\n\nexport type CrossViewState = {\n initialAgent?: string | null;\n};\n\nconst VIEW_MAP: Record<string, (p: ViewProps) => React.ReactNode> = {\n overview: Overview,\n chat: Chat,\n agents: Agents,\n artifacts: Artifacts,\n memory: Memory,\n tasks: Tasks,\n activity: Activity,\n background: BackgroundAgents,\n config: Config,\n settings: SettingsView,\n marketplace: Marketplace,\n mods: Mods,\n schedules: Schedules,\n skills: Skills,\n history: History,\n minimax: MiniMaxUsage,\n plugins: Plugins,\n // v6.0.0 — Doctor page (system health + diagnostics surface).\n // Registered here so the tab id 'doctor' from Topbar.tsx TABS\n // resolves to a real view instead of falling back to Overview.\n doctor: Doctor,\n // v5.2.0 — Eval framework web UI. `eval` is the sidebar tab\n // (recent runs summary), `evalReport` is reachable from the\n // Eval view's \"Open Eval Report\" button (full report + diff).\n eval: Eval,\n evalReport: EvalReport,\n};\n\nconst VERSION = 'v4.5.0';\n\n/**\n * Render the active view. If `activeTab` matches a built-in tab id,\n * use VIEW_MAP. If it matches a mod view id (any id not in VIEW_MAP),\n * render the ModView component with that view id.\n */\nfunction renderActiveView(\n activeTab: string,\n viewProps: ViewProps,\n modViews: ModViewType[],\n reloadKey: number,\n): React.ReactNode {\n if (VIEW_MAP[activeTab]) {\n const V = VIEW_MAP[activeTab];\n return <V {...viewProps} />;\n }\n // Mod view — find by id\n const mv = modViews.find((v) => v.id === activeTab);\n if (mv) {\n return (\n <ModView\n viewId={mv.id}\n reloadKey={reloadKey}\n activeTab={viewProps.activeTab}\n setActiveTab={viewProps.setActiveTab}\n />\n );\n }\n // Fallback to Overview\n const V = VIEW_MAP.overview;\n return <V {...viewProps} />;\n}\n\n// v3.6.2 — Inline token-entry form shown on the boot-error screen when\n// the server returns 401 (reverse-proxy / Tailscale Serve scenario).\n// The user pastes the token, it is saved to localStorage, and boot is\n// retried. The form closes on Escape or on successful save.\nfunction TokenEntryForm({ onSaved }: { onSaved: () => void }) {\n const [value, setValue] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Auto-focus the input on mount\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n const submit = () => {\n const tok = value.trim();\n if (!tok) return;\n api.setToken(tok);\n onSaved();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onSaved();\n }\n if (e.key === 'Enter') {\n e.preventDefault();\n submit();\n }\n };\n\n return (\n <form\n className=\"token-entry-form\"\n onSubmit={(e) => { e.preventDefault(); submit(); }}\n >\n <div className=\"token-entry-row\">\n <input\n ref={inputRef}\n type=\"password\"\n className=\"input mono\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Paste auth token\"\n spellCheck={false}\n autoComplete=\"off\"\n onKeyDown={handleKeyDown}\n />\n <Button type=\"submit\" variant=\"primary\" size=\"sm\" disabled={!value.trim()}>\n Save & retry\n </Button>\n </div>\n <p className=\"token-entry-hint\">\n Where do I find this token? Check the file{' '}\n <code>~/.config/bizar/dashboard-secret</code> on the machine\n running the dashboard, or look for it in the server output.\n </p>\n </form>\n );\n}\n\nexport function App() {\n return (\n <ToastProvider>\n <ModalProvider>\n <Shell />\n </ModalProvider>\n </ToastProvider>\n );\n}\n\nfunction Shell() {\n const toast = useToast();\n const modalApi = useModal();\n const { isModalOpen } = modalApi;\n const isModalOpenRef = useRef(false);\n const [activeTab, setActiveTab] = useState<string>('overview');\n const [snapshot, setSnapshot] = useState<Snapshot | null>(null);\n const [settings, setSettings] = useState<Settings | null>(null);\n const [wsStatus, setWsStatus] = useState<WsStatus>('connecting');\n const [bootError, setBootError] = useState<string | null>(null);\n // v4.9.0 — Settings mode: when true, sidebar shows all settings sections\n const [settingsMode, setSettingsMode] = useState(false);\n // v4.9.0 — The active settings section shown in the sidebar nav.\n // Null means \"show all sections\". Managed here so Sidebar can read it.\n const [settingsActiveSection, setSettingsActiveSection] = useState<string | null>(null);\n const [authPromptOpen, setAuthPromptOpen] = useState(false);\n const [searchOpen, setSearchOpen] = useState(false);\n const [stuckAgents, setStuckAgents] = useState<{ name: string }[]>([]);\n const [stuckBannerDismissed, setStuckBannerDismissed] = useState(false);\n // v3.20.3 — Mod views become first-class nav entries. Fetched on mount\n // and after every mod install/uninstall/enable toggle.\n const [modViews, setModViews] = useState<ModViewType[]>([]);\n const [modViewsReloadKey, setModViewsReloadKey] = useState(0);\n const wsRef = useRef<Ws | null>(null);\n const [ws, setWs] = useState<Ws | null>(null);\n\n // Fetch installed mod views (any enabled mod with a web/index.html or\n // a views/registry.json entry). These become top-level nav tabs.\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const r = await api.get<{ views: ModViewType[] }>('/mods/views');\n if (cancelled) return;\n setModViews(r.views || []);\n } catch {\n if (!cancelled) setModViews([]);\n }\n })();\n return () => { cancelled = true; };\n }, [modViewsReloadKey, snapshot?.mods]);\n\n // Re-fetch mod views when ws events arrive about mod changes.\n useEffect(() => {\n if (!ws) return;\n const off = ws.on((msg: { type?: string }) => {\n if (msg?.type === 'mod:change' || msg?.type === 'mod:enabled' || msg?.type === 'mod:installed') {\n setModViewsReloadKey((n) => n + 1);\n }\n });\n return () => off();\n }, [ws]);\n\n // Apply theme tokens\n useEffect(() => {\n if (settings?.theme) {\n applyTheme(settings.theme);\n applyThemeTokens(settings.theme);\n }\n }, [settings?.theme]);\n\n // v3.6.1 — Keep a ref in sync with isModalOpen so the keyboard handler\n // always reads the current value even between state updates and effect\n // re-runs. This closes the race window where modal.close() has cleared\n // the state but the old keyboard handler (with isModalOpen=false in\n // its closure) hasn't been replaced yet.\n useEffect(() => {\n isModalOpenRef.current = isModalOpen;\n }, [isModalOpen]);\n\n // System-mode listener\n useEffect(() => {\n if (settings?.theme?.mode !== 'system') return;\n const mql = window.matchMedia('(prefers-color-scheme: light)');\n const handler = () => applyTheme(settings.theme.mode);\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n }, [settings?.theme?.mode]);\n\n // v3.6.2 — Boot logic extracted to retryBoot so it can be re-invoked\n // after the user pastes a token in the inline recovery form.\n const retryBoot = useCallback(async () => {\n let cancelled = false;\n\n const loadBootData = () =>\n Promise.all([\n api.get<Snapshot>('/snapshot').catch(() => null),\n api.get<SettingsResponse>('/settings').catch(() => null),\n api.get<{ stuck: { name: string }[] }>('/agents/stuck').catch(() => null),\n ]);\n\n const applyBootData = (\n snap: Snapshot | null,\n set: SettingsResponse | null,\n stuck: { stuck: { name: string }[] } | null,\n ) => {\n if (snap) setSnapshot(snap);\n if (set?.data) setSettings(set.data);\n if (stuck?.stuck) setStuckAgents(stuck.stuck);\n };\n\n try {\n const auth = await api.probeAuthStatus();\n const [snap, set, stuck] = await loadBootData();\n if (cancelled) return;\n\n applyBootData(snap, set, stuck);\n if (snap || set) {\n setBootError(null);\n return;\n }\n\n if (!auth.loopback) {\n setBootError('Dashboard server unreachable.');\n return;\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1000));\n if (cancelled) return;\n\n const [retrySnap, retrySet, retryStuck] = await loadBootData();\n if (cancelled) return;\n\n applyBootData(retrySnap, retrySet, retryStuck);\n if (!retrySnap && !retrySet) {\n setBootError('Dashboard server unreachable.');\n }\n } catch (err) {\n if (cancelled) return;\n const msg = (err as Error)?.message ?? 'unknown error';\n // v3.6.2 — If we got a 401, the user needs to supply a token.\n // Surface the form inline instead of just the error message.\n if (err instanceof ApiError && err.status === 401) {\n setBootError(msg);\n setAuthPromptOpen(true);\n toast.error(`Auth required: ${msg}`);\n return;\n }\n setBootError(msg);\n toast.error(`Failed to load: ${msg}`);\n }\n }, [toast]);\n\n // Initial fetch — runs once on mount\n useEffect(() => {\n let cancelled = false;\n const id = setTimeout(() => {\n if (!cancelled) retryBoot();\n }, 0);\n return () => {\n cancelled = true;\n clearTimeout(id);\n };\n }, [retryBoot]);\n\n // Apply defaultTab ONCE on mount only — must NOT re-fire on toast changes\n useEffect(() => {\n let cancelled = false;\n api.get<SettingsResponse>('/settings')\n .then((set) => {\n if (cancelled) return;\n const defaultTab = set?.data?.ui?.defaultTab;\n if (defaultTab) setActiveTab(defaultTab);\n })\n .catch(() => undefined);\n return () => {\n cancelled = true;\n };\n }, []); // empty deps — runs once on mount\n\n // v3.1.0 — Periodic stuck-agent poll. Light-weight; the server does\n // the threshold math and only returns the list.\n useEffect(() => {\n let cancelled = false;\n const tick = async () => {\n try {\n const r = await api.get<{ stuck: { name: string }[] }>('/agents/stuck');\n if (!cancelled) {\n setStuckAgents((cur) => {\n const next = r.stuck || [];\n const wasEmpty = cur.length === 0;\n if (wasEmpty && next.length > 0) {\n toast.warning(`${next.length} agent${next.length === 1 ? '' : 's'} stuck`, 5000);\n }\n return next;\n });\n }\n } catch {\n /* best-effort */\n }\n };\n const id = setInterval(tick, 30_000);\n tick();\n return () => {\n cancelled = true;\n clearInterval(id);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // WebSocket lifecycle\n useEffect(() => {\n const ws = new Ws();\n wsRef.current = ws;\n setWs(ws);\n const offStatus = ws.onStatus((s) => setWsStatus(s));\n const offMsg = ws.on((msg: WsMessage) => {\n if (msg.type === 'snapshot' && 'data' in msg && msg.data) {\n setSnapshot((cur) => ({ ...(cur ?? ({} as Snapshot)), ...msg.data }));\n } else if (msg.type === 'change') {\n const m = msg;\n const file = m.path?.split('/').pop() || m.path || '';\n toast.info(`File changed: ${file}`, 2500);\n } else if (msg.type === 'tasks:change') {\n const m = msg;\n setSnapshot((cur) => {\n if (!cur) return cur;\n const tasks = (cur.tasks || []).map((t) =>\n t.id === m.task.id ? m.task : t,\n );\n const exists = tasks.some((t) => t.id === m.task.id);\n return { ...cur, tasks: exists ? tasks : [m.task, ...tasks] };\n });\n } else if (msg.type === 'tasks:delete') {\n const m = msg;\n setSnapshot((cur) =>\n cur\n ? { ...cur, tasks: (cur.tasks || []).filter((t) => t.id !== m.id) }\n : cur,\n );\n } else if (msg.type === 'settings:change') {\n const m = msg;\n if (m.settings) setSettings(m.settings);\n } else if (msg.type === 'project:change') {\n // Refresh the whole snapshot to pick up the new active project\n api\n .get<Snapshot>('/snapshot')\n .then((s) => setSnapshot((cur) => ({ ...(cur ?? ({} as Snapshot)), ...s })))\n .catch(() => undefined);\n } else if (msg.type === 'agents:change' || msg.type === 'schedules:change') {\n api\n .get<Snapshot>('/snapshot')\n .then((s) => setSnapshot((cur) => ({ ...(cur ?? ({} as Snapshot)), ...s })))\n .catch(() => undefined);\n } else if (msg.type === 'agent:status' || msg.type === 'agent:restarted') {\n const m = msg;\n setSnapshot((cur) => {\n if (!cur) return cur;\n const agents = (cur.agents || []).map((a) => (a.name === m.agent.name ? m.agent : a));\n return { ...cur, agents };\n });\n } else if (msg.type === 'artifact:change') {\n // Artifacts list refreshes after any artifact mutation.\n api\n .get<{ artifacts: Artifact[] }>('/artifacts')\n .then((d) => {\n setSnapshot((cur) => (cur ? { ...cur, artifacts: d.artifacts || [] } : cur));\n })\n .catch(() => undefined);\n } else if (msg.type === 'agent:stuck') {\n const m = msg;\n setStuckAgents(m.agents || []);\n } else if (msg.type === 'dialog:show') {\n // v0.5.1: Open a command dialog received from the plugin via WS broadcast.\n const m = msg as { type: 'dialog:show'; dialog: DialogDescriptor };\n if (m.dialog) {\n modalApi.open({\n title: m.dialog.title,\n width: 520,\n children: <CommandDialog dialog={m.dialog} onClose={() => modalApi.close()} />,\n });\n }\n }\n });\n return () => {\n offStatus();\n offMsg();\n ws.close();\n setWs(null);\n };\n }, [toast]);\n\n const subscribeToWs = useCallback((cb: (msg: WsMessage) => void) => {\n if (!ws) return () => undefined;\n return ws.on(cb);\n }, [ws]);\n\n // v3.3.1 — Track recent user interactions. After any mousedown/click/\n // focusin/keydown we set a 1500ms \"safe\" window during which digit-key\n // shortcuts are suppressed. This protects against the case where a modal\n // closes on a click and the user's next key event (often a key-repeat)\n // would otherwise trigger setActiveTab(\"overview\").\n // v3.3.0 used 250ms which was too short (keyboard repeat can fire later).\n //\n // v3.5.4 (bug #4) — The safe window alone was not enough. Users were\n // still being bounced to overview after action grace windows expired\n // because the transientFocus check (activeElement === body) was nested\n // inside the safe-window branch. See the handler below for the new\n // two-gate model: (1) body/null focus ALWAYS blocks digit shortcuts;\n // (2) the safe window relaxes that block only for the first 1500ms\n // after an interaction. After the window passes, the user must\n // explicitly focus a real element before digit-key tab switches work.\n const safeUntilRef = useRef(0);\n useEffect(() => {\n const bump = () => {\n safeUntilRef.current = Date.now() + 1500;\n };\n document.addEventListener('mousedown', bump, true);\n document.addEventListener('click', bump, true);\n document.addEventListener('focusin', bump, true);\n document.addEventListener('keydown', bump, true);\n return () => {\n document.removeEventListener('mousedown', bump, true);\n document.removeEventListener('click', bump, true);\n document.removeEventListener('focusin', bump, true);\n document.removeEventListener('keydown', bump, true);\n };\n }, []);\n\n // Keyboard shortcuts\n useEffect(() => {\n const map: Record<string, string> = {};\n TABS.forEach((t, i) => {\n map[String(i + 1)] = t.id;\n });\n const handler = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n setSearchOpen(true);\n return;\n }\n if (e.key === '/' && !e.metaKey && !e.ctrlKey) {\n const t = (e.target as HTMLElement | null)?.tagName?.toLowerCase();\n if (t !== 'input' && t !== 'textarea' && !((e.target as HTMLElement)?.isContentEditable)) {\n e.preventDefault();\n setSearchOpen(true);\n return;\n }\n }\n // v3.2.0 — broader guard. Digit-key shortcuts must not fire while\n // the user is interacting with ANY focusable form control or a\n // modal/contentEditable region. Previously this only excluded\n // <input> and <textarea>, which let digit presses through when\n // focus was on a <select>, <button>, <label>, or contenteditable\n // node — causing mysterious tab switches (most often back to\n // \"overview\" via the `1` shortcut).\n //\n // v3.3.1 — \"click after modal close\" guard (extended). When a modal\n // closes (e.g. the user clicks \"Submit to Odin\" in the Tasks tab),\n // React portals the modal out of the DOM and the previously-focused\n // button is unmounted. Focus falls back to <body>. If the user then\n // accidentally taps a digit key (1/2/3/...) — or a key-repeat fires\n // while they're still mid-click — the handler would switch tabs.\n // The safe window is now 1500ms (up from 250ms) and covers all\n // interaction types (mousedown/click/focusin/keydown).\n //\n // v3.3.1 — transient-focus check. If active element is body/null,\n // treat it as a transient focus state (modal close → body fallback)\n // and bail. v3.5.4 (bug #4): this check is now independent of the\n // safe window — it ALWAYS applies. Previously it was only effective\n // inside the 1500ms grace window, which let digit-key presses through\n // once the window expired. The user would see themselves bounced back\n // to overview (digit `1`) after every action whose grace window had\n // already elapsed. The safe window now only relaxes the rule\n // temporarily for the action that JUST happened; it must be combined\n // with a real focus element for digit-key shortcuts to fire.\n const activeEl = document.activeElement;\n const transientFocus = !activeEl || activeEl === document.body || activeEl === document.documentElement;\n if (transientFocus) {\n // Even within the grace window, body/null focus means there is\n // no real input target — refuse to switch tabs. The user must\n // explicitly click into a focusable element (input, button, etc.)\n // to enable digit-key tab switching again.\n return;\n }\n const target = e.target as HTMLElement | null;\n const tag = target?.tagName?.toLowerCase();\n const isFormControl =\n tag === 'input' ||\n tag === 'textarea' ||\n tag === 'select' ||\n tag === 'button' ||\n tag === 'option' ||\n tag === 'label' ||\n !!target?.isContentEditable;\n // Inside a form? Even safer: walk up to check.\n let inForm = false;\n if (target && typeof target.closest === 'function') {\n inForm = !!target.closest('form, [role=\"dialog\"], [contenteditable], [data-no-key]');\n }\n // v3.5.2 — reject key-repeat events. When a user presses and holds\n // a digit key the browser fires repeated keydown events; we must only\n // act on the first (e.repeat === false). This prevents the modal-close\n // + key-repeat scenario from switching tabs after the safe window closes.\n if (e.repeat) return;\n // v3.6.1 — Check isModalOpenRef (not the closure variable) so we always\n // see the current value even between state update and effect re-run.\n if (isModalOpenRef.current) return;\n if (\n isFormControl ||\n inForm ||\n e.metaKey ||\n e.ctrlKey ||\n e.altKey ||\n e.shiftKey ||\n Date.now() < safeUntilRef.current\n )\n return;\n const id = map[e.key];\n if (id) {\n e.preventDefault();\n handleTabChange(id);\n }\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, []);\n\n const refreshSnapshot = useMemo(\n () => async () => {\n try {\n const s = await api.get<Snapshot>('/snapshot');\n setSnapshot((cur) => ({ ...(cur ?? ({} as Snapshot)), ...s }));\n } catch (err) {\n toast.error(`Refresh failed: ${(err as Error).message}`);\n }\n },\n [toast],\n );\n\n // v4.9.0 — Settings mode: entering settings tab activates the sidebar layout.\n // Navigating to any other tab exits settings mode.\n const handleTabChange = useCallback((id: string) => {\n setActiveTab(id);\n if (id === 'settings') setSettingsMode(true);\n else setSettingsMode(false);\n }, []);\n\n // v3.20.3 — Merge built-in tabs with installed mod views. Mod views\n // are appended after the built-in tabs and use the same rendering\n // surface; their tab ids are mod view ids (e.g. 'graphify:web').\n // Declared AFTER refreshSnapshot so the deps list has the right value.\n const mergedTabs = useMemo(() => {\n const modTabs = modViews.map((v) => ({\n id: v.id,\n label: v.label,\n icon: v.kind === 'iframe' ? Globe : LayoutTemplate,\n isMod: true,\n modId: v.modId,\n }));\n return [...TABS, ...modTabs];\n }, [modViews]);\n\n // Surface the underlying view for the active tab (built-in or mod).\n // Declared AFTER refreshSnapshot so its useMemo factory can capture it.\n const renderedView = useMemo(() => {\n if (snapshot && settings) {\n const viewProps: ViewProps = {\n snapshot,\n settings,\n activeTab,\n setActiveTab: handleTabChange,\n refreshSnapshot,\n settingsMode,\n settingsActiveSection,\n setSettingsActiveSection,\n };\n return renderActiveView(activeTab, viewProps, modViews, modViewsReloadKey);\n }\n return null;\n }, [activeTab, snapshot, settings, modViews, modViewsReloadKey, refreshSnapshot, settingsMode, settingsActiveSection, setSettingsActiveSection, handleTabChange]);\n\n const refreshProjects = async () => {\n try {\n const r = await api.get<{ projects: ProjectRecord[]; active: string | null }>('/projects');\n setSnapshot((cur) =>\n cur ? { ...cur, projects: r.projects || [], activeProject: r.projects?.find((p) => p.id === r.active) || null } : cur,\n );\n } catch (err) {\n toast.error(`Projects refresh failed: ${(err as Error).message}`);\n }\n };\n\n const onActivateProject = async (id: string) => {\n try {\n await api.post(`/projects/${encodeURIComponent(id)}/activate`);\n // WS will fire project:change and refresh; but also reflect locally\n setSnapshot((cur) => {\n if (!cur) return cur;\n return {\n ...cur,\n activeProject: cur.projects.find((p) => p.id === id) || null,\n };\n });\n } catch (err) {\n toast.error(`Activate failed: ${(err as Error).message}`);\n }\n };\n\n const onSearchSelect = (r: SearchResult) => {\n const t = r.type;\n if (t === 'agent') handleTabChange('agents');\n else if (t === 'task') handleTabChange('tasks');\n else if (t === 'mod') handleTabChange('mods');\n else if (t === 'schedule') handleTabChange('schedules');\n else if (t === 'project') {\n const id = (r.item as ProjectRecord).id;\n onActivateProject(id);\n } else if (t === 'command') {\n // No command page; just toast\n toast.info(`/${(r.item as { name: string }).name} — run from the TUI`, 2500);\n } else if (t === 'setting') {\n // v3.0.4 — Jump to Settings view and scroll to the matching row.\n const settingId = (r.item as { id?: string; path?: string }).id\n || (r.item as { path?: string }).path\n || '';\n handleTabChange('settings');\n // Defer the scroll to allow the view to mount, then apply a brief\n // CSS highlight. We poll a few times because the Settings view\n // mounts lazily after tab switch.\n const tryScroll = (tries: number) => {\n if (tries <= 0) return;\n const el = settingId\n ? document.querySelector(`[data-setting-id=\"${CSS.escape(settingId)}\"]`)\n : null;\n if (el) {\n (el as HTMLElement).scrollIntoView({ behavior: 'smooth', block: 'center' });\n el.classList.remove('setting-flash');\n // Force reflow so the animation re-triggers on rapid jumps.\n void (el as HTMLElement).offsetWidth;\n el.classList.add('setting-flash');\n window.setTimeout(() => el.classList.remove('setting-flash'), 1500);\n } else {\n window.setTimeout(() => tryScroll(tries - 1), 80);\n }\n };\n window.setTimeout(() => tryScroll(15), 60);\n }\n };\n\n const layout = settings?.ui?.layout || 'topnav';\n const showHeader = settings?.ui?.showHeader !== false;\n\n return (\n <div className=\"app\" data-layout={layout} data-active-tab={activeTab}>\n {/* v4.8.0 — WCAG 2.2 AA: skip-to-main-content link. Hidden visually\n until focused; clicking moves keyboard focus past the nav into\n the active view. Screen readers and keyboard users can jump\n past the topbar + sidebar without tabbing through every tab. */}\n <a className=\"skip-to-main\" href=\"#main-content\">\n Skip to main content\n </a>\n {showHeader && (\n <Topbar\n activeTab={activeTab}\n onTabChange={handleTabChange}\n wsStatus={wsStatus}\n version={VERSION}\n activeProject={snapshot?.activeProject || null}\n projects={snapshot?.projects || []}\n onProjectChange={onActivateProject}\n onProjectsRefresh={refreshProjects}\n onOpenSearch={() => setSearchOpen(true)}\n settings={settings}\n notificationsSlot={<Notifications wsSubscribe={subscribeToWs} />}\n showTabs={layout === 'topnav'}\n extraTabs={mergedTabs}\n />\n )}\n {stuckAgents.length > 0 && !stuckBannerDismissed && (\n <div className=\"stuck-banner\" role=\"alert\">\n <AlertTriangle size={16} />\n <span>\n <strong>{stuckAgents.length}</strong> agent{stuckAgents.length === 1 ? '' : 's'} stuck:{' '}\n <span className=\"mono\">\n {stuckAgents.map((a) => a.name).join(', ')}\n </span>\n </span>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n handleTabChange('agents');\n setStuckBannerDismissed(true);\n }}\n >\n Review\n </Button>\n <button\n type=\"button\"\n className=\"icon-btn\"\n aria-label=\"Dismiss\"\n onClick={() => setStuckBannerDismissed(true)}\n >\n <X size={14} />\n </button>\n </div>\n )}\n <div className=\"layout-body\">\n {layout !== 'topnav' && (\n <Sidebar\n tabs={mergedTabs}\n activeTab={activeTab}\n onTabChange={handleTabChange}\n settingsMode={settingsMode}\n settingsActiveSection={settingsActiveSection}\n onSettingsSectionChange={setSettingsActiveSection}\n onExitSettings={() => handleTabChange('overview')}\n />\n )}\n <main className=\"content\" id=\"main-content\" tabIndex={-1}>\n {bootError && (\n <div className=\"boot-error\">\n <h2>Dashboard unavailable</h2>\n <p>{bootError}</p>\n {authPromptOpen && (\n <TokenEntryForm\n onSaved={() => {\n setAuthPromptOpen(false);\n retryBoot();\n }}\n />\n )}\n <p className=\"boot-error-hint\">\n Make sure the Bizar dashboard server is running. Try{' '}\n <code>bizar-dash start</code> in your terminal.\n </p>\n </div>\n )}\n {!bootError && (!snapshot || !settings) && (\n <div className=\"loading\">\n <Spinner size=\"lg\" />\n <p>Loading Bizar…</p>\n </div>\n )}\n {renderedView && (\n <Suspense fallback={<div className=\"loading\"><Spinner size=\"lg\" /><p>Loading…</p></div>}>\n <ViewErrorBoundary>{renderedView}</ViewErrorBoundary>\n </Suspense>\n )}\n </main>\n </div>\n <SearchModal\n open={searchOpen}\n onClose={() => setSearchOpen(false)}\n onSelect={onSearchSelect}\n />\n </div>\n );\n}\n\n// v4.5.x — Catches render-time errors in the active view so a single bad\n// component doesn't bring down the whole dashboard (topbar, sidebar, WS).\n// Falls back to a friendly error card with a Retry button that re-mounts\n// the wrapped subtree by remounting the boundary via React `key` bumps.\nclass ViewErrorBoundary extends Component<\n { children: React.ReactNode },\n { err: Error | null }\n> {\n state: { err: Error | null } = { err: null };\n static getDerivedStateFromError(err: Error): { err: Error | null } {\n return { err };\n }\n componentDidCatch(err: Error, info: { componentStack?: string }) {\n // eslint-disable-next-line no-console\n console.error('[ViewErrorBoundary] caught render error:', err, info?.componentStack);\n }\n reset = () => this.setState({ err: null });\n override render() {\n if (this.state.err) {\n return (\n <div className=\"view-error-fallback\" role=\"alert\">\n <AlertTriangle size={20} />\n <div className=\"view-error-body\">\n <strong>This view crashed.</strong>\n <pre>{this.state.err.message}</pre>\n <Button variant=\"secondary\" size=\"sm\" onClick={this.reset}>Retry</Button>\n </div>\n </div>\n );\n }\n return this.props.children;\n }\n}\n","// src/main.tsx — viewport-based entry: mobile or desktop\nimport { StrictMode, useEffect, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { App } from './App';\nimport { MobileApp } from './MobileApp';\nimport en from './locales/en.json';\nimport { setLocale } from './lib/i18n';\n\n// Initialize i18n\nsetLocale('en', en);\n// Import mobile CSS so the MobileApp renders with styles when served\n// from index.html (e.g. when the auto-redirect to /m is bypassed).\nimport './styles/main.css';\nimport './styles/mobile.css';\nimport './styles/mobile-layout.css';\nimport './styles/glyphs.css';\nimport './styles/minimax-usage.css';\nimport './styles/skills.css';\nimport './styles/memory.css';\n\nfunction Root() {\n const [isMobile, setIsMobile] = useState(() => {\n if (typeof window === 'undefined') return false;\n return window.matchMedia('(max-width: 767px)').matches;\n });\n\n useEffect(() => {\n const mql = window.matchMedia('(max-width: 767px)');\n const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches);\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n }, []);\n\n return isMobile ? <MobileApp /> : <App />;\n}\n\nconst root = document.getElementById('root');\nif (!root) throw new Error('Root element #root not found');\ncreateRoot(root).render(\n <StrictMode>\n <Root />\n </StrictMode>,\n);\n"],"file":"assets/main-dq0UZN8-.js"}
|