Framework update — Phase 1 (detect + install, no handoff)#233
Framework update — Phase 1 (detect + install, no handoff)#233
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 17 minutes and 7 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughIntroduces a framework update feature for agents with API helpers, a new FrameworkTab component for managing updates with status polling, integration of update-availability indicators in the AgentsApp and StoreApp, and rebuilding of bundled static assets with updated module hashes. Changes
Sequence DiagramsequenceDiagram
participant User
participant FrameworkTab
participant framework-api
participant Backend
participant UI
User->>FrameworkTab: Load agent framework state
FrameworkTab->>framework-api: fetchFrameworkState(agent.name)
framework-api->>Backend: GET /api/agents/{name}/framework
Backend-->>framework-api: FrameworkState
framework-api-->>FrameworkTab: FrameworkState
FrameworkTab->>UI: Render (update available/idle)
User->>FrameworkTab: Click "Update Framework"
FrameworkTab->>FrameworkTab: Show confirmation modal
User->>FrameworkTab: Confirm update
FrameworkTab->>framework-api: startFrameworkUpdate(agent.name, version)
framework-api->>Backend: POST /api/agents/{name}/framework/update
Backend-->>framework-api: Response
FrameworkTab->>FrameworkTab: Set state to "updating"
rect rgba(100, 150, 200, 0.5)
Note over FrameworkTab,UI: Polling every 2 seconds
loop While updating
FrameworkTab->>framework-api: fetchFrameworkState(agent.name)
framework-api->>Backend: GET /api/agents/{name}/framework
Backend-->>framework-api: FrameworkState (status)
framework-api-->>FrameworkTab: FrameworkState
FrameworkTab->>UI: Update elapsed timer & status
end
end
Backend->>Backend: Update completes
FrameworkTab->>framework-api: Final fetchFrameworkState
framework-api-->>FrameworkTab: status="idle"
FrameworkTab->>UI: Render success or failure
FrameworkTab->>User: Invoke onUpdated callback
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
| <div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50"> | ||
| <div className="bg-shell-bg border border-white/10 rounded p-4 max-w-sm"> | ||
| <p className="text-sm mb-3"> | ||
| Update {agent.name}'s {state.framework} to <code>{state.latest?.tag}</code>? |
There was a problem hiding this comment.
SUGGESTION: Handle case where state.latest?.tag is null to avoid displaying 'undefined' in the confirmation dialog.
| Update {agent.name}'s {state.framework} to <code>{state.latest?.tag}</code>? | |
| Update {agent.name}'s {state.framework} to <code>{state.latest?.tag ?? "latest"}</code>? |
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Overview
Issue Details (click to expand)No issues found. Files Reviewed (13 files)
Fix these issues in Kilo Cloud Reviewed by grok-code-fast-1:optimized:free · 362,851 tokens |
…I incorrectly pruned
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (2)
static/desktop/assets/BrowserApp-Bb5zltov.js (1)
1-1: This is minified build output — source files should be reviewed instead.This file is a bundled/minified JavaScript artifact generated by the build toolchain. Meaningful code review should target the original source files (likely
.tsxor.tsin asrc/directory) rather than transpiled output.If the source files are part of this PR but not included in the review, please add them. If this bundle is committed solely to track build output, consider whether it should be in
.gitignoreand served from a build pipeline instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@static/desktop/assets/BrowserApp-Bb5zltov.js` at line 1, The reviewed file is a minified build artifact (BrowserApp exported as we) and should not be reviewed directly; update the PR to include the original source (e.g., the React/TSX component that compiles to BrowserApp/we) or remove this bundle from the commit and add it to .gitignore; if the intent is to ship built artifacts, move them to a dedicated build/output directory and document the generation step in the CI pipeline so reviewers can inspect the source (look for the component that defines useState/useCallback handlers like O, X, te and the exported BrowserApp/we).static/desktop/assets/ImportApp-AV3jmR5U.js (1)
1-1: Silent error handling hides upload failures from users.The upload loop catches errors silently:
try{await fetch("/api/import/upload",{method:"POST",body:n})}catch{}If an individual file upload fails (network error, server error), the user sees a success message like "Uploaded 3 files" even though some may have failed. Consider tracking failures and reporting them in the status message.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@static/desktop/assets/ImportApp-AV3jmR5U.js` at line 1, The upload loop in function T silently swallows errors and doesn't check response.ok, causing false "Uploaded X files" messages; modify T (the async upload function) to track per-file failures by checking the fetch response.ok and catching exceptions to increment a failure counter and collect failed file names (use the existing i array items like a.file/a.name), update progress v as before, and at the end call o(...) with a final status that includes succeeded vs failed counts and names (e.g., "Uploaded 2 of 3 files; failed: fileA.txt") and preserve toggling b (isUploading) and other state updates as currently done.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@desktop/src/components/agent-settings/FrameworkTab.tsx`:
- Around line 32-36: The update call must pass the confirmed tag and mark the UI
as updating immediately: in doUpdate(), before awaiting startFrameworkUpdate,
call the local updater state setter (e.g., setUpdating(true)) so the polling
loop arms, and call startFrameworkUpdate with the confirmed tag (e.g.,
startFrameworkUpdate(agent.name, { targetVersion: state.latest.tag }) or the
equivalent API shape) instead of the current single-arg call; keep existing
error handling (setErr) and ensure setSubmitting(false) and setConfirming(false)
are still run in finally.
- Around line 11-22: The polling useEffect that starts an interval when
state?.update_status === "updating" can keep polling the previous agent because
its dependency array only includes state?.update_status; update the effect to
also depend on agent.name so the interval is torn down when the agent changes
(i.e., modify the dependency array of the useEffect that uses setInterval and
clearInterval to include agent.name), ensuring the existing cleanup runs and
load() will reflect the current agent.name instead of allowing stale responses
to overwrite state.
In `@static/desktop/assets/framework-api-DrEi_Szr.js`:
- Line 1: The helper function s (exported as f) is ignoring the second parameter
(targetVersion) and always POSTs an empty body to /framework/update; update the
implementation of function s(r, t) (the /framework/update caller) to include the
targetVersion in the JSON body (e.g., JSON.stringify({ targetVersion: t })) when
present and handle missing/undefined values appropriately, then rebuild the
desktop bundle so the generated asset reflects the TypeScript source changes.
In `@static/desktop/assets/GitHubApp-CJvVZ0RH.js`:
- Line 1: The release detail component (ze) builds a fallback URL r="#" when
repo is missing and still calls window.open(r, ...); update the Open on GitHub
button in ze to guard against the placeholder by either disabling the button
when r === "#" (like the Save button does) or wrapping the onClick so it only
calls window.open when r !== "#", ensuring no navigation is attempted for the
placeholder URL.
- Line 1: Replace the no-op click handlers on the two Connect CTAs (the button
with aria-label "Connect GitHub account" and the banner "Connect" button inside
ne) so they call a real auth starter instead of ()=>{}; add or call a
startGitHubAuth helper (implement it to open your auth entry point, e.g.
window.open('/api/github/auth/start','_blank') or invoke the Secrets app URI)
and use that function in the onClick handlers; ensure the helper is
imported/defined in this module and keep existing R.authenticated logic intact.
- Line 1: The watched tab never gets data because Z is declared without a setter
(const [Z] = i.useState([])) and the tab-switch logic calls the starred fetch
(I()) for "watched"; update the nt component to use a proper state pair (const
[Z, setZ] = i.useState([])), implement/populate watched repos via a fetch (reuse
or add a fetch function similar to We that calls the watched API) and call that
setter when loading watched repos, and change the tab-switch effect (where n
changes) to call the watched fetch when n==="watched" instead of calling I();
ensure the memo g continues to reference Z for watched filtering.
In `@static/desktop/assets/ImportApp-AV3jmR5U.js`:
- Line 1: The embed POST is sending {agent: r} but the backend expects
agent_name; in function P (the embed handler that does
fetch("/api/import/embed", ... , body:JSON.stringify({agent:r}))), change the
payload key to agent_name (i.e. JSON.stringify({agent_name: r})) so the request
body matches the backend's body.get("agent_name") check and stops returning 400.
- Line 1: The embed request (function P in component Y) currently sends only
{agent: r} but the backend requires a files array; modify the upload flow
(function T and the queued-file state managed by i) to capture successful upload
responses (the returned filename) for each file, store those uploaded filenames
(e.g., add uploadedName or a filesUploaded array in state), and then change P to
include body: JSON.stringify({agent: r, files: [/* list of uploaded filenames
*/]}) so the embed endpoint receives the required files list; ensure T updates
state only after a successful upload and collects those names to be sent by P.
In `@static/desktop/assets/SettingsApp-Dxe4E4Jg.js`:
- Line 1: The default YAML template in function Ce contains embedded literal
line numbers (e.g. "2", "3", …) making the config invalid; replace the initial
useState string in Ce with a clean, valid YAML template (no line-number markers)
that reflects expected keys (e.g. top-level comments and example fields) so
backend saves/loads valid YAML when defaults are used.
---
Nitpick comments:
In `@static/desktop/assets/BrowserApp-Bb5zltov.js`:
- Line 1: The reviewed file is a minified build artifact (BrowserApp exported as
we) and should not be reviewed directly; update the PR to include the original
source (e.g., the React/TSX component that compiles to BrowserApp/we) or remove
this bundle from the commit and add it to .gitignore; if the intent is to ship
built artifacts, move them to a dedicated build/output directory and document
the generation step in the CI pipeline so reviewers can inspect the source (look
for the component that defines useState/useCallback handlers like O, X, te and
the exported BrowserApp/we).
In `@static/desktop/assets/ImportApp-AV3jmR5U.js`:
- Line 1: The upload loop in function T silently swallows errors and doesn't
check response.ok, causing false "Uploaded X files" messages; modify T (the
async upload function) to track per-file failures by checking the fetch
response.ok and catching exceptions to increment a failure counter and collect
failed file names (use the existing i array items like a.file/a.name), update
progress v as before, and at the end call o(...) with a final status that
includes succeeded vs failed counts and names (e.g., "Uploaded 2 of 3 files;
failed: fileA.txt") and preserve toggling b (isUploading) and other state
updates as currently done.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: acbe85b5-d92c-434b-be0a-ea4cf7f5def4
📒 Files selected for processing (84)
desktop/src/apps/AgentsApp.tsxdesktop/src/apps/StoreApp.tsxdesktop/src/components/agent-settings/FrameworkTab.tsxdesktop/src/lib/framework-api.tsdesktop/tsconfig.tsbuildinfostatic/desktop/assets/ActivityApp-DLf5-AAB.jsstatic/desktop/assets/AgentBrowsersApp-wWjBRYht.jsstatic/desktop/assets/AgentsApp-_Qg7-zrP.jsstatic/desktop/assets/BrowserApp-Bb5zltov.jsstatic/desktop/assets/CalendarApp-BJnvuKGY.jsstatic/desktop/assets/ChannelsApp-q8uhDhwu.jsstatic/desktop/assets/ClusterApp-ioljQelH.jsstatic/desktop/assets/ContactsApp-DxPrMLAp.jsstatic/desktop/assets/FilesApp-BTNsw5-U.jsstatic/desktop/assets/GitHubApp-CJvVZ0RH.jsstatic/desktop/assets/ImageViewerApp-DFBYGYf6.jsstatic/desktop/assets/ImagesApp-BE4XWuXd.jsstatic/desktop/assets/ImportApp-AV3jmR5U.jsstatic/desktop/assets/ImportApp-BhVzWoYf.jsstatic/desktop/assets/LibraryApp-NzJAyw3P.jsstatic/desktop/assets/MCPApp-BNKCQ0Yu.jsstatic/desktop/assets/MemoryApp-Bv8OQwsD.jsstatic/desktop/assets/MessagesApp-CpdV4x56.jsstatic/desktop/assets/MobileSplitView-qc4KfHBU.jsstatic/desktop/assets/ModelsApp-DBNNEeby.jsstatic/desktop/assets/ProvidersApp-xjy6jve3.jsstatic/desktop/assets/RedditApp-CkwARPpU.jsstatic/desktop/assets/SecretsApp-DQmL3uER.jsstatic/desktop/assets/SettingsApp-Dxe4E4Jg.jsstatic/desktop/assets/StoreApp-B0Yyd-Nx.jsstatic/desktop/assets/StoreApp-ByYq7iFv.jsstatic/desktop/assets/TasksApp-Cue8cE8j.jsstatic/desktop/assets/TextEditorApp-BY7tHNNz.jsstatic/desktop/assets/XApp-DSy-xMWn.jsstatic/desktop/assets/YouTubeApp-Bv-vMHrm.jsstatic/desktop/assets/chat-CXuhmImJ.jsstatic/desktop/assets/framework-api-DrEi_Szr.jsstatic/desktop/assets/index-AdP8dET7.jsstatic/desktop/assets/index-B1RaCrsP.jsstatic/desktop/assets/index-B4nMaGyz.jsstatic/desktop/assets/index-BWQn2E_V.jsstatic/desktop/assets/index-BihecqOj.jsstatic/desktop/assets/index-BmxogU3l.jsstatic/desktop/assets/index-CEB840_S.jsstatic/desktop/assets/index-CLD8ZaMh.jsstatic/desktop/assets/index-CMdPCfyQ.jsstatic/desktop/assets/index-CU-BnpOm.jsstatic/desktop/assets/index-CxwKt0z8.jsstatic/desktop/assets/index-DRCGGbc1.jsstatic/desktop/assets/index-DRlwiMyJ.jsstatic/desktop/assets/index-DSXyGPzk.jsstatic/desktop/assets/index-E-g1VTjI.jsstatic/desktop/assets/index-gywVfqgD.jsstatic/desktop/assets/index-hX7Cdp4T.jsstatic/desktop/assets/main-DolX-lHu.jsstatic/desktop/assets/main-RoS4E9ey.jsstatic/desktop/assets/tokens-BDvF0_Hi.jsstatic/desktop/assets/tokens-Cgwnj38Z.cssstatic/desktop/assets/tokens-f9GIns3r.cssstatic/desktop/assets/vendor-codemirror-Byxbuxf1.jsstatic/desktop/assets/vendor-icons-DcMSPw1y.jsstatic/desktop/chat.htmlstatic/desktop/index.htmltests/e2e/test_framework_store_pill.pytests/e2e/test_framework_tab.pytests/test_auto_update_framework.pytests/test_config_normalize.pytests/test_containers_snapshots.pytests/test_framework_api.pytests/test_framework_manifest.pytests/test_framework_update_runner.pytests/test_github_releases.pytests/test_openclaw_bootstrap_ping.pytinyagentos/agent_image.pytinyagentos/app.pytinyagentos/auto_update.pytinyagentos/config.pytinyagentos/containers/__init__.pytinyagentos/framework_update.pytinyagentos/frameworks.pytinyagentos/github_releases.pytinyagentos/routes/framework.pytinyagentos/routes/openclaw.pytinyagentos/scripts/taos-framework-update.sh
💤 Files with no reviewable changes (2)
- static/desktop/assets/StoreApp-ByYq7iFv.js
- static/desktop/assets/ImportApp-BhVzWoYf.js
| async function load() { | ||
| try { setState(await fetchFrameworkState(agent.name)); setErr(null); } | ||
| catch (e: any) { setErr(String(e)); } | ||
| } | ||
|
|
||
| useEffect(() => { load(); }, [agent.name]); | ||
|
|
||
| useEffect(() => { | ||
| if (state?.update_status !== "updating") return; | ||
| const id = setInterval(() => { load(); }, 2000); | ||
| return () => clearInterval(id); | ||
| }, [state?.update_status]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd desktop/src/components/agent-settings && wc -l FrameworkTab.tsxRepository: jaylfc/tinyagentos
Length of output: 82
🏁 Script executed:
cd desktop/src/components/agent-settings && head -50 FrameworkTab.tsxRepository: jaylfc/tinyagentos
Length of output: 2184
🏁 Script executed:
cd desktop/src/components/agent-settings && tail -60 FrameworkTab.tsxRepository: jaylfc/tinyagentos
Length of output: 2734
🏁 Script executed:
cd desktop/src/components/agent-settings && sed -n '40,106p' FrameworkTab.tsxRepository: jaylfc/tinyagentos
Length of output: 3063
Add agent.name to the polling effect dependency array to prevent stale requests from previous agents.
The polling effect (lines 18-22) depends only on state?.update_status and will continue running even when the agent changes. If the user switches agents while update_status === "updating", the old agent's polling interval persists and competes with the new agent's load request. Whichever response finishes last will overwrite the current state, potentially showing stale data from the previous agent.
Add agent.name to the dependency array so the interval cleans up when the agent changes:
}, [state?.update_status, agent.name]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@desktop/src/components/agent-settings/FrameworkTab.tsx` around lines 11 - 22,
The polling useEffect that starts an interval when state?.update_status ===
"updating" can keep polling the previous agent because its dependency array only
includes state?.update_status; update the effect to also depend on agent.name so
the interval is torn down when the agent changes (i.e., modify the dependency
array of the useEffect that uses setInterval and clearInterval to include
agent.name), ensuring the existing cleanup runs and load() will reflect the
current agent.name instead of allowing stale responses to overwrite state.
| @@ -0,0 +1 @@ | |||
| async function o(r){const t=await fetch(`/api/agents/${encodeURIComponent(r)}/framework`);if(!t.ok)throw new Error(`framework fetch ${t.status}`);return t.json()}async function s(r,t){const e=await fetch(`/api/agents/${encodeURIComponent(r)}/framework/update`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})});if(!e.ok){const a=await e.json().catch(()=>({}));throw new Error(a.error||`update start ${e.status}`)}}async function n(r=!1){const t=await fetch(`/api/frameworks/latest${r?"?refresh=true":""}`);if(!t.ok)throw new Error(`latest frameworks ${t.status}`);return t.json()}export{n as a,o as f,s}; | |||
There was a problem hiding this comment.
Rebuild the desktop bundle — this helper still discards targetVersion.
The generated asset accepts a second parameter but always POSTs {} to /framework/update. That means the shipped desktop bundle will ignore the version pinning supported by desktop/src/lib/framework-api.ts, so runtime behavior will diverge from the TypeScript source until this bundle is regenerated.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/framework-api-DrEi_Szr.js` at line 1, The helper
function s (exported as f) is ignoring the second parameter (targetVersion) and
always POSTs an empty body to /framework/update; update the implementation of
function s(r, t) (the /framework/update caller) to include the targetVersion in
the JSON body (e.g., JSON.stringify({ targetVersion: t })) when present and
handle missing/undefined values appropriately, then rebuild the desktop bundle
so the generated asset reflects the TypeScript source changes.
| @@ -1 +1 @@ | |||
| import{r as i,j as e}from"./vendor-react-l6srOxy7.js";import{B as x,I as Be,C as H,a as O,c as E,S as Te,d as Ae,e as Ge,f as M,g as U}from"./toolbar-UW6q5pkx.js";import{M as He}from"./MobileSplitView-D5Xh9lUE.js";import{u as Oe}from"./use-is-mobile-v5lglusa.js";import{aX as y,aY as w,B as ie,aR as oe,aZ as v,a_ as N,am as ce,r as Ee,S as de,D as q,aL as W,a2 as Me,a0 as P,ay as K,a$ as F,aF as xe,ac as Ue}from"./vendor-icons-CiM_hUpN.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";async function k(l,c,s){try{const d=await fetch(l,{...s,headers:{Accept:"application/json",...s==null?void 0:s.headers}});return!d.ok||!(d.headers.get("content-type")??"").includes("application/json")?c:await d.json()}catch{return c}}async function qe(l,c,s){return k(l,s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)})}async function We(l){const s=new URLSearchParams().toString(),d=`/api/github/starred${s?`?${s}`:""}`,n=await k(d,{repos:[],total:0});return{repos:Array.isArray(n.repos)?n.repos:[],total:n.total??0}}async function Pe(){const l=await k("/api/github/notifications",{notifications:[],unread_count:0});return{notifications:Array.isArray(l.notifications)?l.notifications:[],unread_count:l.unread_count??0}}async function Ke(l,c){try{const s=await fetch(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}`,{headers:{Accept:"application/json"}});return!s.ok||!(s.headers.get("content-type")??"").includes("application/json")?null:await s.json()}catch{return null}}async function Fe(l,c,s){try{const d=await fetch(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}/issues/${s}`,{headers:{Accept:"application/json"}});return!d.ok||!(d.headers.get("content-type")??"").includes("application/json")?null:await d.json()}catch{return null}}async function Ve(l,c){const s=await k(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}/releases`,{releases:[]});return Array.isArray(s.releases)?s.releases:[]}async function Je(){return k("/api/github/auth/status",{authenticated:!1})}async function Ye(l){return qe("/api/knowledge/ingest",{url:l,title:"",text:"",categories:[],source:"github-browser"},null)}const j=l=>{if(!l)return"";const c=new Date(l),s=(Date.now()-c.getTime())/1e3;return s<60?"just now":s<3600?`${Math.floor(s/60)}m ago`:s<86400?`${Math.floor(s/3600)}h ago`:s<604800?`${Math.floor(s/86400)}d ago`:c.toLocaleDateString()},Xe=l=>l<1024?`${l} B`:l<1048576?`${(l/1024).toFixed(1)} KB`:`${(l/1048576).toFixed(1)} MB`,he=l=>l==="open"?"bg-green-500/15 text-green-400 border-green-500/30":l==="closed"?"bg-red-500/15 text-red-400 border-red-500/30":l==="merged"?"bg-slate-500/15 text-slate-400 border-slate-500/30":"bg-white/10 text-shell-text-tertiary border-white/10";function Ze({comment:l,depth:c=0}){const[s,d]=i.useState(c>=3);return e.jsxs("div",{className:`border-l-2 ${c===0?"border-white/10":"border-white/5"} pl-3 py-1`,style:{marginLeft:c>0?`${c*12}px`:0},children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("span",{className:"text-xs font-medium text-shell-text-secondary",children:l.author}),e.jsx("span",{className:"text-[10px] text-shell-text-tertiary",children:j(l.created_at)}),c>=3&&e.jsx("button",{className:"text-[10px] text-accent hover:underline ml-1",onClick:()=>d(n=>!n),"aria-expanded":!s,"aria-label":s?"Expand comment":"Collapse comment",children:s?"expand":"collapse"})]}),!s&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed mb-1",children:l.body}),Object.keys(l.reactions??{}).length>0&&e.jsx("div",{className:"flex gap-1.5 flex-wrap mb-1",children:Object.entries(l.reactions).map(([n,u])=>u>0?e.jsxs("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary","aria-label":`${n}: ${u}`,children:[n," ",u]},n):null)})]})]})}function nt({windowId:l}){const[,c]=i.useState("list"),[s,d]=i.useState(null),[n,u]=i.useState("starred"),[S,V]=i.useState("repos"),[pe,ue]=i.useState(null),[J,be]=i.useState([]),[Y,me]=i.useState([]),[C,fe]=i.useState(0),[X]=i.useState([]),[Z,$]=i.useState(!0),[p,D]=i.useState(""),[Q,z]=i.useState(!1),[ge,ee]=i.useState([]),[je,te]=i.useState(!1),[m,se]=i.useState(!1),[h,L]=i.useState(!1),[R,ye]=i.useState({authenticated:!1}),f=Oe(),ae=i.useCallback(async()=>{const t=await Je();ye(t)},[]),I=i.useCallback(async()=>{$(!0);const t=await We();be(t.repos),$(!1)},[]),_=i.useCallback(async()=>{$(!0);const t=await Pe();me(t.notifications),fe(t.unread_count),$(!1)},[]);i.useEffect(()=>{ae(),I(),_()},[ae,I,_]),i.useEffect(()=>{c("list"),d(null),D(""),n==="starred"||n==="watched"?I():n==="notifications"&&_()},[n,I,_]);const B=i.useCallback(async t=>{c("detail"),d({type:"repo",repo:t}),L(!1),te(!1),z(!0);const[a,r]=await Promise.all([Ve(t.owner,t.name),Ke(t.owner,t.name)]);ee(a),r&&d({type:"repo",repo:r}),z(!1)},[]),T=i.useCallback(async t=>{c("detail"),d({type:"issue",issue:t}),L(!1),z(!0);const[a,r]=t.repo.split("/");if(a&&r){const o=await Fe(a,r,t.number);o&&d({type:"issue",issue:o})}z(!1)},[]),re=i.useCallback((t,a)=>{c("detail"),d({type:"release",release:{...t,repo:a}}),L(!1)},[]),b=i.useCallback(()=>{c("list"),d(null),ee([])},[]),le=i.useMemo(()=>s?s.type==="repo"&&s.repo?`repo:${s.repo.owner}/${s.repo.name}`:s.type==="issue"&&s.issue?`issue:${s.issue.repo}#${s.issue.number}`:s.type==="release"&&s.release?`release:${s.release.tag}`:null:null,[s]),A=i.useCallback(async t=>{se(!0);const a=await Ye(t);se(!1),a&&L(!0)},[]),g=i.useMemo(()=>n==="starred"||n==="watched"?(n==="watched"?X:J).filter(a=>{var o;if(!p)return!0;const r=p.toLowerCase();return a.name.toLowerCase().includes(r)||a.owner.toLowerCase().includes(r)||((o=a.description)==null?void 0:o.toLowerCase().includes(r))}):n==="notifications"?Y.filter(t=>{if(!p)return!0;const a=p.toLowerCase();return t.title.toLowerCase().includes(a)||t.repo.toLowerCase().includes(a)}):[],[n,J,X,Y,p]),we=e.jsxs("nav",{className:"w-52 shrink-0 border-r border-white/5 bg-shell-surface/30 flex flex-col overflow-hidden","aria-label":"GitHub Browser navigation",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-3 border-b border-white/5 shrink-0",children:[e.jsx(y,{size:15,className:"text-accent","aria-hidden":"true"}),e.jsx("h1",{className:"text-sm font-semibold",children:"GitHub"})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-4",children:[e.jsx("section",{"aria-label":"Sections",children:e.jsxs("div",{className:"space-y-0.5",children:[e.jsxs(x,{variant:n==="starred"?"secondary":"ghost",size:"sm","aria-pressed":n==="starred",onClick:()=>u("starred"),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(w,{size:11,"aria-hidden":"true"}),"Starred Repos"]}),e.jsxs(x,{variant:n==="notifications"?"secondary":"ghost",size:"sm","aria-pressed":n==="notifications",onClick:()=>u("notifications"),className:"w-full justify-between text-xs h-7 px-2",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(ie,{size:11,"aria-hidden":"true"}),"Notifications"]}),C>0&&e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-accent text-white text-[10px] tabular-nums","aria-label":`${C} unread`,children:C})]}),e.jsxs(x,{variant:n==="watched"?"secondary":"ghost",size:"sm","aria-pressed":n==="watched",onClick:()=>u("watched"),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(oe,{size:11,"aria-hidden":"true"}),"Watched"]})]})}),e.jsxs("section",{"aria-label":"Content type",children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary px-2 mb-1.5",children:"Content"}),e.jsx("div",{className:"space-y-0.5",children:[{id:"repos",label:"Repos",icon:y},{id:"issues",label:"Issues",icon:v},{id:"prs",label:"Pull Requests",icon:N},{id:"releases",label:"Releases",icon:ce}].map(({id:t,label:a,icon:r})=>e.jsxs(x,{variant:S===t?"secondary":"ghost",size:"sm","aria-pressed":S===t,onClick:()=>V(t),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(r,{size:11,"aria-hidden":"true"}),a]},t))})]}),e.jsxs("section",{"aria-label":"Status filter",children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary px-2 mb-1.5",children:"Status"}),e.jsx("div",{className:"space-y-0.5",children:["open","closed","merged"].map(t=>{const a=pe===t;return e.jsx(x,{variant:a?"secondary":"ghost",size:"sm","aria-pressed":a,onClick:()=>ue(r=>r===t?null:t),className:"w-full justify-start text-xs h-7 px-2 capitalize",children:t},t)})})]})]}),e.jsx("div",{className:"shrink-0 border-t border-white/5 px-3 py-2",children:R.authenticated?e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("p",{className:"text-[10px] text-shell-text-tertiary capitalize",children:R.method??"connected"}),e.jsxs("p",{className:"text-xs text-shell-text-secondary truncate",children:["@",R.username]})]}):e.jsx("button",{className:"text-xs text-accent hover:underline",onClick:()=>{},"aria-label":"Connect GitHub account",children:"Connect GitHub"})})]}),ne=R.authenticated?null:e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2 bg-amber-500/10 border-b border-amber-500/20 text-xs text-amber-300 shrink-0",role:"banner","aria-label":"GitHub authentication notice",children:[e.jsx(Ee,{size:13,"aria-hidden":"true"}),e.jsx("span",{children:"Connect GitHub for starred repos and notifications."}),e.jsx("button",{className:"ml-auto underline hover:text-amber-200","aria-label":"Open Secrets app to connect GitHub",children:"Connect"})]}),ve=t=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>B(t),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),B(t))},tabIndex:0,role:"button","aria-label":`Open ${t.owner}/${t.name}`,children:[e.jsxs(O,{className:"pb-1 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("h3",{className:"text-sm font-medium leading-snug",children:[e.jsxs("span",{className:"text-shell-text-tertiary",children:[t.owner,"/"]}),t.name]}),t.language&&e.jsx("span",{className:"shrink-0 text-[10px] px-1.5 py-0.5 rounded bg-accent/10 text-accent border border-accent/20",children:t.language})]}),t.description&&e.jsx("p",{className:"text-[11px] text-shell-text-secondary line-clamp-1 leading-relaxed mt-0.5",children:t.description})]}),e.jsx(E,{className:"pt-0 px-3 pb-3",children:e.jsxs("div",{className:"flex items-center gap-3 text-[10px] text-shell-text-tertiary",children:[e.jsxs("span",{className:"flex items-center gap-1","aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:10,"aria-hidden":"true"}),t.stars.toLocaleString()]}),e.jsxs("span",{className:"flex items-center gap-1","aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:10,"aria-hidden":"true"}),t.forks.toLocaleString()]}),e.jsx("span",{className:"ml-auto",children:j(t.updated_at)})]})})]},`${t.owner}/${t.name}`),Ne=t=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>T(t),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),T(t))},tabIndex:0,role:"button","aria-label":`Open ${t.is_pull_request?"PR":"issue"}: ${t.title}`,children:[e.jsx(O,{className:"pb-1 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[t.is_pull_request?e.jsx(N,{size:13,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}):e.jsx(v,{size:13,className:"mt-0.5 shrink-0 text-green-400","aria-hidden":"true"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-sm font-medium leading-snug line-clamp-1",children:t.title}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:t.repo})]}),e.jsx("span",{className:`shrink-0 text-[10px] px-1.5 py-0.5 rounded border ${he(t.state)}`,"aria-label":`Status: ${t.state}`,children:t.state})]})}),e.jsxs(E,{className:"pt-0 px-3 pb-3 space-y-1.5",children:[t.labels.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1","aria-label":"Labels",children:t.labels.map(a=>e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary",children:a},a))}),e.jsxs("div",{className:"flex items-center gap-3 text-[10px] text-shell-text-tertiary",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(Me,{size:10,"aria-hidden":"true"}),t.comments.length]}),e.jsx("span",{children:t.author}),e.jsx("span",{className:"ml-auto",children:j(t.created_at)})]})]})]},`${t.repo}#${t.number}`),ke=(t,a="")=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>re(t,a),onKeyDown:r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),re(t,a))},tabIndex:0,role:"button","aria-label":`Open release ${t.tag}`,children:[e.jsx(O,{className:"pb-1 p-3",children:e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"text-sm font-medium leading-snug flex items-center gap-1.5",children:[e.jsx(xe,{size:11,"aria-hidden":"true",className:"text-accent"}),t.tag]}),a&&e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:a})]}),t.prerelease&&e.jsx("span",{className:"shrink-0 text-[10px] px-1.5 py-0.5 rounded bg-amber-500/15 text-amber-400 border border-amber-500/30",children:"pre-release"})]})}),e.jsx(E,{className:"pt-0 px-3 pb-3",children:e.jsx("p",{className:"text-[10px] text-shell-text-tertiary",children:j(t.published_at)})})]},t.tag),Se=e.jsxs("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":"GitHub content list",children:[e.jsx("div",{className:"flex items-center gap-2 px-4 py-3 border-b border-white/5 shrink-0",children:e.jsxs("div",{className:"relative flex-1",children:[e.jsx(de,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-shell-text-tertiary pointer-events-none z-10","aria-hidden":"true"}),e.jsx(Be,{type:"search",value:p,onChange:t=>D(t.target.value),placeholder:"Search…",className:"pl-8 h-8","aria-label":"Search GitHub content"})]})}),e.jsx("div",{className:"flex-1 overflow-y-auto p-3 space-y-2",role:"list","aria-label":"GitHub items",children:Z?e.jsx("div",{className:"flex items-center justify-center h-full text-shell-text-tertiary text-sm",role:"status","aria-live":"polite",children:"Loading…"}):g.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center h-full gap-3 text-shell-text-tertiary",children:[e.jsx(y,{size:36,className:"opacity-20","aria-hidden":"true"}),e.jsx("p",{className:"text-sm",children:p?"No results for your search":"Nothing here yet"})]}):n==="notifications"?g.map(t=>e.jsx("div",{role:"listitem",children:Ne(t)},`${t.repo}#${t.number}`)):g.map(t=>e.jsx("div",{role:"listitem",children:ve(t)},`${t.owner}/${t.name}`))})]}),Ce=t=>{const a=`https://github.com/${t.owner}/${t.name}`,r=ge[0]??null;return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`${t.owner}/${t.name} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:o=>o.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("h2",{className:"text-lg font-semibold leading-snug mb-1",children:[e.jsxs("span",{className:"text-shell-text-tertiary",children:[t.owner,"/"]}),t.name]}),t.description&&e.jsx("p",{className:"text-sm text-shell-text-secondary mb-3",children:t.description}),e.jsxs("div",{className:"flex flex-wrap gap-2 mb-3",children:[e.jsxs("span",{className:"flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary","aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:10,"aria-hidden":"true"}),t.stars.toLocaleString()," stars"]}),e.jsxs("span",{className:"flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary","aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:10,"aria-hidden":"true"}),t.forks.toLocaleString()," forks"]}),t.language&&e.jsx("span",{className:"text-[11px] px-2 py-0.5 rounded bg-accent/10 text-accent border border-accent/20",children:t.language}),t.license&&e.jsx("span",{className:"text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary",children:t.license})]}),t.topics.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mb-2","aria-label":"Topics",children:t.topics.map(o=>e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-blue-500/10 text-blue-400 text-[10px] border border-blue-500/20",children:o},o))})]}),t.readme_content&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"README"}),e.jsx("div",{className:"rounded-lg bg-white/[0.02] border border-white/5 p-3 max-h-64 overflow-y-auto",children:e.jsx("pre",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed font-sans",children:Q?"Loading…":t.readme_content})})]}),r&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"Latest Release"}),ke(r,`${t.owner}/${t.name}`)]}),e.jsxs("div",{className:"px-5 py-3 border-b border-white/5 flex items-center justify-between",children:[e.jsx("label",{htmlFor:`monitor-${t.name}`,className:"text-xs text-shell-text-secondary cursor-pointer",children:"Monitor releases"}),e.jsx(Te,{id:`monitor-${t.name}`,checked:je,onCheckedChange:te,"aria-label":"Monitor releases for this repository"})]}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(a,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>A(a),disabled:m||h,"aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},$e=t=>{const a=`https://github.com/${t.repo}/${t.is_pull_request?"pull":"issues"}/${t.number}`;return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`Issue ${t.number} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:r=>r.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("div",{className:"flex items-start gap-2 mb-2",children:[t.is_pull_request?e.jsx(N,{size:16,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}):e.jsx(v,{size:16,className:"mt-0.5 shrink-0 text-green-400","aria-hidden":"true"}),e.jsx("h2",{className:"text-base font-semibold leading-snug flex-1",children:t.title}),e.jsx("span",{className:`shrink-0 text-[10px] px-1.5 py-0.5 rounded border ${he(t.state)}`,"aria-label":`Status: ${t.state}`,children:t.state})]}),e.jsxs("p",{className:"text-xs text-shell-text-tertiary mb-2",children:[t.repo," · ",t.author," · ",j(t.created_at)]}),t.labels.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mb-2","aria-label":"Labels",children:t.labels.map(r=>e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary",children:r},r))})]}),e.jsx("div",{className:"px-5 py-3 flex-1",children:e.jsxs(Ae,{defaultValue:"discussion",children:[e.jsxs(Ge,{children:[e.jsx(M,{value:"discussion",children:"Discussion"}),e.jsx(M,{value:"history",children:"History"}),e.jsx(M,{value:"metadata",children:"Metadata"})]}),e.jsxs(U,{value:"discussion",children:[t.body&&e.jsx("div",{className:"rounded-lg bg-white/[0.02] border border-white/5 p-3 mb-3 mt-3",children:e.jsx("p",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed",children:Q?"Loading…":t.body})}),t.comments.length>0&&e.jsxs("div",{className:"space-y-2 mt-2","aria-label":"Comments",children:[e.jsxs("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary mb-1",children:[t.comments.length," comment",t.comments.length!==1?"s":""]}),t.comments.map((r,o)=>e.jsx(Ze,{comment:r,depth:0},o))]})]}),e.jsx(U,{value:"history",children:e.jsx("div",{className:"mt-3 text-xs text-shell-text-tertiary italic",children:"Issue history not available in this view."})}),e.jsx(U,{value:"metadata",children:e.jsx("div",{className:"mt-3 space-y-2",children:[{label:"Number",value:`#${t.number}`},{label:"State",value:t.state},{label:"Author",value:t.author},{label:"Repo",value:t.repo},{label:"Type",value:t.is_pull_request?"Pull Request":"Issue"},{label:"Created",value:t.created_at}].map(({label:r,value:o})=>e.jsxs("div",{className:"flex justify-between text-xs",children:[e.jsx("span",{className:"text-shell-text-tertiary",children:r}),e.jsx("span",{className:"text-shell-text-secondary",children:o})]},r))})})]})}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2 border-t border-white/5",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(a,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>A(a),disabled:m||h,"aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},ze=t=>{const a=t.repo??"",r=a?`https://github.com/${a}/releases/tag/${encodeURIComponent(t.tag)}`:"#";return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`Release ${t.tag} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:o=>o.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("div",{className:"flex items-start gap-2 mb-1",children:[e.jsx(xe,{size:16,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}),e.jsx("h2",{className:"text-lg font-semibold leading-snug",children:t.tag}),t.prerelease&&e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-amber-500/15 text-amber-400 border border-amber-500/30",children:"pre-release"})]}),a&&e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-1",children:a}),e.jsxs("p",{className:"text-xs text-shell-text-tertiary",children:[t.author," · ",j(t.published_at)]})]}),t.body&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"Release Notes"}),e.jsx("pre",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed font-sans",children:t.body})]}),t.assets.length>0&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsxs("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:["Assets (",t.assets.length,")"]}),e.jsx("div",{className:"space-y-1.5",role:"list","aria-label":"Release assets",children:t.assets.map(o=>e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 rounded-lg bg-white/[0.02] border border-white/5 text-xs",role:"listitem",children:[e.jsx(Ue,{size:11,"aria-hidden":"true",className:"text-shell-text-tertiary shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-shell-text-secondary font-mono",children:o.name}),e.jsx("span",{className:"text-shell-text-tertiary shrink-0",children:Xe(o.size)}),e.jsxs("span",{className:"text-shell-text-tertiary shrink-0","aria-label":`${o.download_count} downloads`,children:[o.download_count.toLocaleString()," dl"]})]},o.name))})]}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(r,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>A(r),disabled:m||h||r==="#","aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},Le=s?s.type==="repo"&&s.repo?Ce(s.repo):s.type==="issue"&&s.issue?$e(s.issue):s.type==="release"&&s.release?ze(s.release):null:null,Re=i.useMemo(()=>s?s.type==="repo"&&s.repo?`${s.repo.owner}/${s.repo.name}`:s.type==="issue"&&s.issue?s.issue.title:s.type==="release"&&s.release?s.release.tag:"":"",[s]),Ie=!f||le===null,_e=e.jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%"},children:[ne,e.jsx("div",{style:{padding:"8px 0 4px",borderBottom:"1px solid rgba(255,255,255,0.05)",flexShrink:0},children:e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},children:[{id:"starred",label:"Starred Repos",icon:w,badge:null},{id:"notifications",label:"Notifications",icon:ie,badge:C},{id:"watched",label:"Watched",icon:oe,badge:null}].map(({id:t,label:a,icon:r,badge:o},G,De)=>e.jsxs("button",{type:"button",onClick:()=>u(t),"aria-pressed":n===t,"aria-label":a,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:n===t?"rgba(255,255,255,0.08)":"none",border:"none",borderBottom:G===De.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsx(r,{size:15,style:{color:"rgba(255,255,255,0.6)",flexShrink:0},"aria-hidden":"true"}),e.jsx("span",{style:{flex:1,fontSize:15,fontWeight:500,color:"rgba(255,255,255,0.9)"},children:a}),o!=null&&o>0&&e.jsx("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:20,background:"var(--accent, #7c6be8)",color:"#fff",fontWeight:600},"aria-label":`${o} unread`,children:o}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},t))})}),e.jsxs("div",{style:{padding:"8px 0 4px",borderBottom:"1px solid rgba(255,255,255,0.05)",flexShrink:0},children:[e.jsx("div",{style:{fontSize:12,textTransform:"uppercase",letterSpacing:.5,color:"rgba(255,255,255,0.45)",padding:"0 20px 6px",fontWeight:600},children:"Content"}),e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},children:[{id:"repos",label:"Repos",icon:y},{id:"issues",label:"Issues",icon:v},{id:"prs",label:"Pull Requests",icon:N},{id:"releases",label:"Releases",icon:ce}].map(({id:t,label:a,icon:r},o,G)=>e.jsxs("button",{type:"button",onClick:()=>V(t),"aria-pressed":S===t,"aria-label":a,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"12px 16px",background:S===t?"rgba(255,255,255,0.08)":"none",border:"none",borderBottom:o===G.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsx(r,{size:14,style:{color:"rgba(255,255,255,0.6)",flexShrink:0},"aria-hidden":"true"}),e.jsx("span",{style:{flex:1,fontSize:14,color:"rgba(255,255,255,0.85)"},children:a})]},t))})]}),e.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"8px 0 16px"},children:[e.jsx("div",{style:{fontSize:12,textTransform:"uppercase",letterSpacing:.5,color:"rgba(255,255,255,0.45)",padding:"4px 20px 8px",fontWeight:600},children:n==="notifications"?"Notifications":n==="watched"?"Watched":"Starred"}),e.jsx("div",{style:{padding:"0 12px 8px"},children:e.jsxs("div",{style:{position:"relative"},children:[e.jsx(de,{size:13,style:{position:"absolute",left:10,top:"50%",transform:"translateY(-50%)",color:"rgba(255,255,255,0.4)",pointerEvents:"none"},"aria-hidden":"true"}),e.jsx("input",{type:"search",value:p,onChange:t=>D(t.target.value),placeholder:"Search…","aria-label":"Search GitHub content",style:{width:"100%",padding:"8px 12px 8px 30px",borderRadius:10,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)",color:"inherit",fontSize:13,outline:"none",boxSizing:"border-box"}})]})}),Z?e.jsx("div",{style:{padding:"24px 20px",textAlign:"center",fontSize:13,color:"rgba(255,255,255,0.4)"},role:"status","aria-live":"polite",children:"Loading…"}):g.length===0?e.jsx("div",{style:{padding:"32px 20px",textAlign:"center",fontSize:13,color:"rgba(255,255,255,0.4)"},children:p?"No results for your search":"Nothing here yet"}):e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},role:"list","aria-label":"GitHub items",children:n==="notifications"?g.map((t,a,r)=>e.jsxs("button",{type:"button",role:"listitem",onClick:()=>T(t),"aria-label":`Open ${t.is_pull_request?"PR":"issue"}: ${t.title}`,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:"none",border:"none",borderBottom:a===r.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[t.is_pull_request?e.jsx(N,{size:13,style:{flexShrink:0,color:"rgba(130,140,255,0.9)"},"aria-hidden":"true"}):e.jsx(v,{size:13,style:{flexShrink:0,color:"rgba(80,200,120,0.9)"},"aria-hidden":"true"}),e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsx("div",{style:{fontSize:14,fontWeight:500,color:"rgba(255,255,255,0.9)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",marginBottom:2},children:t.title}),e.jsx("div",{style:{fontSize:12,color:"rgba(255,255,255,0.45)"},children:t.repo})]}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},`${t.repo}#${t.number}`)):g.map((t,a,r)=>e.jsxs("button",{type:"button",role:"listitem",onClick:()=>B(t),"aria-label":`Open ${t.owner}/${t.name}`,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:"none",border:"none",borderBottom:a===r.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsxs("div",{style:{fontSize:14,fontWeight:600,color:"rgba(255,255,255,0.95)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",marginBottom:2},children:[e.jsxs("span",{style:{color:"rgba(255,255,255,0.5)"},children:[t.owner,"/"]}),t.name]}),t.description&&e.jsx("div",{style:{fontSize:12,color:"rgba(255,255,255,0.45)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.description}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginTop:4,fontSize:11,color:"rgba(255,255,255,0.35)"},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:3},"aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:9,"aria-hidden":"true"})," ",t.stars.toLocaleString()]}),e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:3},"aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:9,"aria-hidden":"true"})," ",t.forks.toLocaleString()]}),t.language&&e.jsx("span",{children:t.language})]})]}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},`${t.owner}/${t.name}`))})]})]});return e.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden bg-shell-surface text-shell-text select-none relative",children:[Ie&&e.jsx("div",{className:"flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(y,{size:15,className:"text-accent shrink-0","aria-hidden":"true"}),e.jsx("h1",{className:"text-sm font-semibold",children:"GitHub"})]})}),e.jsx(He,{selectedId:le,onBack:b,listTitle:"GitHub",detailTitle:Re,listWidth:208,list:f?_e:e.jsxs("div",{className:"flex h-full overflow-hidden",children:[we,e.jsxs("div",{className:"flex-1 flex flex-col overflow-hidden",children:[ne,Se]})]}),detail:Le??(f?null:e.jsx("div",{className:"flex items-center justify-center h-full text-shell-text-tertiary text-sm",children:"Select an item to view details"}))})]})}export{nt as GitHubApp}; | |||
| import{r as i,j as e}from"./vendor-react-l6srOxy7.js";import{B as x,I as Be,C as H,a as M,c as O,S as Ge,d as Te,e as Ae,f as E,g as U}from"./toolbar-UW6q5pkx.js";import{M as He}from"./MobileSplitView-qc4KfHBU.js";import{u as Me}from"./use-is-mobile-v5lglusa.js";import{aY as y,aZ as w,B as ie,aS as oe,a_ as v,a$ as N,an as ce,r as Oe,S as de,D as q,aM as W,a2 as Ee,a0 as P,az as K,b0 as F,aG as xe,ad as Ue}from"./vendor-icons-DcMSPw1y.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";async function k(l,c,s){try{const d=await fetch(l,{...s,headers:{Accept:"application/json",...s==null?void 0:s.headers}});return!d.ok||!(d.headers.get("content-type")??"").includes("application/json")?c:await d.json()}catch{return c}}async function qe(l,c,s){return k(l,s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)})}async function We(l){const s=new URLSearchParams().toString(),d=`/api/github/starred${s?`?${s}`:""}`,n=await k(d,{repos:[],total:0});return{repos:Array.isArray(n.repos)?n.repos:[],total:n.total??0}}async function Pe(){const l=await k("/api/github/notifications",{notifications:[],unread_count:0});return{notifications:Array.isArray(l.notifications)?l.notifications:[],unread_count:l.unread_count??0}}async function Ke(l,c){try{const s=await fetch(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}`,{headers:{Accept:"application/json"}});return!s.ok||!(s.headers.get("content-type")??"").includes("application/json")?null:await s.json()}catch{return null}}async function Fe(l,c,s){try{const d=await fetch(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}/issues/${s}`,{headers:{Accept:"application/json"}});return!d.ok||!(d.headers.get("content-type")??"").includes("application/json")?null:await d.json()}catch{return null}}async function Ve(l,c){const s=await k(`/api/github/repo/${encodeURIComponent(l)}/${encodeURIComponent(c)}/releases`,{releases:[]});return Array.isArray(s.releases)?s.releases:[]}async function Je(){return k("/api/github/auth/status",{authenticated:!1})}async function Ye(l){return qe("/api/knowledge/ingest",{url:l,title:"",text:"",categories:[],source:"github-browser"},null)}const j=l=>{if(!l)return"";const c=new Date(l),s=(Date.now()-c.getTime())/1e3;return s<60?"just now":s<3600?`${Math.floor(s/60)}m ago`:s<86400?`${Math.floor(s/3600)}h ago`:s<604800?`${Math.floor(s/86400)}d ago`:c.toLocaleDateString()},Ze=l=>l<1024?`${l} B`:l<1048576?`${(l/1024).toFixed(1)} KB`:`${(l/1048576).toFixed(1)} MB`,he=l=>l==="open"?"bg-green-500/15 text-green-400 border-green-500/30":l==="closed"?"bg-red-500/15 text-red-400 border-red-500/30":l==="merged"?"bg-slate-500/15 text-slate-400 border-slate-500/30":"bg-white/10 text-shell-text-tertiary border-white/10";function Qe({comment:l,depth:c=0}){const[s,d]=i.useState(c>=3);return e.jsxs("div",{className:`border-l-2 ${c===0?"border-white/10":"border-white/5"} pl-3 py-1`,style:{marginLeft:c>0?`${c*12}px`:0},children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("span",{className:"text-xs font-medium text-shell-text-secondary",children:l.author}),e.jsx("span",{className:"text-[10px] text-shell-text-tertiary",children:j(l.created_at)}),c>=3&&e.jsx("button",{className:"text-[10px] text-accent hover:underline ml-1",onClick:()=>d(n=>!n),"aria-expanded":!s,"aria-label":s?"Expand comment":"Collapse comment",children:s?"expand":"collapse"})]}),!s&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed mb-1",children:l.body}),Object.keys(l.reactions??{}).length>0&&e.jsx("div",{className:"flex gap-1.5 flex-wrap mb-1",children:Object.entries(l.reactions).map(([n,u])=>u>0?e.jsxs("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary","aria-label":`${n}: ${u}`,children:[n," ",u]},n):null)})]})]})}function nt({windowId:l}){const[,c]=i.useState("list"),[s,d]=i.useState(null),[n,u]=i.useState("starred"),[S,V]=i.useState("repos"),[pe,ue]=i.useState(null),[J,be]=i.useState([]),[Y,me]=i.useState([]),[C,fe]=i.useState(0),[Z]=i.useState([]),[Q,$]=i.useState(!0),[p,D]=i.useState(""),[X,z]=i.useState(!1),[ge,ee]=i.useState([]),[je,te]=i.useState(!1),[m,se]=i.useState(!1),[h,L]=i.useState(!1),[R,ye]=i.useState({authenticated:!1}),f=Me(),ae=i.useCallback(async()=>{const t=await Je();ye(t)},[]),I=i.useCallback(async()=>{$(!0);const t=await We();be(t.repos),$(!1)},[]),_=i.useCallback(async()=>{$(!0);const t=await Pe();me(t.notifications),fe(t.unread_count),$(!1)},[]);i.useEffect(()=>{ae(),I(),_()},[ae,I,_]),i.useEffect(()=>{c("list"),d(null),D(""),n==="starred"||n==="watched"?I():n==="notifications"&&_()},[n,I,_]);const B=i.useCallback(async t=>{c("detail"),d({type:"repo",repo:t}),L(!1),te(!1),z(!0);const[a,r]=await Promise.all([Ve(t.owner,t.name),Ke(t.owner,t.name)]);ee(a),r&&d({type:"repo",repo:r}),z(!1)},[]),G=i.useCallback(async t=>{c("detail"),d({type:"issue",issue:t}),L(!1),z(!0);const[a,r]=t.repo.split("/");if(a&&r){const o=await Fe(a,r,t.number);o&&d({type:"issue",issue:o})}z(!1)},[]),re=i.useCallback((t,a)=>{c("detail"),d({type:"release",release:{...t,repo:a}}),L(!1)},[]),b=i.useCallback(()=>{c("list"),d(null),ee([])},[]),le=i.useMemo(()=>s?s.type==="repo"&&s.repo?`repo:${s.repo.owner}/${s.repo.name}`:s.type==="issue"&&s.issue?`issue:${s.issue.repo}#${s.issue.number}`:s.type==="release"&&s.release?`release:${s.release.tag}`:null:null,[s]),T=i.useCallback(async t=>{se(!0);const a=await Ye(t);se(!1),a&&L(!0)},[]),g=i.useMemo(()=>n==="starred"||n==="watched"?(n==="watched"?Z:J).filter(a=>{var o;if(!p)return!0;const r=p.toLowerCase();return a.name.toLowerCase().includes(r)||a.owner.toLowerCase().includes(r)||((o=a.description)==null?void 0:o.toLowerCase().includes(r))}):n==="notifications"?Y.filter(t=>{if(!p)return!0;const a=p.toLowerCase();return t.title.toLowerCase().includes(a)||t.repo.toLowerCase().includes(a)}):[],[n,J,Z,Y,p]),we=e.jsxs("nav",{className:"w-52 shrink-0 border-r border-white/5 bg-shell-surface/30 flex flex-col overflow-hidden","aria-label":"GitHub Browser navigation",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-3 border-b border-white/5 shrink-0",children:[e.jsx(y,{size:15,className:"text-accent","aria-hidden":"true"}),e.jsx("h1",{className:"text-sm font-semibold",children:"GitHub"})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-4",children:[e.jsx("section",{"aria-label":"Sections",children:e.jsxs("div",{className:"space-y-0.5",children:[e.jsxs(x,{variant:n==="starred"?"secondary":"ghost",size:"sm","aria-pressed":n==="starred",onClick:()=>u("starred"),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(w,{size:11,"aria-hidden":"true"}),"Starred Repos"]}),e.jsxs(x,{variant:n==="notifications"?"secondary":"ghost",size:"sm","aria-pressed":n==="notifications",onClick:()=>u("notifications"),className:"w-full justify-between text-xs h-7 px-2",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(ie,{size:11,"aria-hidden":"true"}),"Notifications"]}),C>0&&e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-accent text-white text-[10px] tabular-nums","aria-label":`${C} unread`,children:C})]}),e.jsxs(x,{variant:n==="watched"?"secondary":"ghost",size:"sm","aria-pressed":n==="watched",onClick:()=>u("watched"),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(oe,{size:11,"aria-hidden":"true"}),"Watched"]})]})}),e.jsxs("section",{"aria-label":"Content type",children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary px-2 mb-1.5",children:"Content"}),e.jsx("div",{className:"space-y-0.5",children:[{id:"repos",label:"Repos",icon:y},{id:"issues",label:"Issues",icon:v},{id:"prs",label:"Pull Requests",icon:N},{id:"releases",label:"Releases",icon:ce}].map(({id:t,label:a,icon:r})=>e.jsxs(x,{variant:S===t?"secondary":"ghost",size:"sm","aria-pressed":S===t,onClick:()=>V(t),className:"w-full justify-start text-xs h-7 px-2 gap-1.5",children:[e.jsx(r,{size:11,"aria-hidden":"true"}),a]},t))})]}),e.jsxs("section",{"aria-label":"Status filter",children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary px-2 mb-1.5",children:"Status"}),e.jsx("div",{className:"space-y-0.5",children:["open","closed","merged"].map(t=>{const a=pe===t;return e.jsx(x,{variant:a?"secondary":"ghost",size:"sm","aria-pressed":a,onClick:()=>ue(r=>r===t?null:t),className:"w-full justify-start text-xs h-7 px-2 capitalize",children:t},t)})})]})]}),e.jsx("div",{className:"shrink-0 border-t border-white/5 px-3 py-2",children:R.authenticated?e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("p",{className:"text-[10px] text-shell-text-tertiary capitalize",children:R.method??"connected"}),e.jsxs("p",{className:"text-xs text-shell-text-secondary truncate",children:["@",R.username]})]}):e.jsx("button",{className:"text-xs text-accent hover:underline",onClick:()=>{},"aria-label":"Connect GitHub account",children:"Connect GitHub"})})]}),ne=R.authenticated?null:e.jsxs("div",{className:"flex items-center gap-3 px-4 py-2 bg-amber-500/10 border-b border-amber-500/20 text-xs text-amber-300 shrink-0",role:"banner","aria-label":"GitHub authentication notice",children:[e.jsx(Oe,{size:13,"aria-hidden":"true"}),e.jsx("span",{children:"Connect GitHub for starred repos and notifications."}),e.jsx("button",{className:"ml-auto underline hover:text-amber-200","aria-label":"Open Secrets app to connect GitHub",children:"Connect"})]}),ve=t=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>B(t),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),B(t))},tabIndex:0,role:"button","aria-label":`Open ${t.owner}/${t.name}`,children:[e.jsxs(M,{className:"pb-1 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("h3",{className:"text-sm font-medium leading-snug",children:[e.jsxs("span",{className:"text-shell-text-tertiary",children:[t.owner,"/"]}),t.name]}),t.language&&e.jsx("span",{className:"shrink-0 text-[10px] px-1.5 py-0.5 rounded bg-accent/10 text-accent border border-accent/20",children:t.language})]}),t.description&&e.jsx("p",{className:"text-[11px] text-shell-text-secondary line-clamp-1 leading-relaxed mt-0.5",children:t.description})]}),e.jsx(O,{className:"pt-0 px-3 pb-3",children:e.jsxs("div",{className:"flex items-center gap-3 text-[10px] text-shell-text-tertiary",children:[e.jsxs("span",{className:"flex items-center gap-1","aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:10,"aria-hidden":"true"}),t.stars.toLocaleString()]}),e.jsxs("span",{className:"flex items-center gap-1","aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:10,"aria-hidden":"true"}),t.forks.toLocaleString()]}),e.jsx("span",{className:"ml-auto",children:j(t.updated_at)})]})})]},`${t.owner}/${t.name}`),Ne=t=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>G(t),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),G(t))},tabIndex:0,role:"button","aria-label":`Open ${t.is_pull_request?"PR":"issue"}: ${t.title}`,children:[e.jsx(M,{className:"pb-1 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[t.is_pull_request?e.jsx(N,{size:13,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}):e.jsx(v,{size:13,className:"mt-0.5 shrink-0 text-green-400","aria-hidden":"true"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-sm font-medium leading-snug line-clamp-1",children:t.title}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:t.repo})]}),e.jsx("span",{className:`shrink-0 text-[10px] px-1.5 py-0.5 rounded border ${he(t.state)}`,"aria-label":`Status: ${t.state}`,children:t.state})]})}),e.jsxs(O,{className:"pt-0 px-3 pb-3 space-y-1.5",children:[t.labels.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1","aria-label":"Labels",children:t.labels.map(a=>e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary",children:a},a))}),e.jsxs("div",{className:"flex items-center gap-3 text-[10px] text-shell-text-tertiary",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(Ee,{size:10,"aria-hidden":"true"}),t.comments.length]}),e.jsx("span",{children:t.author}),e.jsx("span",{className:"ml-auto",children:j(t.created_at)})]})]})]},`${t.repo}#${t.number}`),ke=(t,a="")=>e.jsxs(H,{className:"cursor-pointer hover:border-white/15 transition-colors",onClick:()=>re(t,a),onKeyDown:r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),re(t,a))},tabIndex:0,role:"button","aria-label":`Open release ${t.tag}`,children:[e.jsx(M,{className:"pb-1 p-3",children:e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"text-sm font-medium leading-snug flex items-center gap-1.5",children:[e.jsx(xe,{size:11,"aria-hidden":"true",className:"text-accent"}),t.tag]}),a&&e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:a})]}),t.prerelease&&e.jsx("span",{className:"shrink-0 text-[10px] px-1.5 py-0.5 rounded bg-amber-500/15 text-amber-400 border border-amber-500/30",children:"pre-release"})]})}),e.jsx(O,{className:"pt-0 px-3 pb-3",children:e.jsx("p",{className:"text-[10px] text-shell-text-tertiary",children:j(t.published_at)})})]},t.tag),Se=e.jsxs("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":"GitHub content list",children:[e.jsx("div",{className:"flex items-center gap-2 px-4 py-3 border-b border-white/5 shrink-0",children:e.jsxs("div",{className:"relative flex-1",children:[e.jsx(de,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-shell-text-tertiary pointer-events-none z-10","aria-hidden":"true"}),e.jsx(Be,{type:"search",value:p,onChange:t=>D(t.target.value),placeholder:"Search…",className:"pl-8 h-8","aria-label":"Search GitHub content"})]})}),e.jsx("div",{className:"flex-1 overflow-y-auto p-3 space-y-2",role:"list","aria-label":"GitHub items",children:Q?e.jsx("div",{className:"flex items-center justify-center h-full text-shell-text-tertiary text-sm",role:"status","aria-live":"polite",children:"Loading…"}):g.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center h-full gap-3 text-shell-text-tertiary",children:[e.jsx(y,{size:36,className:"opacity-20","aria-hidden":"true"}),e.jsx("p",{className:"text-sm",children:p?"No results for your search":"Nothing here yet"})]}):n==="notifications"?g.map(t=>e.jsx("div",{role:"listitem",children:Ne(t)},`${t.repo}#${t.number}`)):g.map(t=>e.jsx("div",{role:"listitem",children:ve(t)},`${t.owner}/${t.name}`))})]}),Ce=t=>{const a=`https://github.com/${t.owner}/${t.name}`,r=ge[0]??null;return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`${t.owner}/${t.name} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:o=>o.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("h2",{className:"text-lg font-semibold leading-snug mb-1",children:[e.jsxs("span",{className:"text-shell-text-tertiary",children:[t.owner,"/"]}),t.name]}),t.description&&e.jsx("p",{className:"text-sm text-shell-text-secondary mb-3",children:t.description}),e.jsxs("div",{className:"flex flex-wrap gap-2 mb-3",children:[e.jsxs("span",{className:"flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary","aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:10,"aria-hidden":"true"}),t.stars.toLocaleString()," stars"]}),e.jsxs("span",{className:"flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary","aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:10,"aria-hidden":"true"}),t.forks.toLocaleString()," forks"]}),t.language&&e.jsx("span",{className:"text-[11px] px-2 py-0.5 rounded bg-accent/10 text-accent border border-accent/20",children:t.language}),t.license&&e.jsx("span",{className:"text-[11px] px-2 py-0.5 rounded bg-white/5 border border-white/10 text-shell-text-secondary",children:t.license})]}),t.topics.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mb-2","aria-label":"Topics",children:t.topics.map(o=>e.jsx("span",{className:"px-1.5 py-0.5 rounded-full bg-blue-500/10 text-blue-400 text-[10px] border border-blue-500/20",children:o},o))})]}),t.readme_content&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"README"}),e.jsx("div",{className:"rounded-lg bg-white/[0.02] border border-white/5 p-3 max-h-64 overflow-y-auto",children:e.jsx("pre",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed font-sans",children:X?"Loading…":t.readme_content})})]}),r&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"Latest Release"}),ke(r,`${t.owner}/${t.name}`)]}),e.jsxs("div",{className:"px-5 py-3 border-b border-white/5 flex items-center justify-between",children:[e.jsx("label",{htmlFor:`monitor-${t.name}`,className:"text-xs text-shell-text-secondary cursor-pointer",children:"Monitor releases"}),e.jsx(Ge,{id:`monitor-${t.name}`,checked:je,onCheckedChange:te,"aria-label":"Monitor releases for this repository"})]}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(a,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>T(a),disabled:m||h,"aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},$e=t=>{const a=`https://github.com/${t.repo}/${t.is_pull_request?"pull":"issues"}/${t.number}`;return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`Issue ${t.number} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:r=>r.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("div",{className:"flex items-start gap-2 mb-2",children:[t.is_pull_request?e.jsx(N,{size:16,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}):e.jsx(v,{size:16,className:"mt-0.5 shrink-0 text-green-400","aria-hidden":"true"}),e.jsx("h2",{className:"text-base font-semibold leading-snug flex-1",children:t.title}),e.jsx("span",{className:`shrink-0 text-[10px] px-1.5 py-0.5 rounded border ${he(t.state)}`,"aria-label":`Status: ${t.state}`,children:t.state})]}),e.jsxs("p",{className:"text-xs text-shell-text-tertiary mb-2",children:[t.repo," · ",t.author," · ",j(t.created_at)]}),t.labels.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mb-2","aria-label":"Labels",children:t.labels.map(r=>e.jsx("span",{className:"px-1.5 py-0.5 rounded bg-white/5 border border-white/10 text-[10px] text-shell-text-secondary",children:r},r))})]}),e.jsx("div",{className:"px-5 py-3 flex-1",children:e.jsxs(Te,{defaultValue:"discussion",children:[e.jsxs(Ae,{children:[e.jsx(E,{value:"discussion",children:"Discussion"}),e.jsx(E,{value:"history",children:"History"}),e.jsx(E,{value:"metadata",children:"Metadata"})]}),e.jsxs(U,{value:"discussion",children:[t.body&&e.jsx("div",{className:"rounded-lg bg-white/[0.02] border border-white/5 p-3 mb-3 mt-3",children:e.jsx("p",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed",children:X?"Loading…":t.body})}),t.comments.length>0&&e.jsxs("div",{className:"space-y-2 mt-2","aria-label":"Comments",children:[e.jsxs("p",{className:"text-[10px] uppercase tracking-wider text-shell-text-tertiary mb-1",children:[t.comments.length," comment",t.comments.length!==1?"s":""]}),t.comments.map((r,o)=>e.jsx(Qe,{comment:r,depth:0},o))]})]}),e.jsx(U,{value:"history",children:e.jsx("div",{className:"mt-3 text-xs text-shell-text-tertiary italic",children:"Issue history not available in this view."})}),e.jsx(U,{value:"metadata",children:e.jsx("div",{className:"mt-3 space-y-2",children:[{label:"Number",value:`#${t.number}`},{label:"State",value:t.state},{label:"Author",value:t.author},{label:"Repo",value:t.repo},{label:"Type",value:t.is_pull_request?"Pull Request":"Issue"},{label:"Created",value:t.created_at}].map(({label:r,value:o})=>e.jsxs("div",{className:"flex justify-between text-xs",children:[e.jsx("span",{className:"text-shell-text-tertiary",children:r}),e.jsx("span",{className:"text-shell-text-secondary",children:o})]},r))})})]})}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2 border-t border-white/5",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(a,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>T(a),disabled:m||h,"aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},ze=t=>{const a=t.repo??"",r=a?`https://github.com/${a}/releases/tag/${encodeURIComponent(t.tag)}`:"#";return e.jsx("main",{className:"flex-1 flex flex-col overflow-hidden","aria-label":`Release ${t.tag} detail`,children:e.jsxs("div",{className:"flex-1 overflow-y-auto",children:[e.jsxs("div",{className:"px-5 pt-4 pb-3 border-b border-white/5",children:[!f&&e.jsxs(x,{variant:"ghost",size:"sm",onClick:b,className:"text-xs mb-3 -ml-1 text-shell-text-secondary","aria-label":"Back to list",onKeyDown:o=>o.key==="Escape"&&b(),children:[e.jsx(P,{size:14,"aria-hidden":"true"}),"Back"]}),e.jsxs("div",{className:"flex items-start gap-2 mb-1",children:[e.jsx(xe,{size:16,className:"mt-0.5 shrink-0 text-accent","aria-hidden":"true"}),e.jsx("h2",{className:"text-lg font-semibold leading-snug",children:t.tag}),t.prerelease&&e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-amber-500/15 text-amber-400 border border-amber-500/30",children:"pre-release"})]}),a&&e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-1",children:a}),e.jsxs("p",{className:"text-xs text-shell-text-tertiary",children:[t.author," · ",j(t.published_at)]})]}),t.body&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsx("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:"Release Notes"}),e.jsx("pre",{className:"text-xs text-shell-text-secondary whitespace-pre-wrap leading-relaxed font-sans",children:t.body})]}),t.assets.length>0&&e.jsxs("div",{className:"px-5 py-4 border-b border-white/5",children:[e.jsxs("h3",{className:"text-xs font-semibold text-shell-text-tertiary uppercase tracking-wider mb-2",children:["Assets (",t.assets.length,")"]}),e.jsx("div",{className:"space-y-1.5",role:"list","aria-label":"Release assets",children:t.assets.map(o=>e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 rounded-lg bg-white/[0.02] border border-white/5 text-xs",role:"listitem",children:[e.jsx(Ue,{size:11,"aria-hidden":"true",className:"text-shell-text-tertiary shrink-0"}),e.jsx("span",{className:"flex-1 truncate text-shell-text-secondary font-mono",children:o.name}),e.jsx("span",{className:"text-shell-text-tertiary shrink-0",children:Ze(o.size)}),e.jsxs("span",{className:"text-shell-text-tertiary shrink-0","aria-label":`${o.download_count} downloads`,children:[o.download_count.toLocaleString()," dl"]})]},o.name))})]}),e.jsxs("div",{className:"px-5 py-3 flex flex-wrap gap-2",children:[e.jsxs(x,{size:"sm",variant:"ghost",className:"text-xs gap-1.5",onClick:()=>window.open(r,"_blank","noopener,noreferrer"),"aria-label":"Open on GitHub",children:[e.jsx(K,{size:13,"aria-hidden":"true"}),"Open on GitHub"]}),e.jsxs(x,{size:"sm",variant:h?"secondary":"outline",className:"text-xs gap-1.5",onClick:()=>T(r),disabled:m||h||r==="#","aria-label":h?"Saved to library":"Save to Library",children:[e.jsx(F,{size:13,"aria-hidden":"true"}),h?"Saved":m?"Saving…":"Save to Library"]})]})]})})},Le=s?s.type==="repo"&&s.repo?Ce(s.repo):s.type==="issue"&&s.issue?$e(s.issue):s.type==="release"&&s.release?ze(s.release):null:null,Re=i.useMemo(()=>s?s.type==="repo"&&s.repo?`${s.repo.owner}/${s.repo.name}`:s.type==="issue"&&s.issue?s.issue.title:s.type==="release"&&s.release?s.release.tag:"":"",[s]),Ie=!f||le===null,_e=e.jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%"},children:[ne,e.jsx("div",{style:{padding:"8px 0 4px",borderBottom:"1px solid rgba(255,255,255,0.05)",flexShrink:0},children:e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},children:[{id:"starred",label:"Starred Repos",icon:w,badge:null},{id:"notifications",label:"Notifications",icon:ie,badge:C},{id:"watched",label:"Watched",icon:oe,badge:null}].map(({id:t,label:a,icon:r,badge:o},A,De)=>e.jsxs("button",{type:"button",onClick:()=>u(t),"aria-pressed":n===t,"aria-label":a,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:n===t?"rgba(255,255,255,0.08)":"none",border:"none",borderBottom:A===De.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsx(r,{size:15,style:{color:"rgba(255,255,255,0.6)",flexShrink:0},"aria-hidden":"true"}),e.jsx("span",{style:{flex:1,fontSize:15,fontWeight:500,color:"rgba(255,255,255,0.9)"},children:a}),o!=null&&o>0&&e.jsx("span",{style:{fontSize:11,padding:"1px 7px",borderRadius:20,background:"var(--accent, #7c6be8)",color:"#fff",fontWeight:600},"aria-label":`${o} unread`,children:o}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},t))})}),e.jsxs("div",{style:{padding:"8px 0 4px",borderBottom:"1px solid rgba(255,255,255,0.05)",flexShrink:0},children:[e.jsx("div",{style:{fontSize:12,textTransform:"uppercase",letterSpacing:.5,color:"rgba(255,255,255,0.45)",padding:"0 20px 6px",fontWeight:600},children:"Content"}),e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},children:[{id:"repos",label:"Repos",icon:y},{id:"issues",label:"Issues",icon:v},{id:"prs",label:"Pull Requests",icon:N},{id:"releases",label:"Releases",icon:ce}].map(({id:t,label:a,icon:r},o,A)=>e.jsxs("button",{type:"button",onClick:()=>V(t),"aria-pressed":S===t,"aria-label":a,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"12px 16px",background:S===t?"rgba(255,255,255,0.08)":"none",border:"none",borderBottom:o===A.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsx(r,{size:14,style:{color:"rgba(255,255,255,0.6)",flexShrink:0},"aria-hidden":"true"}),e.jsx("span",{style:{flex:1,fontSize:14,color:"rgba(255,255,255,0.85)"},children:a})]},t))})]}),e.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"8px 0 16px"},children:[e.jsx("div",{style:{fontSize:12,textTransform:"uppercase",letterSpacing:.5,color:"rgba(255,255,255,0.45)",padding:"4px 20px 8px",fontWeight:600},children:n==="notifications"?"Notifications":n==="watched"?"Watched":"Starred"}),e.jsx("div",{style:{padding:"0 12px 8px"},children:e.jsxs("div",{style:{position:"relative"},children:[e.jsx(de,{size:13,style:{position:"absolute",left:10,top:"50%",transform:"translateY(-50%)",color:"rgba(255,255,255,0.4)",pointerEvents:"none"},"aria-hidden":"true"}),e.jsx("input",{type:"search",value:p,onChange:t=>D(t.target.value),placeholder:"Search…","aria-label":"Search GitHub content",style:{width:"100%",padding:"8px 12px 8px 30px",borderRadius:10,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)",color:"inherit",fontSize:13,outline:"none",boxSizing:"border-box"}})]})}),Q?e.jsx("div",{style:{padding:"24px 20px",textAlign:"center",fontSize:13,color:"rgba(255,255,255,0.4)"},role:"status","aria-live":"polite",children:"Loading…"}):g.length===0?e.jsx("div",{style:{padding:"32px 20px",textAlign:"center",fontSize:13,color:"rgba(255,255,255,0.4)"},children:p?"No results for your search":"Nothing here yet"}):e.jsx("div",{style:{margin:"0 12px",borderRadius:16,background:"rgba(255,255,255,0.05)",border:"1px solid rgba(255,255,255,0.08)",overflow:"hidden"},role:"list","aria-label":"GitHub items",children:n==="notifications"?g.map((t,a,r)=>e.jsxs("button",{type:"button",role:"listitem",onClick:()=>G(t),"aria-label":`Open ${t.is_pull_request?"PR":"issue"}: ${t.title}`,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:"none",border:"none",borderBottom:a===r.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[t.is_pull_request?e.jsx(N,{size:13,style:{flexShrink:0,color:"rgba(130,140,255,0.9)"},"aria-hidden":"true"}):e.jsx(v,{size:13,style:{flexShrink:0,color:"rgba(80,200,120,0.9)"},"aria-hidden":"true"}),e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsx("div",{style:{fontSize:14,fontWeight:500,color:"rgba(255,255,255,0.9)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",marginBottom:2},children:t.title}),e.jsx("div",{style:{fontSize:12,color:"rgba(255,255,255,0.45)"},children:t.repo})]}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},`${t.repo}#${t.number}`)):g.map((t,a,r)=>e.jsxs("button",{type:"button",role:"listitem",onClick:()=>B(t),"aria-label":`Open ${t.owner}/${t.name}`,style:{display:"flex",alignItems:"center",gap:10,width:"100%",padding:"14px 16px",background:"none",border:"none",borderBottom:a===r.length-1?"none":"1px solid rgba(255,255,255,0.06)",cursor:"pointer",color:"inherit",textAlign:"left"},children:[e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsxs("div",{style:{fontSize:14,fontWeight:600,color:"rgba(255,255,255,0.95)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",marginBottom:2},children:[e.jsxs("span",{style:{color:"rgba(255,255,255,0.5)"},children:[t.owner,"/"]}),t.name]}),t.description&&e.jsx("div",{style:{fontSize:12,color:"rgba(255,255,255,0.45)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.description}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginTop:4,fontSize:11,color:"rgba(255,255,255,0.35)"},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:3},"aria-label":`${t.stars} stars`,children:[e.jsx(w,{size:9,"aria-hidden":"true"})," ",t.stars.toLocaleString()]}),e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:3},"aria-label":`${t.forks} forks`,children:[e.jsx(W,{size:9,"aria-hidden":"true"})," ",t.forks.toLocaleString()]}),t.language&&e.jsx("span",{children:t.language})]})]}),e.jsx(q,{size:14,style:{color:"rgba(255,255,255,0.3)",flexShrink:0},"aria-hidden":"true"})]},`${t.owner}/${t.name}`))})]})]});return e.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden bg-shell-surface text-shell-text select-none relative",children:[Ie&&e.jsx("div",{className:"flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(y,{size:15,className:"text-accent shrink-0","aria-hidden":"true"}),e.jsx("h1",{className:"text-sm font-semibold",children:"GitHub"})]})}),e.jsx(He,{selectedId:le,onBack:b,listTitle:"GitHub",detailTitle:Re,listWidth:208,list:f?_e:e.jsxs("div",{className:"flex h-full overflow-hidden",children:[we,e.jsxs("div",{className:"flex-1 flex flex-col overflow-hidden",children:[ne,Se]})]}),detail:Le??(f?null:e.jsx("div",{className:"flex items-center justify-center h-full text-shell-text-tertiary text-sm",children:"Select an item to view details"}))})]})}export{nt as GitHubApp}; | |||
There was a problem hiding this comment.
Guard “Open on GitHub” when release URL is placeholder.
On Line 1 in release detail, r can be "#" when repo is missing. “Save to Library” correctly disables for this case, but “Open on GitHub” still attempts window.open("#", ...).
Suggested fix
- onClick:()=>window.open(r,"_blank","noopener,noreferrer")
+ onClick:()=>{ if (r !== "#") window.open(r,"_blank","noopener,noreferrer"); }
+ disabled={r==="#"}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/GitHubApp-CJvVZ0RH.js` at line 1, The release detail
component (ze) builds a fallback URL r="#" when repo is missing and still calls
window.open(r, ...); update the Open on GitHub button in ze to guard against the
placeholder by either disabling the button when r === "#" (like the Save button
does) or wrapping the onClick so it only calls window.open when r !== "#",
ensuring no navigation is attempted for the placeholder URL.
Connect buttons are wired as no-ops.
On Line 1, both unauthenticated “Connect GitHub”/“Connect” CTAs use onClick:()=>{}. This blocks the auth entry point from this UI.
Suggested fix
- onClick:()=>{}
+ onClick:openGitHubConnectFlow+ const openGitHubConnectFlow = () => {
+ // e.g. route to Secrets app / OAuth setup screen
+ window.dispatchEvent(new CustomEvent("open-secrets-app", { detail: { provider: "github" } }));
+ };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/GitHubApp-CJvVZ0RH.js` at line 1, Replace the no-op
click handlers on the two Connect CTAs (the button with aria-label "Connect
GitHub account" and the banner "Connect" button inside ne) so they call a real
auth starter instead of ()=>{}; add or call a startGitHubAuth helper (implement
it to open your auth entry point, e.g.
window.open('/api/github/auth/start','_blank') or invoke the Secrets app URI)
and use that function in the onClick handlers; ensure the helper is
imported/defined in this module and keep existing R.authenticated logic intact.
Watched tab state is never populated.
On Line 1, watched filtering reads Z, but Z is declared via const [Z] = i.useState([]) (no setter) and never updated. The tab switch effect also calls starred fetch (I()) for watched, so watched view will remain empty.
Suggested fix
- const [Z] = i.useState([]);
+ const [Z, setWatchedRepos] = i.useState([]);
+ const fetchWatched = i.useCallback(async () => {
+ $(!0);
+ const t = await k("/api/github/watched", { repos: [] });
+ setWatchedRepos(Array.isArray(t.repos) ? t.repos : []);
+ $(!1);
+ }, []);
- n==="starred"||n==="watched"?I():n==="notifications"&&_()
+ n==="starred" ? I() : n==="watched" ? fetchWatched() : n==="notifications" && _()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/GitHubApp-CJvVZ0RH.js` at line 1, The watched tab never
gets data because Z is declared without a setter (const [Z] = i.useState([]))
and the tab-switch logic calls the starred fetch (I()) for "watched"; update the
nt component to use a proper state pair (const [Z, setZ] = i.useState([])),
implement/populate watched repos via a fetch (reuse or add a fetch function
similar to We that calls the watched API) and call that setter when loading
watched repos, and change the tab-switch effect (where n changes) to call the
watched fetch when n==="watched" instead of calling I(); ensure the memo g
continues to reference Z for watched filtering.
| @@ -0,0 +1 @@ | |||
| import{r as l,j as t}from"./vendor-react-l6srOxy7.js";import{L as U,C,c as k,B as p}from"./toolbar-UW6q5pkx.js";import{ac as f,al as B,y as M,ao as O}from"./vendor-icons-DcMSPw1y.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";const g=[".txt",".md",".pdf",".html",".json",".csv"],L=["text/plain","text/markdown","application/pdf","text/html","application/json","text/csv"];function R(c){return c<1024?`${c} B`:c<1024*1024?`${(c/1024).toFixed(1)} KB`:`${(c/(1024*1024)).toFixed(1)} MB`}function Y({windowId:c}){const[S,D]=l.useState([]),[r,E]=l.useState(""),[i,j]=l.useState([]),[A,x]=l.useState(!1),[h,b]=l.useState(!1),[u,v]=l.useState(0),[y,w]=l.useState(!1),[d,o]=l.useState(null),m=l.useRef(null);l.useEffect(()=>{(async()=>{try{const e=await fetch("/api/agents",{headers:{Accept:"application/json"}});if(e.ok&&(e.headers.get("content-type")??"").includes("application/json")){const a=await e.json();Array.isArray(a)&&a.length>0&&D(a.map(n=>String(n.name??"unknown")))}}catch{}})()},[]);const $=l.useCallback(e=>{var a;const s="."+((a=e.name.split(".").pop())==null?void 0:a.toLowerCase());return g.includes(s)||L.includes(e.type)},[]);function N(e){const a=e.filter($).map(n=>({id:`${n.name}-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,file:n,name:n.name,size:n.size}));j(n=>[...n,...a]),o(null)}function z(e){e.preventDefault(),x(!1);const s=Array.from(e.dataTransfer.files);N(s)}function F(e){e.target.files&&N(Array.from(e.target.files)),e.target.value=""}function I(e){j(s=>s.filter(a=>a.id!==e))}async function T(){if(!r||i.length===0)return;b(!0),v(0),o(null);const e=i.length;let s=0;for(const a of i){const n=new FormData;n.append("file",a.file),n.append("agent",r);try{await fetch("/api/import/upload",{method:"POST",body:n})}catch{}s++,v(Math.round(s/e*100))}b(!1),o(`Uploaded ${e} file${e!==1?"s":""} for ${r}`)}async function P(){if(r){w(!0),o(null);try{(await fetch("/api/import/embed",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agent:r})})).ok?o("Embedding complete. Memory updated."):o("Embedding request sent. Check agent memory.")}catch{o("Could not reach embed endpoint. API may not be available.")}w(!1)}}return t.jsxs("div",{className:"flex flex-col h-full bg-shell-bg text-shell-text select-none",children:[t.jsxs("div",{className:"flex items-center gap-2 px-4 py-3 border-b border-white/5",children:[t.jsx(f,{size:18,className:"text-accent"}),t.jsx("h1",{className:"text-sm font-semibold",children:"Import"})]}),t.jsxs("div",{className:"flex-1 overflow-auto p-4 space-y-4",children:[t.jsxs("div",{className:"space-y-1.5",children:[t.jsx(U,{htmlFor:"import-agent",children:"Target Agent"}),t.jsxs("select",{id:"import-agent",value:r,onChange:e=>E(e.target.value),className:"flex h-9 w-full max-w-sm rounded-lg border border-white/10 bg-shell-bg-deep px-3 py-1 text-sm text-shell-text focus-visible:outline-none focus-visible:border-accent/40 focus-visible:ring-2 focus-visible:ring-accent/20",children:[t.jsx("option",{value:"",children:"Select an agent..."}),S.map(e=>t.jsx("option",{value:e,children:e},e))]})]}),t.jsx(C,{onDragOver:e=>{e.preventDefault(),x(!0)},onDragLeave:()=>x(!1),onDrop:z,className:`border-2 border-dashed transition-colors cursor-pointer ${A?"border-accent bg-accent/5":"border-white/10 hover:border-white/20"}`,onClick:()=>{var e;return(e=m.current)==null?void 0:e.click()},role:"button","aria-label":"Drop files here or click to browse",tabIndex:0,onKeyDown:e=>{var s;(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),(s=m.current)==null||s.click())},children:t.jsxs(k,{className:"flex flex-col items-center justify-center gap-3 p-8",children:[t.jsx(f,{size:32,className:"text-shell-text-tertiary"}),t.jsxs("div",{className:"text-center",children:[t.jsx("p",{className:"text-sm text-shell-text-secondary",children:"Drag and drop files here"}),t.jsx("p",{className:"text-xs text-shell-text-tertiary mt-1",children:g.join(", ")})]}),t.jsx(p,{variant:"secondary",size:"sm",onClick:e=>{var s;e.stopPropagation(),(s=m.current)==null||s.click()},children:"Browse"}),t.jsx("input",{ref:m,type:"file",multiple:!0,accept:g.join(","),onChange:F,className:"hidden","aria-label":"Select files to import"})]})}),i.length>0&&t.jsxs("div",{className:"space-y-1.5",children:[t.jsxs("h2",{className:"text-xs text-shell-text-secondary font-medium",children:["Queued Files (",i.length,")"]}),i.map(e=>t.jsx(C,{children:t.jsxs(k,{className:"flex items-center gap-3 px-3.5 py-2.5",children:[t.jsx(B,{size:14,className:"text-shell-text-tertiary shrink-0"}),t.jsx("span",{className:"text-sm flex-1 truncate",children:e.name}),t.jsx("span",{className:"text-xs text-shell-text-tertiary tabular-nums shrink-0",children:R(e.size)}),t.jsx(p,{variant:"ghost",size:"icon",onClick:()=>I(e.id),className:"h-7 w-7 hover:text-red-400 hover:bg-red-500/15","aria-label":`Remove ${e.name}`,children:t.jsx(M,{size:14})})]})},e.id))]}),h&&t.jsxs("div",{className:"space-y-1.5",children:[t.jsxs("div",{className:"flex items-center justify-between text-xs text-shell-text-secondary",children:[t.jsx("span",{children:"Uploading..."}),t.jsxs("span",{className:"tabular-nums",children:[u,"%"]})]}),t.jsx("div",{className:"h-2 w-full rounded-full bg-white/5",role:"progressbar","aria-valuenow":u,"aria-valuemin":0,"aria-valuemax":100,children:t.jsx("div",{className:"h-full rounded-full bg-accent transition-all",style:{width:`${u}%`}})})]}),d&&t.jsx("p",{className:`text-xs ${d.includes("complete")||d.includes("Uploaded")?"text-emerald-400":"text-amber-400"}`,children:d}),t.jsxs("div",{className:"flex gap-2",children:[t.jsxs(p,{onClick:T,disabled:!r||i.length===0||h,children:[t.jsx(f,{size:14}),h?"Uploading...":"Upload"]}),t.jsxs(p,{variant:"secondary",onClick:P,disabled:!r||y,className:"bg-violet-600 text-white hover:bg-violet-500",children:[t.jsx(O,{size:14}),y?"Embedding...":"Embed"]})]})]})]})}export{Y as ImportApp}; | |||
There was a problem hiding this comment.
Critical: Embed endpoint field name mismatch — embed functionality is broken.
The embed function sends {agent: r} but the backend /api/import/embed endpoint expects agent_name:
# From tinyagentos/routes/import_data.py:47-50
agent_name = body.get("agent_name")
if not agent_name:
return JSONResponse({"error": "agent_name is required"}, status_code=400)This will always return a 400 error. The minified source contains:
body:JSON.stringify({agent:r})The source (pre-minification) should send agent_name instead of agent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/ImportApp-AV3jmR5U.js` at line 1, The embed POST is
sending {agent: r} but the backend expects agent_name; in function P (the embed
handler that does fetch("/api/import/embed", ... ,
body:JSON.stringify({agent:r}))), change the payload key to agent_name (i.e.
JSON.stringify({agent_name: r})) so the request body matches the backend's
body.get("agent_name") check and stops returning 400.
Embed request missing required files array.
In addition to the field name issue, the embed endpoint requires a files array listing the uploaded filenames:
# From tinyagentos/routes/import_data.py:48-50
filenames = body.get("files", [])
if not filenames:
return JSONResponse({"error": "No files specified"}, status_code=400)The frontend sends only {agent: ...} without tracking or sending the uploaded filenames. The embed request should include the list of successfully uploaded file names from the upload responses.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/ImportApp-AV3jmR5U.js` at line 1, The embed request
(function P in component Y) currently sends only {agent: r} but the backend
requires a files array; modify the upload flow (function T and the queued-file
state managed by i) to capture successful upload responses (the returned
filename) for each file, store those uploaded filenames (e.g., add uploadedName
or a filesUploaded array in state), and then change P to include body:
JSON.stringify({agent: r, files: [/* list of uploaded filenames */]}) so the
embed endpoint receives the required files list; ensure T updates state only
after a successful upload and collects those names to be sent by P.
| @@ -1,4 +1,4 @@ | |||
| import{r as s,j as e}from"./vendor-react-l6srOxy7.js";import{B as b,C as w,L as N,I as E,S as T,T as Z}from"./toolbar-UW6q5pkx.js";import{u as ee}from"./main-DolX-lHu.js";import{t as te,a1 as se,an as ae,ac as K,a9 as P,as as V,at as le,au as ne,l as re,U as ce,a0 as ie,r as F,f as D,av as Y,g as oe,y as de,c as xe,ab as me,aw as ue,X as he}from"./vendor-icons-CiM_hUpN.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";import"./tokens-BsnKgzFE.js";import"./vendor-codemirror-BzcrrKz1.js";function pe(r,l,t=a=>a,x=a=>({value:a})){const a=`taos-pref:${r}`,[d,i]=s.useState(()=>{try{const p=localStorage.getItem(a);if(p!==null)return JSON.parse(p)}catch{}return l}),[n,c]=s.useState(!1),m=s.useRef(null);s.useEffect(()=>{let p=!1;return(async()=>{try{const o=await fetch(`/api/preferences/${encodeURIComponent(r)}`);if(!o.ok){c(!0);return}const j=await o.json();if(p)return;if(j&&typeof j=="object"&&Object.keys(j).length>0){const v=t(j);i(v);try{localStorage.setItem(a,JSON.stringify(v))}catch{}}c(!0)}catch{c(!0)}})(),()=>{p=!0}},[r]);const h=s.useCallback(p=>{i(o=>{const j=typeof p=="function"?p(o):p;try{localStorage.setItem(a,JSON.stringify(j))}catch{}return m.current!==null&&clearTimeout(m.current),m.current=setTimeout(()=>{m.current=null,fetch(`/api/preferences/${encodeURIComponent(r)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(x(j))}).catch(()=>{})},500),j})},[a,x,r]);return[d,h,{loaded:n}]}const fe=[{id:"system",label:"System Info",icon:te},{id:"storage",label:"Storage",icon:se},{id:"memory",label:"Memory",icon:ae},{id:"backup",label:"Backup & Restore",icon:K},{id:"updates",label:"Updates",icon:P},{id:"advanced",label:"Advanced",icon:V},{id:"shortcuts",label:"Keyboard Shortcuts",icon:le},{id:"accessibility",label:"Accessibility",icon:ne},{id:"desktop",label:"Desktop & Dock",icon:re},{id:"users",label:"Users",icon:ce}],je={cpu:"Detecting...",ram:"Detecting...",npu:"Detecting...",gpu:"Detecting...",disk:"Detecting...",os:"Detecting..."},ye=[{label:"Models",size:"--",bytes:0,maxBytes:1},{label:"Data",size:"--",bytes:0,maxBytes:1},{label:"App Catalog",size:"--",bytes:0,maxBytes:1}];async function G(r,l){try{const t=await fetch(r,{headers:{Accept:"application/json"}});return!t.ok||!(t.headers.get("content-type")??"").includes("application/json")?l:await t.json()}catch{return l}}function be({value:r,max:l}){const t=l>0?Math.min(100,r/l*100):0;return e.jsx("div",{className:"h-2 w-full rounded-full bg-white/5",role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,children:e.jsx("div",{className:"h-full rounded-full bg-sky-500 transition-all",style:{width:`${t}%`}})})}function ge(){const[r,l]=s.useState(je),[t,x]=s.useState(!1),[a,d]=s.useState(!1),i=s.useCallback(async()=>{var m,h,p,o,j,v,k,S,g,R,_,I,y;x(!0);const c=await G("/api/system",null);if(c!=null&&c.hardware||c!=null&&c.resources){const u=c.hardware??{},U=c.resources??{},C=U.ram_total_mb??u.ram_mb??0,$=U.disk_total_gb??((m=u.disk)==null?void 0:m.total_gb)??0,A=((h=u.cpu)==null?void 0:h.model)??((p=u.cpu)==null?void 0:p.soc)??"Unknown",B=(o=u.cpu)!=null&&o.cores?` × ${u.cpu.cores}`:"",L=(j=u.cpu)!=null&&j.arch?` (${u.cpu.arch})`:"",f=((v=u.gpu)==null?void 0:v.model)||((k=u.gpu)==null?void 0:k.type)||"None",z=(S=u.gpu)!=null&&S.vram_mb&&u.gpu.vram_mb>0?` (${(u.gpu.vram_mb/1024).toFixed(1)} GB)`:"",M=(g=u.npu)!=null&&g.type&&u.npu.type!=="none"?u.npu.type:"None",q=(R=u.npu)!=null&&R.tops&&u.npu.tops>0?` · ${u.npu.tops} TOPS`:"",X=(_=u.disk)!=null&&_.type?` ${u.disk.type}`:"",J=[(I=u.os)==null?void 0:I.distro,(y=u.os)==null?void 0:y.version].filter(Boolean),Q=J.length>0?J.join(" "):"—";l({cpu:`${A}${B}${L}`,ram:C>=1024?`${(C/1024).toFixed(1)} GB`:C>0?`${C} MB`:"—",npu:`${M}${q}`,gpu:`${f}${z}`,disk:$>0?`${$} GB${X}`:"—",os:Q})}else l({cpu:"Unavailable",ram:"Unavailable",npu:"Unavailable",gpu:"Unavailable",disk:"Unavailable",os:"Unavailable"});x(!1)},[]);s.useEffect(()=>{i()},[i]);const n=[["CPU",r.cpu],["RAM",r.ram],["NPU",r.npu],["GPU",r.gpu],["Disk",r.disk],["OS",r.os]];return e.jsxs("section",{"aria-label":"System information",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"System Information"}),e.jsx("div",{className:"rounded-2xl bg-white/[0.04] border border-white/[0.06] overflow-x-auto backdrop-blur-sm",children:e.jsx("table",{className:"w-full text-sm min-w-[360px]",children:e.jsx("tbody",{children:n.map(([c,m])=>e.jsxs("tr",{className:"border-b border-white/5 last:border-0",children:[e.jsx("td",{className:"px-5 py-3 text-shell-text-secondary font-medium w-32",children:c}),e.jsx("td",{className:"px-5 py-3",children:m})]},c))})})}),e.jsxs("div",{className:"mt-3 flex items-center gap-2 flex-wrap",children:[e.jsxs(b,{variant:"outline",size:"sm",onClick:i,disabled:t,children:[e.jsx(P,{size:14,className:t?"animate-spin":""}),"Re-detect Hardware"]}),e.jsxs(b,{variant:"outline",size:"sm",onClick:async()=>{d(!0);try{await fetch("/api/system/restart/prepare",{method:"POST"})}catch{}},"aria-label":"Restart taOS server",children:[e.jsx(P,{size:14}),"Restart Server"]})]}),e.jsx("p",{className:"mt-2 text-xs text-shell-text-tertiary",children:"Restart the server to apply settings changes that require a reload."}),a&&e.jsx(W,{onClose:()=>d(!1)})]})}function Ne(){const[r,l]=s.useState(ye);return s.useEffect(()=>{G("/api/settings/storage",null).then(t=>{t&&Array.isArray(t)?l(t):l([{label:"Models",size:"4.2 GB",bytes:4200,maxBytes:32e3},{label:"Data",size:"1.8 GB",bytes:1800,maxBytes:32e3},{label:"App Catalog",size:"320 MB",bytes:320,maxBytes:32e3}])})},[]),e.jsxs("section",{"aria-label":"Storage usage",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Storage Usage"}),e.jsx("div",{className:"space-y-3",children:r.map(t=>e.jsxs(w,{className:"p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-sm font-medium",children:t.label}),e.jsx("span",{className:"text-sm text-shell-text-secondary tabular-nums",children:t.size})]}),e.jsx(be,{value:t.bytes,max:t.maxBytes})]},t.label))})]})}const ve=[{key:"capture_conversations",label:"Conversations",desc:"Messages you send to agents in the Message Hub"},{key:"capture_notes",label:"Notes",desc:"Notes from the Text Editor app"},{key:"capture_files",label:"File activity",desc:"Files you upload or open"},{key:"capture_searches",label:"Search queries",desc:"What you search for in global search"}];function we(){const[r,l]=s.useState(null),[t,x]=s.useState(null),[a,d]=s.useState(null);s.useEffect(()=>{fetch("/api/user-memory/settings").then(n=>n.ok?n.json():null).then(n=>{l(n||{})}).catch(()=>{l({}),d("Could not load memory settings.")}),fetch("/api/user-memory/stats").then(n=>n.ok?n.json():null).then(n=>{n&&x(n)}).catch(()=>{})},[]);const i=(n,c)=>{const m={...r||{},[n]:c};l(m),fetch("/api/user-memory/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({[n]:c})}).then(h=>{h.ok?d(null):d(`Failed to save setting (${h.status})`)}).catch(()=>d("Could not reach backend."))};return r?e.jsxs("section",{"aria-label":"Memory capture settings",children:[e.jsx("h2",{className:"text-lg font-semibold mb-2",children:"Memory Capture"}),e.jsx("p",{className:"text-sm text-shell-text-tertiary mb-5",children:"Choose what activity gets saved to your personal memory index. All data stays on this device."}),a&&e.jsxs("p",{className:"mb-3 text-xs text-amber-400 flex items-center gap-1.5",children:[e.jsx(F,{size:12})," ",a]}),e.jsx("div",{className:"space-y-2",children:ve.map(n=>{const c=!!r[n.key],m=`capture-${String(n.key)}`;return e.jsxs(w,{className:"p-4 flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{htmlFor:m,className:"text-sm font-medium text-shell-text",children:n.label}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mt-0.5",children:n.desc})]}),e.jsx(T,{id:m,checked:c,onCheckedChange:h=>i(n.key,h),"aria-label":`Capture ${n.label}`})]},String(n.key))})}),t&&e.jsxs(w,{className:"mt-6 p-4",children:[e.jsx("h3",{className:"text-sm font-medium mb-3",children:"Stored chunks"}),e.jsxs("div",{className:"text-xs text-shell-text-secondary mb-2 tabular-nums",children:["Total: ",t.total]}),Object.keys(t.collections||{}).length>0?e.jsx("ul",{className:"space-y-1 text-xs text-shell-text-tertiary",children:Object.entries(t.collections).map(([n,c])=>e.jsxs("li",{className:"flex justify-between tabular-nums",children:[e.jsx("span",{children:n}),e.jsx("span",{children:c})]},n))}):e.jsx("p",{className:"text-xs text-shell-text-tertiary",children:"No memories captured yet."})]})]}):e.jsxs("section",{"aria-label":"Memory capture settings",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Memory Capture"}),e.jsx("p",{className:"text-sm text-shell-text-tertiary",children:"Loading..."})]})}function ke(){const[r,l]=s.useState(null),[t,x]=s.useState(!1),a=async()=>{x(!0),l(null);try{const d=await fetch("/api/backup",{method:"POST"});d.ok?l("Backup created successfully."):l(`Backup failed (${d.status}). API may not be available yet.`)}catch{l("Could not reach backup endpoint. API not available yet.")}x(!1)};return e.jsxs("section",{"aria-label":"Backup and restore",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Backup & Restore"}),e.jsxs(w,{className:"p-4 space-y-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-medium mb-2",children:"Create Backup"}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-3",children:"Export all agents, memory, and configuration as a backup archive."}),e.jsxs(b,{size:"sm",onClick:a,disabled:t,children:[e.jsx(K,{size:14,className:t?"animate-bounce":""}),t?"Creating...":"Create Backup"]}),r&&e.jsx("p",{className:`mt-2 text-xs ${r.includes("success")?"text-emerald-400":"text-amber-400"}`,children:r})]}),e.jsx("hr",{className:"border-white/5"}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-medium mb-2",children:"Restore from Backup"}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-3",children:"Upload a previously created backup archive to restore."}),e.jsxs("label",{className:"flex flex-col items-center gap-2 p-6 rounded-lg border-2 border-dashed border-white/10 hover:border-white/20 transition-colors cursor-pointer",children:[e.jsx(me,{size:24,className:"text-shell-text-tertiary"}),e.jsx("span",{className:"text-xs text-shell-text-tertiary",children:"Click to select a backup file"}),e.jsx("input",{type:"file",accept:".tar.gz,.zip,.bak",className:"hidden","aria-label":"Upload backup file"})]})]})]})]})}function W({onClose:r}){const[l,t]=s.useState(null),[x,a]=s.useState(!1);s.useEffect(()=>{let n=!1,c=null,m=null,h=!1;const p=()=>{h||n||(h=!0,c&&clearInterval(c),m=setInterval(async()=>{if(!n)try{(await fetch("/api/settings/update-status")).ok&&(a(!0),m&&clearInterval(m),setTimeout(()=>{n||window.location.reload()},500))}catch{}},2e3))};return c=setInterval(async()=>{if(!n)try{const o=await fetch("/api/system/restart/status");if(o.ok){const j=await o.json();t(j),j.phase==="restarting"&&p()}}catch{p()}},1e3),()=>{n=!0,c&&clearInterval(c),m&&clearInterval(m)}},[]);const d=l?Object.entries(l.agents):[];function i(n){return n==="ready"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-emerald-500/20 text-emerald-300",children:"ready"}):n==="timeout"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-300",children:"timeout"}):n==="error"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-red-500/20 text-red-300",children:"error"}):e.jsxs("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-sky-500/20 text-sky-300 flex items-center gap-1",children:[e.jsx(P,{size:10,className:"animate-spin"}),n]})}return e.jsx("div",{role:"dialog","aria-modal":"true","aria-label":"Restart progress",className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:e.jsxs("div",{className:"bg-shell-surface border border-white/10 rounded-xl p-6 w-full max-w-md shadow-xl space-y-4",children:[e.jsx("h3",{className:"text-base font-semibold",children:x?"Restarted — reloading…":d.length>0?"Preparing agents for restart":"Restarting server…"}),d.length>0&&e.jsx("ul",{className:"space-y-1","aria-label":"Agent preparation status",children:d.map(([n,c])=>e.jsxs("li",{className:"flex items-center justify-between text-sm",children:[e.jsx("span",{className:"text-shell-text-secondary",children:n}),i(c.status)]},n))}),(l==null?void 0:l.phase)==="restarting"&&!x&&e.jsx("p",{className:"text-xs text-shell-text-tertiary",children:"Waiting for server to come back…"}),!l&&e.jsxs("p",{className:"text-xs text-shell-text-tertiary flex items-center gap-1",children:[e.jsx(P,{size:12,className:"animate-spin"})," Connecting…"]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(b,{variant:"outline",size:"sm",onClick:r,"aria-label":"Cancel restart progress dialog",children:"Cancel"})})]})})}function Se(){const[r,l]=s.useState(!1),[t,x]=s.useState(!1),[a,d]=s.useState(null),[i,n]=s.useState(null),[c,m]=s.useState({check_enabled:!0,auto_apply:!1,auto_restart:!1}),[h,p]=s.useState(null),[o,j]=s.useState(!1),[v,k]=s.useState(!1);s.useEffect(()=>{(async()=>{try{const y=await fetch("/api/preferences/auto-update");if(y.ok){const u=await y.json();u&&typeof u=="object"&&m({check_enabled:u.check_enabled??!0,auto_apply:u.auto_apply??!1,auto_restart:u.auto_restart??!1})}}catch{}try{const y=await fetch("/api/settings/update-check");y.ok&&d(await y.json())}catch{}try{const y=await fetch("/api/settings/update-status");y.ok&&p(await y.json())}catch{}})()},[]);const S=s.useCallback(async y=>{m(y);try{await fetch("/api/preferences/auto-update",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(y)})}catch{}},[]),g=async()=>{l(!0),n(null);try{const y=await fetch("/api/settings/update-check");if(y.ok){const u=await y.json();d(u),n(u.has_updates?"A new version is available.":"You are up to date.")}else n("Update check not available.")}catch{n("Could not reach update server.")}l(!1)},R=async()=>{x(!0),n(null);try{const y=await fetch("/api/settings/update",{method:"POST"});if(y.ok){const u=await y.json().catch(()=>({}));if(u.status==="restarting")j(!0);else{n(u.message??"Update applied. Restart the server to finish."),k(!0);const U=await fetch("/api/settings/update-check");U.ok&&d(await U.json());const C=await fetch("/api/settings/update-status");C.ok&&p(await C.json())}}else{const u=await y.json().catch(()=>({}));n(u.error??"Update failed.")}}catch{n("Could not apply update.")}x(!1)},_=async()=>{j(!0);try{await fetch("/api/system/restart/prepare",{method:"POST"})}catch{}},I=!!(h!=null&&h.pending_restart_sha);return e.jsxs("section",{"aria-label":"System updates",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Updates"}),I&&e.jsxs("div",{className:"mb-4 flex items-center justify-between gap-3 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-amber-200",children:[e.jsx(F,{size:16,className:"shrink-0"}),e.jsxs("span",{children:["Update pulled — restart to finish applying (",h.pending_restart_sha.slice(0,7),")"]})]}),e.jsx(b,{size:"sm",onClick:_,"aria-label":"Restart server to apply update",children:"Restart now"})]}),e.jsxs(w,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 rounded-lg bg-white/5 text-sky-400",children:e.jsx(xe,{size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"taOS"}),a!=null&&a.has_updates&&a.new_commit?e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsxs("p",{className:"text-xs text-shell-text-tertiary tabular-nums",children:[e.jsx("span",{className:"text-white/40",children:"installed "}),a.current_commit]}),e.jsxs("p",{className:"text-xs text-amber-300/90 tabular-nums",children:[e.jsx("span",{className:"text-amber-300/50",children:"available "}),a.new_commit]})]}):e.jsx("p",{className:"text-xs text-shell-text-tertiary tabular-nums",children:(a==null?void 0:a.current_commit)??"v0.1.0-dev"})]}),(a==null?void 0:a.has_updates)&&e.jsx("span",{className:"text-[10px] px-2 py-1 rounded-full font-semibold bg-amber-500/20 text-amber-300",children:"Update available"})]}),e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(b,{variant:"outline",size:"sm",onClick:g,disabled:r,children:[e.jsx(P,{size:14,className:r?"animate-spin":""}),r?"Checking...":"Check Now"]}),v?e.jsx(b,{size:"sm",onClick:_,"aria-label":"Restart server to apply update",children:"Restart Now"}):a!=null&&a.has_updates?e.jsx(b,{size:"sm",onClick:R,disabled:t,children:t?"Installing...":"Install Update"}):null]}),i&&e.jsxs("div",{className:"flex items-start gap-2 text-xs",children:[i.includes("up to date")||i.includes("applied")?e.jsx(D,{size:14,className:"text-emerald-400 shrink-0 mt-0.5"}):e.jsx(F,{size:14,className:"text-amber-400 shrink-0 mt-0.5"}),e.jsx("span",{className:"text-shell-text-secondary",children:i})]}),e.jsxs("div",{className:"border-t border-white/5 pt-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Check for updates automatically"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:"Polls GitHub hourly and notifies when a new version is available."})]}),e.jsx(T,{checked:c.check_enabled??!0,onCheckedChange:y=>S({...c,check_enabled:y})})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Install updates automatically"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:"Pulls + installs new versions as soon as they're detected. You'll still need to restart the server manually."})]}),e.jsx(T,{checked:c.auto_apply??!1,onCheckedChange:y=>S({...c,auto_apply:y}),disabled:!(c.check_enabled??!0)})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Automatically restart after update"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:c.auto_restart?"Server will restart automatically once an update is pulled.":"We'll remind you every 6 hours when a restart is pending."})]}),e.jsx(T,{checked:c.auto_restart??!1,onCheckedChange:y=>S({...c,auto_restart:y}),"aria-label":"Automatically restart after update"})]})]})]}),o&&e.jsx(W,{onClose:()=>j(!1)})]})}function Ce(){const[r,l]=s.useState(`# taOS Configuration | |||
| import{r as s,j as e}from"./vendor-react-l6srOxy7.js";import{B as b,C as w,L as N,I as E,S as T,T as Z}from"./toolbar-UW6q5pkx.js";import{u as ee}from"./main-RoS4E9ey.js";import{t as te,a1 as se,ao as ae,ad as K,aa as P,at as V,au as le,av as ne,l as re,U as ce,a0 as ie,r as F,f as D,aw as Y,g as oe,y as de,c as xe,ac as me,ax as ue,X as he}from"./vendor-icons-DcMSPw1y.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";import"./tokens-BDvF0_Hi.js";import"./vendor-codemirror-Byxbuxf1.js";function pe(r,l,t=a=>a,x=a=>({value:a})){const a=`taos-pref:${r}`,[d,i]=s.useState(()=>{try{const p=localStorage.getItem(a);if(p!==null)return JSON.parse(p)}catch{}return l}),[n,c]=s.useState(!1),m=s.useRef(null);s.useEffect(()=>{let p=!1;return(async()=>{try{const o=await fetch(`/api/preferences/${encodeURIComponent(r)}`);if(!o.ok){c(!0);return}const j=await o.json();if(p)return;if(j&&typeof j=="object"&&Object.keys(j).length>0){const v=t(j);i(v);try{localStorage.setItem(a,JSON.stringify(v))}catch{}}c(!0)}catch{c(!0)}})(),()=>{p=!0}},[r]);const h=s.useCallback(p=>{i(o=>{const j=typeof p=="function"?p(o):p;try{localStorage.setItem(a,JSON.stringify(j))}catch{}return m.current!==null&&clearTimeout(m.current),m.current=setTimeout(()=>{m.current=null,fetch(`/api/preferences/${encodeURIComponent(r)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(x(j))}).catch(()=>{})},500),j})},[a,x,r]);return[d,h,{loaded:n}]}const fe=[{id:"system",label:"System Info",icon:te},{id:"storage",label:"Storage",icon:se},{id:"memory",label:"Memory",icon:ae},{id:"backup",label:"Backup & Restore",icon:K},{id:"updates",label:"Updates",icon:P},{id:"advanced",label:"Advanced",icon:V},{id:"shortcuts",label:"Keyboard Shortcuts",icon:le},{id:"accessibility",label:"Accessibility",icon:ne},{id:"desktop",label:"Desktop & Dock",icon:re},{id:"users",label:"Users",icon:ce}],je={cpu:"Detecting...",ram:"Detecting...",npu:"Detecting...",gpu:"Detecting...",disk:"Detecting...",os:"Detecting..."},ye=[{label:"Models",size:"--",bytes:0,maxBytes:1},{label:"Data",size:"--",bytes:0,maxBytes:1},{label:"App Catalog",size:"--",bytes:0,maxBytes:1}];async function G(r,l){try{const t=await fetch(r,{headers:{Accept:"application/json"}});return!t.ok||!(t.headers.get("content-type")??"").includes("application/json")?l:await t.json()}catch{return l}}function be({value:r,max:l}){const t=l>0?Math.min(100,r/l*100):0;return e.jsx("div",{className:"h-2 w-full rounded-full bg-white/5",role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,children:e.jsx("div",{className:"h-full rounded-full bg-sky-500 transition-all",style:{width:`${t}%`}})})}function ge(){const[r,l]=s.useState(je),[t,x]=s.useState(!1),[a,d]=s.useState(!1),i=s.useCallback(async()=>{var m,h,p,o,j,v,k,S,g,R,_,I,y;x(!0);const c=await G("/api/system",null);if(c!=null&&c.hardware||c!=null&&c.resources){const u=c.hardware??{},U=c.resources??{},C=U.ram_total_mb??u.ram_mb??0,$=U.disk_total_gb??((m=u.disk)==null?void 0:m.total_gb)??0,A=((h=u.cpu)==null?void 0:h.model)??((p=u.cpu)==null?void 0:p.soc)??"Unknown",B=(o=u.cpu)!=null&&o.cores?` × ${u.cpu.cores}`:"",L=(j=u.cpu)!=null&&j.arch?` (${u.cpu.arch})`:"",f=((v=u.gpu)==null?void 0:v.model)||((k=u.gpu)==null?void 0:k.type)||"None",z=(S=u.gpu)!=null&&S.vram_mb&&u.gpu.vram_mb>0?` (${(u.gpu.vram_mb/1024).toFixed(1)} GB)`:"",M=(g=u.npu)!=null&&g.type&&u.npu.type!=="none"?u.npu.type:"None",q=(R=u.npu)!=null&&R.tops&&u.npu.tops>0?` · ${u.npu.tops} TOPS`:"",X=(_=u.disk)!=null&&_.type?` ${u.disk.type}`:"",J=[(I=u.os)==null?void 0:I.distro,(y=u.os)==null?void 0:y.version].filter(Boolean),Q=J.length>0?J.join(" "):"—";l({cpu:`${A}${B}${L}`,ram:C>=1024?`${(C/1024).toFixed(1)} GB`:C>0?`${C} MB`:"—",npu:`${M}${q}`,gpu:`${f}${z}`,disk:$>0?`${$} GB${X}`:"—",os:Q})}else l({cpu:"Unavailable",ram:"Unavailable",npu:"Unavailable",gpu:"Unavailable",disk:"Unavailable",os:"Unavailable"});x(!1)},[]);s.useEffect(()=>{i()},[i]);const n=[["CPU",r.cpu],["RAM",r.ram],["NPU",r.npu],["GPU",r.gpu],["Disk",r.disk],["OS",r.os]];return e.jsxs("section",{"aria-label":"System information",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"System Information"}),e.jsx("div",{className:"rounded-2xl bg-white/[0.04] border border-white/[0.06] overflow-x-auto backdrop-blur-sm",children:e.jsx("table",{className:"w-full text-sm min-w-[360px]",children:e.jsx("tbody",{children:n.map(([c,m])=>e.jsxs("tr",{className:"border-b border-white/5 last:border-0",children:[e.jsx("td",{className:"px-5 py-3 text-shell-text-secondary font-medium w-32",children:c}),e.jsx("td",{className:"px-5 py-3",children:m})]},c))})})}),e.jsxs("div",{className:"mt-3 flex items-center gap-2 flex-wrap",children:[e.jsxs(b,{variant:"outline",size:"sm",onClick:i,disabled:t,children:[e.jsx(P,{size:14,className:t?"animate-spin":""}),"Re-detect Hardware"]}),e.jsxs(b,{variant:"outline",size:"sm",onClick:async()=>{d(!0);try{await fetch("/api/system/restart/prepare",{method:"POST"})}catch{}},"aria-label":"Restart taOS server",children:[e.jsx(P,{size:14}),"Restart Server"]})]}),e.jsx("p",{className:"mt-2 text-xs text-shell-text-tertiary",children:"Restart the server to apply settings changes that require a reload."}),a&&e.jsx(W,{onClose:()=>d(!1)})]})}function Ne(){const[r,l]=s.useState(ye);return s.useEffect(()=>{G("/api/settings/storage",null).then(t=>{t&&Array.isArray(t)?l(t):l([{label:"Models",size:"4.2 GB",bytes:4200,maxBytes:32e3},{label:"Data",size:"1.8 GB",bytes:1800,maxBytes:32e3},{label:"App Catalog",size:"320 MB",bytes:320,maxBytes:32e3}])})},[]),e.jsxs("section",{"aria-label":"Storage usage",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Storage Usage"}),e.jsx("div",{className:"space-y-3",children:r.map(t=>e.jsxs(w,{className:"p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("span",{className:"text-sm font-medium",children:t.label}),e.jsx("span",{className:"text-sm text-shell-text-secondary tabular-nums",children:t.size})]}),e.jsx(be,{value:t.bytes,max:t.maxBytes})]},t.label))})]})}const ve=[{key:"capture_conversations",label:"Conversations",desc:"Messages you send to agents in the Message Hub"},{key:"capture_notes",label:"Notes",desc:"Notes from the Text Editor app"},{key:"capture_files",label:"File activity",desc:"Files you upload or open"},{key:"capture_searches",label:"Search queries",desc:"What you search for in global search"}];function we(){const[r,l]=s.useState(null),[t,x]=s.useState(null),[a,d]=s.useState(null);s.useEffect(()=>{fetch("/api/user-memory/settings").then(n=>n.ok?n.json():null).then(n=>{l(n||{})}).catch(()=>{l({}),d("Could not load memory settings.")}),fetch("/api/user-memory/stats").then(n=>n.ok?n.json():null).then(n=>{n&&x(n)}).catch(()=>{})},[]);const i=(n,c)=>{const m={...r||{},[n]:c};l(m),fetch("/api/user-memory/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({[n]:c})}).then(h=>{h.ok?d(null):d(`Failed to save setting (${h.status})`)}).catch(()=>d("Could not reach backend."))};return r?e.jsxs("section",{"aria-label":"Memory capture settings",children:[e.jsx("h2",{className:"text-lg font-semibold mb-2",children:"Memory Capture"}),e.jsx("p",{className:"text-sm text-shell-text-tertiary mb-5",children:"Choose what activity gets saved to your personal memory index. All data stays on this device."}),a&&e.jsxs("p",{className:"mb-3 text-xs text-amber-400 flex items-center gap-1.5",children:[e.jsx(F,{size:12})," ",a]}),e.jsx("div",{className:"space-y-2",children:ve.map(n=>{const c=!!r[n.key],m=`capture-${String(n.key)}`;return e.jsxs(w,{className:"p-4 flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{htmlFor:m,className:"text-sm font-medium text-shell-text",children:n.label}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mt-0.5",children:n.desc})]}),e.jsx(T,{id:m,checked:c,onCheckedChange:h=>i(n.key,h),"aria-label":`Capture ${n.label}`})]},String(n.key))})}),t&&e.jsxs(w,{className:"mt-6 p-4",children:[e.jsx("h3",{className:"text-sm font-medium mb-3",children:"Stored chunks"}),e.jsxs("div",{className:"text-xs text-shell-text-secondary mb-2 tabular-nums",children:["Total: ",t.total]}),Object.keys(t.collections||{}).length>0?e.jsx("ul",{className:"space-y-1 text-xs text-shell-text-tertiary",children:Object.entries(t.collections).map(([n,c])=>e.jsxs("li",{className:"flex justify-between tabular-nums",children:[e.jsx("span",{children:n}),e.jsx("span",{children:c})]},n))}):e.jsx("p",{className:"text-xs text-shell-text-tertiary",children:"No memories captured yet."})]})]}):e.jsxs("section",{"aria-label":"Memory capture settings",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Memory Capture"}),e.jsx("p",{className:"text-sm text-shell-text-tertiary",children:"Loading..."})]})}function ke(){const[r,l]=s.useState(null),[t,x]=s.useState(!1),a=async()=>{x(!0),l(null);try{const d=await fetch("/api/backup",{method:"POST"});d.ok?l("Backup created successfully."):l(`Backup failed (${d.status}). API may not be available yet.`)}catch{l("Could not reach backup endpoint. API not available yet.")}x(!1)};return e.jsxs("section",{"aria-label":"Backup and restore",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Backup & Restore"}),e.jsxs(w,{className:"p-4 space-y-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-medium mb-2",children:"Create Backup"}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-3",children:"Export all agents, memory, and configuration as a backup archive."}),e.jsxs(b,{size:"sm",onClick:a,disabled:t,children:[e.jsx(K,{size:14,className:t?"animate-bounce":""}),t?"Creating...":"Create Backup"]}),r&&e.jsx("p",{className:`mt-2 text-xs ${r.includes("success")?"text-emerald-400":"text-amber-400"}`,children:r})]}),e.jsx("hr",{className:"border-white/5"}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-medium mb-2",children:"Restore from Backup"}),e.jsx("p",{className:"text-xs text-shell-text-tertiary mb-3",children:"Upload a previously created backup archive to restore."}),e.jsxs("label",{className:"flex flex-col items-center gap-2 p-6 rounded-lg border-2 border-dashed border-white/10 hover:border-white/20 transition-colors cursor-pointer",children:[e.jsx(me,{size:24,className:"text-shell-text-tertiary"}),e.jsx("span",{className:"text-xs text-shell-text-tertiary",children:"Click to select a backup file"}),e.jsx("input",{type:"file",accept:".tar.gz,.zip,.bak",className:"hidden","aria-label":"Upload backup file"})]})]})]})]})}function W({onClose:r}){const[l,t]=s.useState(null),[x,a]=s.useState(!1);s.useEffect(()=>{let n=!1,c=null,m=null,h=!1;const p=()=>{h||n||(h=!0,c&&clearInterval(c),m=setInterval(async()=>{if(!n)try{(await fetch("/api/settings/update-status")).ok&&(a(!0),m&&clearInterval(m),setTimeout(()=>{n||window.location.reload()},500))}catch{}},2e3))};return c=setInterval(async()=>{if(!n)try{const o=await fetch("/api/system/restart/status");if(o.ok){const j=await o.json();t(j),j.phase==="restarting"&&p()}}catch{p()}},1e3),()=>{n=!0,c&&clearInterval(c),m&&clearInterval(m)}},[]);const d=l?Object.entries(l.agents):[];function i(n){return n==="ready"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-emerald-500/20 text-emerald-300",children:"ready"}):n==="timeout"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-amber-500/20 text-amber-300",children:"timeout"}):n==="error"?e.jsx("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-red-500/20 text-red-300",children:"error"}):e.jsxs("span",{className:"text-[10px] px-1.5 py-0.5 rounded bg-sky-500/20 text-sky-300 flex items-center gap-1",children:[e.jsx(P,{size:10,className:"animate-spin"}),n]})}return e.jsx("div",{role:"dialog","aria-modal":"true","aria-label":"Restart progress",className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:e.jsxs("div",{className:"bg-shell-surface border border-white/10 rounded-xl p-6 w-full max-w-md shadow-xl space-y-4",children:[e.jsx("h3",{className:"text-base font-semibold",children:x?"Restarted — reloading…":d.length>0?"Preparing agents for restart":"Restarting server…"}),d.length>0&&e.jsx("ul",{className:"space-y-1","aria-label":"Agent preparation status",children:d.map(([n,c])=>e.jsxs("li",{className:"flex items-center justify-between text-sm",children:[e.jsx("span",{className:"text-shell-text-secondary",children:n}),i(c.status)]},n))}),(l==null?void 0:l.phase)==="restarting"&&!x&&e.jsx("p",{className:"text-xs text-shell-text-tertiary",children:"Waiting for server to come back…"}),!l&&e.jsxs("p",{className:"text-xs text-shell-text-tertiary flex items-center gap-1",children:[e.jsx(P,{size:12,className:"animate-spin"})," Connecting…"]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(b,{variant:"outline",size:"sm",onClick:r,"aria-label":"Cancel restart progress dialog",children:"Cancel"})})]})})}function Se(){const[r,l]=s.useState(!1),[t,x]=s.useState(!1),[a,d]=s.useState(null),[i,n]=s.useState(null),[c,m]=s.useState({check_enabled:!0,auto_apply:!1,auto_restart:!1}),[h,p]=s.useState(null),[o,j]=s.useState(!1),[v,k]=s.useState(!1);s.useEffect(()=>{(async()=>{try{const y=await fetch("/api/preferences/auto-update");if(y.ok){const u=await y.json();u&&typeof u=="object"&&m({check_enabled:u.check_enabled??!0,auto_apply:u.auto_apply??!1,auto_restart:u.auto_restart??!1})}}catch{}try{const y=await fetch("/api/settings/update-check");y.ok&&d(await y.json())}catch{}try{const y=await fetch("/api/settings/update-status");y.ok&&p(await y.json())}catch{}})()},[]);const S=s.useCallback(async y=>{m(y);try{await fetch("/api/preferences/auto-update",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(y)})}catch{}},[]),g=async()=>{l(!0),n(null);try{const y=await fetch("/api/settings/update-check");if(y.ok){const u=await y.json();d(u),n(u.has_updates?"A new version is available.":"You are up to date.")}else n("Update check not available.")}catch{n("Could not reach update server.")}l(!1)},R=async()=>{x(!0),n(null);try{const y=await fetch("/api/settings/update",{method:"POST"});if(y.ok){const u=await y.json().catch(()=>({}));if(u.status==="restarting")j(!0);else{n(u.message??"Update applied. Restart the server to finish."),k(!0);const U=await fetch("/api/settings/update-check");U.ok&&d(await U.json());const C=await fetch("/api/settings/update-status");C.ok&&p(await C.json())}}else{const u=await y.json().catch(()=>({}));n(u.error??"Update failed.")}}catch{n("Could not apply update.")}x(!1)},_=async()=>{j(!0);try{await fetch("/api/system/restart/prepare",{method:"POST"})}catch{}},I=!!(h!=null&&h.pending_restart_sha);return e.jsxs("section",{"aria-label":"System updates",children:[e.jsx("h2",{className:"text-lg font-semibold mb-5",children:"Updates"}),I&&e.jsxs("div",{className:"mb-4 flex items-center justify-between gap-3 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-amber-200",children:[e.jsx(F,{size:16,className:"shrink-0"}),e.jsxs("span",{children:["Update pulled — restart to finish applying (",h.pending_restart_sha.slice(0,7),")"]})]}),e.jsx(b,{size:"sm",onClick:_,"aria-label":"Restart server to apply update",children:"Restart now"})]}),e.jsxs(w,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"p-2 rounded-lg bg-white/5 text-sky-400",children:e.jsx(xe,{size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"taOS"}),a!=null&&a.has_updates&&a.new_commit?e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsxs("p",{className:"text-xs text-shell-text-tertiary tabular-nums",children:[e.jsx("span",{className:"text-white/40",children:"installed "}),a.current_commit]}),e.jsxs("p",{className:"text-xs text-amber-300/90 tabular-nums",children:[e.jsx("span",{className:"text-amber-300/50",children:"available "}),a.new_commit]})]}):e.jsx("p",{className:"text-xs text-shell-text-tertiary tabular-nums",children:(a==null?void 0:a.current_commit)??"v0.1.0-dev"})]}),(a==null?void 0:a.has_updates)&&e.jsx("span",{className:"text-[10px] px-2 py-1 rounded-full font-semibold bg-amber-500/20 text-amber-300",children:"Update available"})]}),e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[e.jsxs(b,{variant:"outline",size:"sm",onClick:g,disabled:r,children:[e.jsx(P,{size:14,className:r?"animate-spin":""}),r?"Checking...":"Check Now"]}),v?e.jsx(b,{size:"sm",onClick:_,"aria-label":"Restart server to apply update",children:"Restart Now"}):a!=null&&a.has_updates?e.jsx(b,{size:"sm",onClick:R,disabled:t,children:t?"Installing...":"Install Update"}):null]}),i&&e.jsxs("div",{className:"flex items-start gap-2 text-xs",children:[i.includes("up to date")||i.includes("applied")?e.jsx(D,{size:14,className:"text-emerald-400 shrink-0 mt-0.5"}):e.jsx(F,{size:14,className:"text-amber-400 shrink-0 mt-0.5"}),e.jsx("span",{className:"text-shell-text-secondary",children:i})]}),e.jsxs("div",{className:"border-t border-white/5 pt-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Check for updates automatically"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:"Polls GitHub hourly and notifies when a new version is available."})]}),e.jsx(T,{checked:c.check_enabled??!0,onCheckedChange:y=>S({...c,check_enabled:y})})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Install updates automatically"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:"Pulls + installs new versions as soon as they're detected. You'll still need to restart the server manually."})]}),e.jsx(T,{checked:c.auto_apply??!1,onCheckedChange:y=>S({...c,auto_apply:y}),disabled:!(c.check_enabled??!0)})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx(N,{className:"text-sm",children:"Automatically restart after update"}),e.jsx("p",{className:"text-[11px] text-shell-text-tertiary mt-0.5",children:c.auto_restart?"Server will restart automatically once an update is pulled.":"We'll remind you every 6 hours when a restart is pending."})]}),e.jsx(T,{checked:c.auto_restart??!1,onCheckedChange:y=>S({...c,auto_restart:y}),"aria-label":"Automatically restart after update"})]})]})]}),o&&e.jsx(W,{onClose:()=>j(!1)})]})}function Ce(){const[r,l]=s.useState(`# taOS Configuration | |||
There was a problem hiding this comment.
Default YAML template is malformed (embedded line numbers).
At Line 1 (function Ce), the initial config string includes literal lines 2, 3, 4, … 15, which makes the default YAML invalid and can lead to bad saves when backend config load fails.
Proposed fix
-const[r,l]=s.useState(`# taOS Configuration
-2
-# Edit YAML below
-3
-
-4
-server:
-5
- port: 3000
-6
- host: 0.0.0.0
-7
-
-8
-agents:
-9
- max_concurrent: 5
-10
- default_model: qwen2.5-7b
-11
-
-12
-providers:
-13
- - name: rkllama
-14
- url: http://localhost:8080
-15
-`)
+const[r,l]=s.useState(`# taOS Configuration
+# Edit YAML below
+
+server:
+ port: 3000
+ host: 0.0.0.0
+
+agents:
+ max_concurrent: 5
+ default_model: qwen2.5-7b
+
+providers:
+ - name: rkllama
+ url: http://localhost:8080
+`)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/SettingsApp-Dxe4E4Jg.js` at line 1, The default YAML
template in function Ce contains embedded literal line numbers (e.g. "2", "3",
…) making the config invalid; replace the initial useState string in Ce with a
clean, valid YAML template (no line-number markers) that reflects expected keys
(e.g. top-level comments and example fields) so backend saves/loads valid YAML
when defaults are used.
…tag in dialog (kilo + coderabbit)
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
docs/superpowers/notes/2026-04-19-multi-framework-chat-routing.md (1)
44-50: Convert ephemeral “not yet in git” notes into durable tracking references.This section will age quickly and become misleading. Prefer linking to an issue/branch name or attaching a patch reference so the note stays actionable.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/superpowers/notes/2026-04-19-multi-framework-chat-routing.md` around lines 44 - 50, Replace the ephemeral “not yet in git” note with durable tracking references: create a short-lived branch (e.g., pi-experimental-install-script) containing the changes to deployer.py and scripts/install_hermes.sh, open an issue summarizing the experiment and link that branch, and/or attach a patch (git format-patch or the Pi’s stash/commit hash) to the issue; update this document to point to the issue/branch/patch reference so readers can find the exact changes later rather than relying on transient local edits.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/superpowers/notes/2026-04-19-multi-framework-chat-routing.md`:
- Around line 46-50: Replace the exposed private LAN IP and personal home path
in the note with redacted placeholders (e.g., "<REDACTED_IP>" and
"<REDACTED_USER_PATH>") so the lines that mention the Pi and local edits no
longer contain "192.168.6.123" or "/home/jay/tinyagentos"; update the text in
the note file(s) (deployer.py mention and install_hermes.sh reference) to use
those placeholders and commit the change, and if the sensitive strings were
already committed to history run an appropriate history-rewrite (interactive
rebase or git-filter-repo) to purge them from the repo history before pushing.
In `@static/desktop/assets/StoreApp-CaxvIj4e.js`:
- Line 1: The catalog parsing in the be component sets compat unconditionally to
"green" when the server response lacks compat (inside the h callback where it
builds y with compat:m.compat??"green"), causing all items to appear compatible;
update the parsing logic in the h callback (the fetch("/api/store/catalog")
handler in function be) to derive compat from m.hardware_tiers (or respect a
provided compat field) instead of defaulting to "green" — compute a resolved
compat value (green/yellow/red) from hardware_tiers (or treat missing compat as
unknown and show a neutral badge) and assign that to the compat property in the
mapped object so the UI reflects real compatibility.
- Line 1: Summary: The fallback catalog `ae` hardcodes installed:true for some
apps, causing incorrect UI/uninstall calls; replace it with metadata-only
entries that default installed state to false (or remove the installed field)
and use that in the fallback path inside be (where g(ae) is called). Fix: create
a metadata-only fallback constant (e.g., fallbackCatalogMetadata or sanitize
`ae`) that ensures every entry has installed:false (or no installed property),
then update the effect in be (the useEffect that does `!await
h()&&!s&&(g(ae),x(!1))`) to call g with the sanitized fallback; keep other
symbols the same (ae, be, g) so lookup is straightforward.
---
Nitpick comments:
In `@docs/superpowers/notes/2026-04-19-multi-framework-chat-routing.md`:
- Around line 44-50: Replace the ephemeral “not yet in git” note with durable
tracking references: create a short-lived branch (e.g.,
pi-experimental-install-script) containing the changes to deployer.py and
scripts/install_hermes.sh, open an issue summarizing the experiment and link
that branch, and/or attach a patch (git format-patch or the Pi’s stash/commit
hash) to the issue; update this document to point to the issue/branch/patch
reference so readers can find the exact changes later rather than relying on
transient local edits.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8b70aa92-37b0-4975-9845-11eb79c35c78
📒 Files selected for processing (11)
desktop/src/components/agent-settings/FrameworkTab.tsxdocs/superpowers/notes/2026-04-19-multi-framework-chat-routing.mdstatic/desktop/assets/AgentsApp-D8hlDDmJ.jsstatic/desktop/assets/MCPApp-Ci8OBr3I.jsstatic/desktop/assets/ProvidersApp-_hGWvOIX.jsstatic/desktop/assets/SettingsApp-B0L5VU3t.jsstatic/desktop/assets/StoreApp-CaxvIj4e.jsstatic/desktop/assets/framework-api-B6uX1y0T.jsstatic/desktop/assets/main-BPhVBqDl.jsstatic/desktop/index.htmltinyagentos/frameworks.py
✅ Files skipped from review due to trivial changes (3)
- static/desktop/assets/MCPApp-Ci8OBr3I.js
- static/desktop/assets/SettingsApp-B0L5VU3t.js
- static/desktop/assets/ProvidersApp-_hGWvOIX.js
🚧 Files skipped from review as they are similar to previous changes (1)
- desktop/src/components/agent-settings/FrameworkTab.tsx
| @@ -0,0 +1 @@ | |||
| import{r,j as t}from"./vendor-react-l6srOxy7.js";import{B as A,I as D,C as B,a as F,c as W,k as G}from"./toolbar-UW6q5pkx.js";import{a as E}from"./framework-api-B6uX1y0T.js";import{am as z,S as _,Y as I,an as T,v as K,ao as L,ap as V,C as P,u as R,aq as U,I as H,ar as $,as as Y,_ as Z,H as J,f as X,y as ee,ad as te}from"./vendor-icons-DcMSPw1y.js";import"./vendor-radix-BhM7AEEG.js";import"./vendor-layout-B-pp9n1f.js";const S=[{id:"all",label:"All Apps",icon:t.jsx(z,{size:16}),types:[],description:"Browse everything"},{id:"frameworks",label:"Agent Frameworks",icon:t.jsx(K,{size:16}),types:["agent-framework"],description:"Execution engines for your AI agents"},{id:"models",label:"Models",icon:t.jsx(L,{size:16}),types:["model"],description:"Language models for inference"},{id:"memory",label:"Memory",icon:t.jsx(L,{size:16}),types:["memory"],description:"Memory backends and knowledge stores for agents"},{id:"plugins",label:"Plugins",icon:t.jsx(V,{size:16}),types:["plugin"],description:"Tools and capabilities for agents"},{id:"mcp-server",label:"MCP Servers",icon:t.jsx(P,{size:16}),types:["mcp"],description:"Model Context Protocol servers"},{id:"services",label:"Services",icon:t.jsx(R,{size:16}),types:["service"],description:"Infrastructure and backends"},{id:"streaming",label:"Streaming Apps",icon:t.jsx(U,{size:16}),types:["streaming-app"],description:"Desktop apps streamed via KasmVNC"},{id:"image",label:"Image Generation",icon:t.jsx(H,{size:16}),types:["image-gen","image-model"],description:"Stable Diffusion and image models"},{id:"audio",label:"Audio & Voice",icon:t.jsx($,{size:16}),types:["voice","audio"],description:"TTS, STT, and music generation"},{id:"video",label:"Video",icon:t.jsx(Y,{size:16}),types:["video-gen"],description:"Video generation tools"},{id:"devtools",label:"Dev Tools",icon:t.jsx(Z,{size:16}),types:["dev-tool"],description:"Development and coding tools"},{id:"home",label:"Home & Monitor",icon:t.jsx(J,{size:16}),types:["home","monitoring"],description:"Home automation and monitoring"},{id:"infra",label:"Infrastructure",icon:t.jsx(P,{size:16}),types:["infrastructure"],description:"System services and networking"}],ae=[{id:"smolagents",name:"SmolAgents",type:"agent-framework",version:"1.0.0",description:"HuggingFace code-based agents — well-documented, 26k stars",installed:!1,compat:"green"},{id:"pocketflow",name:"PocketFlow",type:"agent-framework",version:"1.0.0",description:"Minimal 100-line framework, zero deps, graph-based",installed:!1,compat:"green"},{id:"openclaw",name:"OpenClaw",type:"agent-framework",version:"1.0.0",description:"Full-featured multi-channel agent framework",installed:!0,compat:"green"},{id:"langroid",name:"Langroid",type:"agent-framework",version:"1.0.0",description:"Multi-agent message-passing framework",installed:!1,compat:"green"},{id:"openai-agents-sdk",name:"OpenAI Agents SDK",type:"agent-framework",version:"1.0.0",description:"Provider-agnostic agent SDK from OpenAI",installed:!1,compat:"green"},{id:"qwen3-4b",name:"Qwen3 4B",type:"model",version:"3.0.0",description:"Good balance of speed and capability for most tasks",installed:!0,compat:"green"},{id:"qwen3-1.7b",name:"Qwen3 1.7B",type:"model",version:"3.0.0",description:"Fast, fits comfortably in 8GB RAM",installed:!1,compat:"green"},{id:"qwen3-8b",name:"Qwen3 8B",type:"model",version:"3.0.0",description:"Most capable local model for 16GB devices",installed:!1,compat:"yellow"},{id:"mcp-pandoc",name:"MCP Pandoc",type:"mcp",version:"0.1.0",description:"Document format conversion — markdown, docx, pdf, 30+ formats",installed:!1,compat:"green"},{id:"mcp-server-office",name:"MCP Office Docs",type:"mcp",version:"0.1.0",description:"Read, write, and edit .docx files programmatically",installed:!1,compat:"green"},{id:"playwright-mcp",name:"Playwright MCP",type:"mcp",version:"1.0.0",description:"Browser automation for agents via Playwright",installed:!1,compat:"green"},{id:"github-mcp-server",name:"GitHub MCP",type:"mcp",version:"1.0.0",description:"Issues, PRs, repos, search — official GitHub MCP",installed:!1,compat:"green"},{id:"mcp-memory",name:"MCP Memory",type:"mcp",version:"1.0.0",description:"Knowledge graph memory for persistent context",installed:!1,compat:"green"},{id:"web-search",name:"Web Search",type:"plugin",version:"0.3.0",description:"Search the web via SearXNG or Perplexica",installed:!1,compat:"green"},{id:"image-generation-tool",name:"Image Generation",type:"plugin",version:"0.1.0",description:"Generate images via Stable Diffusion",installed:!1,compat:"green"},{id:"searxng",name:"SearXNG",type:"service",version:"latest",description:"Privacy-respecting metasearch engine",installed:!1,compat:"green"},{id:"gitea",name:"Gitea",type:"service",version:"latest",description:"Lightweight self-hosted Git service",installed:!1,compat:"green"},{id:"n8n",name:"n8n",type:"service",version:"latest",description:"Workflow automation platform",installed:!1,compat:"green"},{id:"code-server-kasm",name:"Code Server (Streamed)",type:"streaming-app",version:"latest",description:"VS Code in the browser via KasmVNC",installed:!1,compat:"green"},{id:"blender",name:"Blender",type:"streaming-app",version:"latest",description:"3D creation suite streamed via KasmVNC",installed:!1,compat:"yellow"},{id:"libreoffice",name:"LibreOffice",type:"streaming-app",version:"latest",description:"Full office suite streamed via KasmVNC",installed:!1,compat:"green"},{id:"comfyui",name:"ComfyUI",type:"image-gen",version:"latest",description:"Node-based Stable Diffusion workflow editor",installed:!1,compat:"yellow"},{id:"fooocus",name:"Fooocus",type:"image-gen",version:"latest",description:"Simple Stable Diffusion with minimal setup",installed:!1,compat:"yellow"},{id:"kokoro-tts",name:"Kokoro TTS",type:"voice",version:"latest",description:"High-quality text-to-speech",installed:!1,compat:"green"},{id:"whisper-stt",name:"Whisper STT",type:"voice",version:"latest",description:"OpenAI Whisper speech-to-text",installed:!1,compat:"green"},{id:"animatediff",name:"AnimateDiff",type:"video-gen",version:"latest",description:"AI video generation from text and images",installed:!1,compat:"yellow"},{id:"corridorkey",name:"CorridorKey",type:"video-gen",version:"latest",description:"AI video generation via ComfyUI workflows",installed:!1,compat:"yellow"},{id:"code-server",name:"Code Server",type:"dev-tool",version:"latest",description:"VS Code in the browser — remote development environment",installed:!1,compat:"green"},{id:"jupyter-lab",name:"JupyterLab",type:"dev-tool",version:"latest",description:"Interactive notebooks for data science and experimentation",installed:!1,compat:"green"},{id:"home-assistant",name:"Home Assistant",type:"home",version:"latest",description:"Open-source home automation platform",installed:!1,compat:"green"},{id:"uptime-kuma",name:"Uptime Kuma",type:"monitoring",version:"latest",description:"Self-hosted monitoring tool — track uptime for services and APIs",installed:!1,compat:"green"},{id:"tailscale",name:"Tailscale",type:"infrastructure",version:"latest",description:"Zero-config mesh VPN for secure networking between devices",installed:!1,compat:"green"},{id:"caddy",name:"Caddy",type:"infrastructure",version:"latest",description:"Automatic HTTPS reverse proxy and web server",installed:!1,compat:"green"}],se={"agent-framework":"bg-blue-500/20 text-blue-400",model:"bg-slate-500/20 text-slate-400",service:"bg-amber-500/20 text-amber-400",plugin:"bg-teal-500/20 text-teal-400",mcp:"bg-violet-500/20 text-violet-400","streaming-app":"bg-indigo-500/20 text-indigo-400","image-gen":"bg-pink-500/20 text-pink-400","image-model":"bg-pink-500/20 text-pink-400",voice:"bg-orange-500/20 text-orange-400",audio:"bg-orange-500/20 text-orange-400","video-gen":"bg-red-500/20 text-red-400","dev-tool":"bg-cyan-500/20 text-cyan-400",home:"bg-green-500/20 text-green-400",monitoring:"bg-green-500/20 text-green-400",infrastructure:"bg-slate-500/20 text-slate-400"},ie={"agent-framework":"Framework",model:"Model",service:"Service",plugin:"Plugin",mcp:"MCP Server","streaming-app":"Streaming","image-gen":"Image Gen","image-model":"Image Model",voice:"Voice",audio:"Audio","video-gen":"Video","dev-tool":"Dev Tool",home:"Home",monitoring:"Monitor",infrastructure:"Infra"},ne={green:"bg-emerald-400",yellow:"bg-amber-400",red:"bg-red-400"},re={green:"Compatible",yellow:"Partial",red:"Unsupported"},oe={"agent-framework":"linear-gradient(135deg, rgba(59,130,246,0.3), rgba(59,130,246,0.1))",model:"linear-gradient(135deg, rgba(139,92,246,0.3), rgba(139,92,246,0.1))",service:"linear-gradient(135deg, rgba(245,158,11,0.3), rgba(245,158,11,0.1))",plugin:"linear-gradient(135deg, rgba(20,184,166,0.3), rgba(20,184,166,0.1))","streaming-app":"linear-gradient(135deg, rgba(99,102,241,0.3), rgba(99,102,241,0.1))","image-gen":"linear-gradient(135deg, rgba(236,72,153,0.3), rgba(236,72,153,0.1))",voice:"linear-gradient(135deg, rgba(249,115,22,0.3), rgba(249,115,22,0.1))","dev-tool":"linear-gradient(135deg, rgba(6,182,212,0.3), rgba(6,182,212,0.1))"},a=i=>`https://cdn.simpleicons.org/${i}/ffffff`,e=i=>`https://github.com/${i}.png?size=96`,q={smolagents:e("huggingface"),pocketflow:e("The-Pocket"),openclaw:"/static/store-icons/openclaw.jpg",nanoclaw:e("openclaw"),picoclaw:"https://raw.githubusercontent.com/sipeed/picoclaw/main/assets/logo.webp",zeroclaw:e("nicholasgasior"),microclaw:e("nicholasgasior"),ironclaw:e("nicholasgasior"),nullclaw:e("nicholasgasior"),shibaclaw:"https://raw.githubusercontent.com/RikyZ90/ShibaClaw/main/assets/shibaclaw_logo.png",moltis:e("moltis-ai"),hermes:e("NousResearch"),"agent-zero":e("frdel"),"openai-agents-sdk":a("openai"),langroid:e("langroid"),"qwen2.5-0.5b":e("QwenLM"),"qwen2.5-1.5b":e("QwenLM"),"qwen2.5-3b":e("QwenLM"),"qwen2.5-7b":e("QwenLM"),"qwen2.5-14b":e("QwenLM"),"qwen2.5-32b":e("QwenLM"),"qwen2.5-72b":e("QwenLM"),"qwen2.5-1.5b-rkllm":e("QwenLM"),"qwen2.5-3b-rkllm":e("QwenLM"),"qwen2.5-7b-rkllm":e("QwenLM"),"qwen2.5-14b-rkllm":e("QwenLM"),"qwen2.5-coder-7b":e("QwenLM"),"qwen2.5-coder-14b":e("QwenLM"),"qwen2.5-vl-7b":e("QwenLM"),"qwen2-vl-7b":e("QwenLM"),"qwen3-1.7b":e("QwenLM"),"qwen3-4b":e("QwenLM"),"qwen3-8b":e("QwenLM"),"qwen3-14b":e("QwenLM"),"qwen3-30b-a3b":e("QwenLM"),"qwen3-32b":e("QwenLM"),"qwen3-embedding-0.6b":e("QwenLM"),"qwen3-reranker-0.6b":e("QwenLM"),"llama-3.1-8b":a("meta"),"llama-3.2-1b":a("meta"),"llama-3.2-3b":a("meta"),"llama-3.3-70b":a("meta"),"llama-3-70b":a("meta"),"gemma-2-2b":a("googlegemini"),"gemma-2-9b":a("googlegemini"),"gemma-3-1b":a("googlegemini"),"gemma-3-4b":a("googlegemini"),"gemma-3-12b":a("googlegemini"),"phi-3.5-mini":e("microsoft"),"phi-4":e("microsoft"),"phi-4-mini":e("microsoft"),"mistral-7b-v0.3":e("mistralai"),"mistral-nemo-12b":e("mistralai"),"mixtral-8x7b":e("mistralai"),"ministral-3b":e("mistralai"),"deepseek-r1-14b":e("deepseek-ai"),"deepseek-coder-v2-lite":e("deepseek-ai"),"granite-3.1-2b":e("ibm-granite"),"granite-3.1-8b":e("ibm-granite"),"command-r-35b":e("cohere"),smollm2:e("huggingface"),"smollm2-135m":e("huggingface"),"smollm2-360m":e("huggingface"),"tinyllama-1.1b":e("jzhang38"),"nemotron-mini-4b":e("NVIDIA"),"pelochus-qwen-1.8b-rkllm":e("pelochus"),"llava-1.6-mistral-7b":e("haotian-liu"),"llava-phi-3-mini":e("haotian-liu"),"minicpm-v-2.6":e("OpenBMB"),moondream2:e("vikhyat"),"florence-2-base":e("microsoft"),"bge-large-en-v1.5":e("FlagOpen"),"bge-small-en-v1.5":e("FlagOpen"),"bge-m3":e("FlagOpen"),"bge-reranker-v2-m3":e("FlagOpen"),"nomic-embed-text-v1.5":e("nomic-ai"),"mxbai-embed-large":e("mixedbread-ai"),"snowflake-arctic-embed-m":e("Snowflake-Labs"),"whisper-tiny":a("openai"),"whisper-base":a("openai"),"whisper-small":a("openai"),"whisper-medium":a("openai"),"whisper-large-v3":a("openai"),"whisper-large-v3-turbo":a("openai"),"kokoro-tts":e("hexgrad"),"piper-en-lessac":e("rhasspy"),"parakeet-tdt-0.6b":e("NVIDIA"),"sd-v1.5-lcm":e("Stability-AI"),"dreamshaper-8-lcm":e("Lykon"),"lcm-dreamshaper-v7":e("Lykon"),"sdxl-turbo":e("Stability-AI"),"sdxl-lightning":e("ByteDance"),"sd3.5-large-turbo-gguf":e("Stability-AI"),"flux-dev-gguf":e("black-forest-labs"),"flux-schnell-gguf":e("black-forest-labs"),"flux-schnell-unsloth":e("black-forest-labs"),"pixart-sigma-512":e("PixArt-alpha"),"sdxs-512":e("IDKiro"),"playground-v2.5":e("playgroundai"),kolors:e("Kwai-Kolors"),"auraflow-v0.3":e("cloneofsimo"),"stable-cascade":e("Stability-AI"),"rmbg-1.4":e("briaai"),birefnet:e("ZhengPeng7"),"real-esrgan-x4":e("xinntao"),"4x-ultrasharp":e("xinntao"),"gfpgan-v1.4":e("TencentARC"),codeformer:e("sczhou"),"controlnet-canny":e("lllyasviel"),"controlnet-depth":e("lllyasviel"),"controlnet-openpose":e("lllyasviel"),"controlnet-openpose-sdxl":e("lllyasviel"),comfyui:e("comfyanonymous"),fooocus:e("lllyasviel"),"stable-diffusion-webui":e("AUTOMATIC1111"),"stable-diffusion-cpp":e("leejet"),fastsdcpu:e("rupeshs"),"rk-llama-cpp":e("marty1885"),"rk3588-sd-gpu":e("happyme531"),"rknn-stable-diffusion":e("happyme531"),"lcm-dreamshaper-rknn":e("happyme531"),"ltx-video":e("Lightricks"),wan2gp:e("alibaba"),musicgpt:e("gabotechs"),searxng:a("searxng"),gitea:a("gitea"),"code-server":e("coder"),n8n:a("n8n"),"home-assistant":a("homeassistant"),"uptime-kuma":a("uptimekuma"),filebrowser:e("filebrowser"),excalidraw:a("excalidraw"),memos:e("usememos"),linkwarden:e("linkwarden"),"open-webui":e("open-webui"),dify:e("langgenius"),perplexica:e("ItzCrazyKns"),litellm:e("BerriAI"),"stirling-pdf":e("Stirling-Tools"),"paperless-ngx":e("paperless-ngx"),docling:e("DS4SD"),libretranslate:e("LibreTranslate"),mailserver:e("docker-mailserver"),"chatterbox-tts":e("resemble-ai"),"piper-tts":e("rhasspy"),"kokoro-tts-server":e("remsky"),tailscale:a("tailscale"),ddns:e("ddclient"),exo:e("exo-explore"),"github-mcp-server":a("github"),"git-mcp":a("git"),"mcp-git":a("git"),"mcp-filesystem":e("modelcontextprotocol"),"mcp-fetch":e("modelcontextprotocol"),"mcp-memory":e("modelcontextprotocol"),"mcp-time":e("modelcontextprotocol"),"mcp-sequential-thinking":e("modelcontextprotocol"),"playwright-mcp":a("playwright"),"mcp-server-docker":a("docker"),"mcp-server-kubernetes":a("kubernetes"),"mongodb-mcp-server":a("mongodb"),"mcp-redis":a("redis"),"chroma-mcp":e("chroma-core"),"supabase-mcp":a("supabase"),dbhub:a("postgresql"),"mcp-toolbox-databases":e("googleapis"),"notion-mcp-server":a("notion"),"mcp-obsidian":a("obsidian"),"mcp-atlassian":a("atlassian"),"google-workspace-mcp":a("google"),"slack-mcp-server":a("slack"),"whatsapp-mcp":a("whatsapp"),"ha-mcp":a("homeassistant"),"mcp-email-server":e("modelcontextprotocol"),"aws-mcp":a("amazonaws"),"cloudflare-mcp":a("cloudflare"),"mcp-grafana":a("grafana"),"arxiv-mcp-server":a("arxiv"),"firecrawl-mcp":e("mendableai"),"exa-mcp-server":e("exa-labs"),"context7-mcp":e("upstash"),supergateway:e("supercorp-ai"),"browser-use-mcp":e("browser-use"),camoufox:e("daijro"),engram:e("engramhq"),"mcp-pandoc":e("jgeorgeson"),"mcp-server-office":e("GongRzhe"),"mcp-server-spreadsheet":e("GongRzhe"),"excel-mcp-server":e("haris-musa"),"markdownify-mcp":e("zcaceres"),"desktop-commander-mcp":e("wonderwhy-er"),mcpo:e("open-webui"),"youtube-transcript-mcp":a("youtube"),"todoist-mcp-server":a("todoist"),playwriter:a("playwright"),"image-generation-tool":e("comfyanonymous"),"code-server-kasm":e("coder"),blender:a("blender"),libreoffice:a("libreoffice"),"jupyter-lab":a("jupyter"),caddy:e("caddyserver"),animatediff:e("guoyww"),corridorkey:e("comfyanonymous"),"whisper-stt":a("openai")};function le(i){return q[i]?q[i]:i.startsWith("qwen")?e("QwenLM"):i.startsWith("llama")?a("meta"):i.startsWith("gemma")?a("googlegemini"):i.startsWith("phi-")?e("microsoft"):i.startsWith("whisper")?a("openai"):i.startsWith("deepseek")?e("deepseek-ai"):i.startsWith("mistral")||i.startsWith("mixtral")?e("mistralai"):i.startsWith("bge-")?e("FlagOpen"):i.startsWith("controlnet")?e("lllyasviel"):i.startsWith("flux-")?e("black-forest-labs"):i.startsWith("sd-")||i.startsWith("sdxl")||i.startsWith("sd3")?e("Stability-AI"):null}function ce({app:i,affected:p,onInstall:g,onUninstall:b}){const[v,c]=r.useState(!1),[u,N]=r.useState(!1),[x,w]=r.useState(null),k=le(i.id),C=async()=>{c(!0),w(null);try{const f=i.installed?"/api/store/uninstall":"/api/store/install",h=await fetch(f,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({app_id:i.id})});if(!h.ok){let l=`${i.installed?"Uninstall":"Install"} failed (${h.status})`;try{const d=await h.json();d!=null&&d.error&&(l=String(d.error))}catch{}w(l),c(!1);return}i.installed?b(i.id):g(i.id)}catch(f){w(f instanceof Error?f.message:"Network error")}c(!1)};return t.jsxs(B,{className:"flex flex-col rounded-2xl hover:-translate-y-0.5 hover:shadow-2xl hover:border-white/[0.12] transition-all duration-200",children:[t.jsx(F,{className:"p-5 pb-2",children:t.jsxs("div",{className:"flex items-start justify-between",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"w-11 h-11 rounded-xl flex items-center justify-center shrink-0 overflow-hidden",style:{background:oe[i.type]??"rgba(255,255,255,0.06)"},children:k&&!u?t.jsx("img",{src:k,alt:"",className:"w-7 h-7 object-contain",onError:()=>N(!0),loading:"lazy"}):t.jsx(T,{className:"w-5 h-5 text-white/60"})}),t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[t.jsx("span",{className:"font-medium text-white/90 truncate text-sm",children:i.name}),i.installed&&t.jsx(X,{className:"w-3.5 h-3.5 text-emerald-400 shrink-0"}),p>0&&t.jsxs("span",{className:"bg-yellow-700/30 text-yellow-200 text-xs px-2 py-0.5 rounded ml-2 shrink-0",children:["Update available · ",p," ",p===1?"agent":"agents"]})]}),t.jsxs("span",{className:"text-[11px] text-white/30",children:["v",i.version]})]})]}),t.jsx("div",{className:"flex items-center gap-1",title:re[i.compat],children:t.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${ne[i.compat]}`})})]})}),t.jsxs(W,{className:"px-5 py-2 flex flex-col gap-3 flex-1",children:[t.jsx("span",{className:`text-[10px] font-medium px-2 py-0.5 rounded-full w-fit ${se[i.type]??"bg-white/10 text-white/50"}`,children:ie[i.type]??i.type}),t.jsx("p",{className:"text-xs text-white/45 leading-relaxed flex-1",children:i.description})]}),t.jsxs(G,{className:"p-5 pt-2 flex flex-col gap-2 items-stretch",children:[x&&t.jsx("div",{role:"alert",className:"text-[11px] text-red-300 bg-red-500/10 border border-red-500/20 rounded px-2 py-1",children:x}),t.jsx(A,{variant:i.installed?"destructive":"default",size:"sm",className:"w-full",onClick:C,disabled:v,children:v?t.jsx(I,{className:"w-3.5 h-3.5 animate-spin"}):i.installed?t.jsxs(t.Fragment,{children:[t.jsx(ee,{className:"w-3.5 h-3.5"})," Uninstall"]}):t.jsxs(t.Fragment,{children:[t.jsx(te,{className:"w-3.5 h-3.5"})," Install"]})})]})]})}function be({windowId:i}){const[p,g]=r.useState([]),[b,v]=r.useState(""),[c,u]=r.useState("all"),[N,x]=r.useState(!0),[w,k]=r.useState({}),[C,f]=r.useState([]),h=r.useCallback(async()=>{try{const s=await fetch("/api/store/catalog",{headers:{Accept:"application/json"}}),n=s.headers.get("content-type")??"";if(s.ok&&n.includes("application/json")){const o=await s.json();if(Array.isArray(o)){const y=o.map(m=>({id:String(m.id),name:String(m.name??m.id),type:String(m.type??"plugin"),version:String(m.version??""),description:String(m.description??""),installed:!!m.installed,compat:m.compat??"green"}));return g(y),x(!1),!0}}}catch{}return!1},[]);r.useEffect(()=>{let s=!1;return(async()=>!await h()&&!s&&(g(ae),x(!1)))(),()=>{s=!0}},[h]),r.useEffect(()=>{const n=new URLSearchParams(window.location.hash.split("?")[1]||"").get("category");n&&u(n)},[]),r.useEffect(()=>{E().then(k).catch(()=>{}),fetch("/api/agents").then(s=>s.ok?s.json():[]).then(s=>f(Array.isArray(s)?s:(s==null?void 0:s.agents)??[])).catch(()=>{})},[]);const l=S.find(s=>s.id===c),d=p.filter(s=>{if(c!=="all"&&l&&!l.types.includes(s.type))return!1;if(b){const n=b.toLowerCase();return s.name.toLowerCase().includes(n)||s.description.toLowerCase().includes(n)}return!0}),O=r.useCallback(s=>{g(n=>n.map(o=>o.id===s?{...o,installed:!0}:o))},[]),Q=r.useCallback(s=>{g(n=>n.map(o=>o.id===s?{...o,installed:!1}:o))},[]),j={};for(const s of S){if(s.id==="all"){j[s.id]=p.length;continue}j[s.id]=p.filter(n=>s.types.includes(n.type)).length}const M=typeof window<"u"&&window.innerWidth<640;return t.jsxs("div",{className:`flex ${M?"flex-col":""} h-full overflow-hidden`,children:[M?t.jsx("div",{className:"flex overflow-x-auto gap-2 px-3 py-2 border-b border-shell-border shrink-0",children:S.map(s=>t.jsx(A,{variant:"outline",size:"sm",onClick:()=>u(s.id),className:`whitespace-nowrap rounded-full ${c===s.id?"bg-accent/15 text-accent border-accent/30":""}`,children:s.label},s.id))}):t.jsxs("div",{className:"w-52 shrink-0 border-r border-shell-border bg-shell-surface/30 flex flex-col overflow-y-auto",children:[t.jsx("div",{className:"px-3 py-3 border-b border-shell-border",children:t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(z,{size:16,className:"text-accent"}),t.jsx("span",{className:"text-sm font-medium text-shell-text",children:"Store"})]})}),t.jsx("nav",{className:"flex-1 py-2 px-2 space-y-0.5",children:S.map(s=>t.jsxs(A,{variant:"ghost",size:"sm",onClick:()=>u(s.id),className:`w-full justify-start gap-2.5 text-xs ${c===s.id?"bg-accent/15 text-accent hover:bg-accent/20 hover:text-accent":""}`,children:[t.jsx("span",{className:"shrink-0",children:s.icon}),t.jsx("span",{className:"flex-1 truncate text-left",children:s.label}),j[s.id]?t.jsx("span",{className:"text-[10px] text-shell-text-tertiary",children:j[s.id]}):null]},s.id))})]}),t.jsxs("div",{className:"flex-1 flex flex-col overflow-hidden",children:[t.jsxs("header",{className:"shrink-0 px-5 py-4 border-b border-shell-border",children:[t.jsxs("div",{className:"flex items-center justify-between mb-1",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-base font-medium text-shell-text",children:(l==null?void 0:l.label)??"All Apps"}),t.jsx("p",{className:"text-xs text-shell-text-tertiary",children:l==null?void 0:l.description})]}),t.jsxs("span",{className:"text-xs text-shell-text-tertiary",children:[d.length," apps"]})]}),t.jsxs("div",{className:"relative mt-3",children:[t.jsx(_,{className:"absolute left-3 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-shell-text-tertiary pointer-events-none z-10"}),t.jsx(D,{type:"text",placeholder:"Search...",value:b,onChange:s=>v(s.target.value),className:"pl-9","aria-label":"Search apps"})]})]}),t.jsx("div",{className:"flex-1 overflow-y-auto px-5 py-4",children:N?t.jsx("div",{className:"flex items-center justify-center h-40",children:t.jsx(I,{className:"w-6 h-6 text-shell-text-tertiary animate-spin"})}):d.length===0&&c==="memory"?t.jsxs("div",{className:"p-6 text-center opacity-70",children:["No third-party memory plugins yet. ",t.jsx("b",{children:"taOSmd"})," is installed by default and available on every agent."]}):d.length===0?t.jsxs("div",{className:"flex flex-col items-center justify-center h-40 text-shell-text-tertiary text-sm gap-2",children:[t.jsx(T,{className:"w-8 h-8"}),t.jsx("span",{children:"No apps in this category"})]}):t.jsx("div",{className:"grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] gap-4",children:d.map(s=>{const n=w[s.id],o=s.type==="agent-framework"?C.filter(y=>y.framework===s.id&&y.framework_version_sha&&n&&n.sha!==y.framework_version_sha).length:0;return t.jsx(ce,{app:s,affected:o,onInstall:O,onUninstall:Q},s.id)})})})]})]})}export{be as StoreApp,be as default}; | |||
There was a problem hiding this comment.
Compatibility is always shown as green with the current catalog mapping.
/api/store/catalog does not return a compat field, so compat:m.compat??"green" makes every server-backed item look fully compatible after load. That masks degraded/unsupported entries and makes the badge misleading. Either compute compatibility from hardware_tiers on the frontend or have the API include a resolved compat value.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/StoreApp-CaxvIj4e.js` at line 1, The catalog parsing in
the be component sets compat unconditionally to "green" when the server response
lacks compat (inside the h callback where it builds y with
compat:m.compat??"green"), causing all items to appear compatible; update the
parsing logic in the h callback (the fetch("/api/store/catalog") handler in
function be) to derive compat from m.hardware_tiers (or respect a provided
compat field) instead of defaulting to "green" — compute a resolved compat value
(green/yellow/red) from hardware_tiers (or treat missing compat as unknown and
show a neutral badge) and assign that to the compat property in the mapped
object so the UI reflects real compatibility.
The fallback catalog should not hardcode install state.
If /api/store/catalog fails, ae becomes the rendered source of truth, but it already marks some apps as installed. That can expose uninstall buttons for apps that are not actually installed on this machine and leads to confusing 404s from /api/store/uninstall. The fallback should be metadata-only and default installation state to unknown/false.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@static/desktop/assets/StoreApp-CaxvIj4e.js` at line 1, Summary: The fallback
catalog `ae` hardcodes installed:true for some apps, causing incorrect
UI/uninstall calls; replace it with metadata-only entries that default installed
state to false (or remove the installed field) and use that in the fallback path
inside be (where g(ae) is called). Fix: create a metadata-only fallback constant
(e.g., fallbackCatalogMetadata or sanitize `ae`) that ensures every entry has
installed:false (or no installed property), then update the effect in be (the
useEffect that does `!await h()&&!s&&(g(ae),x(!1))`) to call g with the
sanitized fallback; keep other symbols the same (ae, be, g) so lookup is
straightforward.
|
|
||
| log "writing /root/.hermes/.env (gateway env vars)" | ||
| mkdir -p /root/.hermes /root/.hermes/gateway | ||
| cat > /root/.hermes/.env <<ENVEOF |
There was a problem hiding this comment.
CRITICAL: Literal string "$MODEL" instead of variable value. This will set the model to the literal string "$MODEL" instead of the actual model name.
| cat > /root/.hermes/.env <<ENVEOF | |
| m["default"] = os.environ.get("TAOS_MODEL", "kilo-auto/free") |
Similarly for api_key:
| cat > /root/.hermes/.env <<ENVEOF | |
| m["api_key"] = os.environ["LITELLM_API_KEY"] |
Each install_<framework>.sh deploys a Python framework into an LXC agent
container and starts a small bridge that subscribes to taOS's SSE event
stream (the same one openclaw consumes), runs each user_message through
the framework, and posts replies back via /api/openclaw/sessions/{slug}/reply.
This makes any python-pip-installable framework chat-routable through
existing taOS infrastructure without taOS-side changes.
Frameworks supported:
- hermes (NousResearch/hermes-agent, custom provider → LiteLLM)
- smolagents
- langroid
- pocketflow
- openai-agents-sdk
Picked up by deployer.py's script-install branch (when
tinyagentos/scripts/install_<framework>.sh exists, it runs that instead
of the broken pip3 install <framework> fallback).
…nai-agents-sdk uses explicit OpenAIChatCompletionsModel
Hermes:
- 'hermes gateway start --run-as-user root' is wrong API. The real CLI is 'gateway run' for foreground (recommended for containers per Hermes' own docs). My systemd unit invokes that directly so we own the lifecycle.
- The 'custom' provider's api_key MUST be set in /root/.hermes/config.yaml (model.api_key); env vars and cli-config.yaml are NOT consulted by the gateway's credential pool. Without this, Hermes returns 'Missing Authentication header' from LiteLLM.
- API_SERVER_ENABLED/HOST/PORT are read as env vars to enable the api_server platform.
OpenAI Agents SDK:
- 'kilo-auto/free' breaks the SDK's provider-prefix parser ('Unknown prefix: kilo-auto'). Use OpenAIChatCompletionsModel(model=..., openai_client=AsyncOpenAI(base_url=..., api_key=...)) to bypass.
- set_tracing_disabled(True) avoids 401 noise from the SDK trying to phone home to OpenAI.
…sion prefers body channel_id Before: reply body didn't carry channel_id; bridge_session._handle_reply resolved each agent's DM channel by member lookup, so group-channel replies silently landed in the agent's DM. Fix threads channel_id from the inbound user_message event through the bridge's post_reply back into bridge_session, which prefers the body-supplied channel_id over its DM fallback.
…edoc Quote the python heredoc and pass values via env vars so any shell- special characters can't break the python string literal. Addresses kilo review on PR #233.
4831616 to
f49d5bd
Compare
|
Triaged review feedback (post force-push to f49d5bd): Addressed:
Deferred (pre-existing, out of scope for framework-update PR):
These are real bugs in pre-existing source surfaced because this PR rebuilds the desktop bundle. Tracking separately — fixing them here would expand the PR's blast radius. |
The openclaw fork's taos-bridge.ts doesn't forward the inbound user_message channel_id into its reply payload — the dispatcher only includes kind, id, trace_id, content. Without this fallback, an openclaw agent's reply to a group-channel message routed to the agent's DM instead, breaking multi-framework group chat. Since trace_id == originating message id (set in agent_chat_router), we can look up the original message and recover the source channel. Verified on Pi: john (openclaw) now replies in the roundtable channel alongside hermes, smolagents, langroid, pocketflow, and openai-agents-sdk.
|
Overnight update — 6-framework group chat working After landing the kilo/CodeRabbit triage commits, end-to-end tested the multi-framework chat in the roundtable channel. All 6 agents replied to the same message in the same channel:
The john (openclaw) case required one more fix that's now in This is a defensive fallback that benefits any framework whose adapter doesn't thread channel_id explicitly. The body-supplied Demo task #21 (Tom + John group chat) now exceeded — 6 frameworks active, not just 2. |
Verified end-to-end: Tom (Hermes) participated in the 6-framework roundtable group chat alongside openclaw, smolagents, langroid, pocketflow, and openai-agents-sdk. Per the deploy-flow promotion plan, moving from alpha to beta to surface it in the recommended-frameworks list. Updated description to reflect the actual taos-hermes-bridge wiring that ships in tinyagentos/scripts/install_hermes.sh.
Summary
Phase 1 of the framework-update feature per
docs/superpowers/specs/2026-04-18-framework-update-phase-1-design.md. Adds per-agent manual updates for installed frameworks (openclaw today, generic contract for hermes / smolagents / etc.). Includes a pre-update LXC snapshot with 3-deep retention and a 120s bootstrap-ping deadline. Failure surfaces a red banner with the snapshot name for manual rollback.Scope
In: new Framework tab in Agent Settings (between Memory and Skills), 4 manifest metadata fields (release_source / release_asset_pattern / install_script / service_name), 7 per-agent state fields, hourly GitHub Releases poll, container-side install script baked into the base image, sidebar dot, Store pill.
Out (separate specs): Phase 2 graceful handoff (pause-and-resume note via taosmd), Phase 3 batch updates + auto-rollback, framework swap UI.
What's new
Backend
tinyagentos/frameworks.py— manifest registry + validatortinyagentos/github_releases.py— release fetch + pure parsertinyagentos/framework_update.py— orchestrator (snapshot → install → wait-for-bootstrap → verify)tinyagentos/routes/framework.py— GET /api/agents/{slug}/framework, POST /api/agents/{slug}/framework/update, GET /api/frameworks/latesttinyagentos/scripts/taos-framework-update.sh— container-side installer, baked into base image/api/openclaw/bootstraphandler so the runner can detect when the agent is backauto_update.pypoll block runs hourly alongside the existing taOS self-update tickFrontend
desktop/src/components/agent-settings/FrameworkTab.tsxwith installed/latest rows, Update button, confirmation dialog, live-elapsed Updating banner, failure banner with snapshot namedesktop/src/lib/framework-api.ts— small fetch wrappersTest plan
tests/e2e/test_framework_tab.py+test_framework_store_pill.py— selectors carry TODOs to be tuned against live DOM on first real run/opt/taos/framework.versionupdates (queued post-merge)Notes
docs/superpowers/specs/2026-04-18-framework-update-phase-1-design.md(gitignored per project policy — local only).Summary by CodeRabbit
Release Notes
New Features
Chores