opencode-navigator 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/HOST_API.md +25 -5
- package/LINT_COVERAGE.md +201 -0
- package/PROVIDERS.md +2 -2
- package/README.md +100 -9
- package/dist/chunk-fd7394y1.js +17 -0
- package/dist/chunk-pwa1wzer.js +22 -0
- package/dist/native-todo-setup.js +1156 -0
- package/dist/navigator-updates.js +63 -25
- package/dist/onboarding.js +379 -0
- package/dist/provider-limits.js +14 -7
- package/dist/runtime-dependencies.json +5 -5
- package/dist/server.js +2 -2
- package/dist/sidebar-settings.js +901 -420
- package/dist/toolbar-settings.js +143 -34
- package/dist/tui.js +512 -625
- package/dist/upgrade-notes.js +87 -0
- package/package.json +20 -15
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import {PLUGIN_ID
|
|
2
|
-
} from "./chunk-bv0nm1tj.js"
|
|
2
|
+
} from "./chunk-bv0nm1tj.js"
|
|
3
|
+
import {parseChangelog2,readBundledChangelog2
|
|
4
|
+
} from "./chunk-pwa1wzer.js"
|
|
5
|
+
import {isNewerVersion,isSameMajorVersion
|
|
6
|
+
} from "./chunk-fd7394y1.js";
|
|
3
7
|
import {createSignal} from "solid-js"
|
|
4
|
-
function versionParts(value){const match=/^v?(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/.exec(value)
|
|
5
|
-
return match?{numbers:match.slice(1,4).map(Number),prerelease:match[4]||undefined}:undefined
|
|
6
|
-
}
|
|
7
|
-
function isNewerVersion(latest,current){const next=versionParts(latest)
|
|
8
|
-
const installed=versionParts(current)
|
|
9
|
-
if(!next||!installed)
|
|
10
|
-
return false
|
|
11
|
-
for(let index=0;index<3; index++){if(next.numbers[index]!==installed.numbers[index])
|
|
12
|
-
return next.numbers[index]>installed.numbers[index]
|
|
13
|
-
}
|
|
14
|
-
return installed.prerelease!==undefined&&next.prerelease===undefined
|
|
15
|
-
}
|
|
16
|
-
function isSameMajorVersion(left,right){const first=versionParts(left)
|
|
17
|
-
const second=versionParts(right)
|
|
18
|
-
return Boolean(first&&second&&first.numbers[0]===second.numbers[0])
|
|
19
|
-
}
|
|
20
8
|
var NAVIGATOR_PACKAGE_URL="https://registry.npmjs.org/opencode-navigator/latest"
|
|
21
9
|
var REQUEST_TIMEOUT_MS=5000
|
|
22
10
|
async function readNavigatorVersion(request,signal){const response=await request(NAVIGATOR_PACKAGE_URL,{headers:{accept:"application/json"},signal})
|
|
@@ -29,6 +17,7 @@ return metadata.version
|
|
|
29
17
|
}
|
|
30
18
|
function createVersionStatus(api,navigatorVersion,request=fetch,timeoutMs=REQUEST_TIMEOUT_MS){const [openCodeUpdate,setOpenCodeUpdate]=createSignal()
|
|
31
19
|
const [navigatorUpdate,setNavigatorUpdate]=createSignal()
|
|
20
|
+
const [navigatorCheckState,setNavigatorCheckState]=createSignal({status:"idle"})
|
|
32
21
|
let controller
|
|
33
22
|
let pending
|
|
34
23
|
let disposed=false
|
|
@@ -43,6 +32,7 @@ function refreshNavigator(){if(disposed)
|
|
|
43
32
|
return Promise.resolve("unavailable")
|
|
44
33
|
if(pending)
|
|
45
34
|
return pending
|
|
35
|
+
setNavigatorCheckState((previous)=>({...previous,status:"checking"}))
|
|
46
36
|
const active=new AbortController
|
|
47
37
|
controller=active
|
|
48
38
|
const timeout=setTimeout(()=>active.abort(),timeoutMs)
|
|
@@ -54,8 +44,12 @@ const reading=Promise.race([readNavigatorVersion(request,active.signal),cancelle
|
|
|
54
44
|
return "unavailable"
|
|
55
45
|
const newer=isNewerVersion(version,navigatorVersion)
|
|
56
46
|
setNavigatorUpdate(newer?version:undefined)
|
|
47
|
+
setNavigatorCheckState({status:newer?"available":"current",latest:version,checkedAt:Date.now()})
|
|
57
48
|
return newer?"update":"current"
|
|
58
|
-
}).catch(()=>
|
|
49
|
+
}).catch(()=>{if(!disposed)
|
|
50
|
+
setNavigatorCheckState((previous)=>({...previous,status:"error",checkedAt:Date.now()}))
|
|
51
|
+
return "unavailable"
|
|
52
|
+
}).finally(()=>{clearTimeout(timeout)
|
|
59
53
|
active.signal.removeEventListener("abort",abort)
|
|
60
54
|
if(controller===active)
|
|
61
55
|
controller=undefined
|
|
@@ -66,7 +60,7 @@ pending=reading
|
|
|
66
60
|
return reading
|
|
67
61
|
}
|
|
68
62
|
refreshNavigator()
|
|
69
|
-
return{openCodeUpdate,navigatorUpdate,refreshNavigator}}
|
|
63
|
+
return{openCodeUpdate,navigatorUpdate,refreshNavigator,navigatorCheckState}}
|
|
70
64
|
import {effect as _$effect3} from "@opentui/solid"
|
|
71
65
|
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
72
66
|
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
@@ -88,7 +82,8 @@ import {insert as _$insert} from "@opentui/solid"
|
|
|
88
82
|
import {setProp as _$setProp} from "@opentui/solid"
|
|
89
83
|
import {createElement as _$createElement} from "@opentui/solid"
|
|
90
84
|
import {useIcons} from "./tui.js"
|
|
91
|
-
import {createComponent as _$
|
|
85
|
+
import {createComponent as _$createComponent4} from "@opentui/solid"
|
|
86
|
+
import {createSignal as createSignal2} from "solid-js"
|
|
92
87
|
function createManualUpdateCheck(api,status,current,onUpdate){let checking=false
|
|
93
88
|
async function read(){try{return await status.refreshNavigator?.()??"unavailable"
|
|
94
89
|
} catch{return "unavailable"
|
|
@@ -108,7 +103,28 @@ api.ui.toast({variant:result==="unavailable"?"warning":"info",title:"Navigator u
|
|
|
108
103
|
})
|
|
109
104
|
} finally{checking=false
|
|
110
105
|
}}}}
|
|
106
|
+
import {createComponent as _$createComponent3} from "@opentui/solid"
|
|
107
|
+
import {onCleanup} from "solid-js"
|
|
108
|
+
import {GuardedConfirmation,SelectionMenu} from "./tui.js"
|
|
109
|
+
function NestedVersionConfirmation(props){onCleanup(props.dismiss)
|
|
110
|
+
return _$createComponent3(GuardedConfirmation,{get api(){return props.api
|
|
111
|
+
},get current(){return props.current
|
|
112
|
+
},get title(){return `Update ${props.name}`
|
|
113
|
+
},get message(){return `Install ${props.version} using the current installation method?`
|
|
114
|
+
},get onConfirm(){return props.confirm
|
|
115
|
+
},render:({confirm
|
|
116
|
+
})=>_$createComponent3(SelectionMenu,{get api(){return props.api
|
|
117
|
+
},get title(){return `Update ${props.name}`
|
|
118
|
+
},get options(){return [{title:"Cancel",value:"cancel",description:"Return without installing an update"
|
|
119
|
+
},{title:`Install ${props.name} ${props.version}`,value:"install",description:"Keep the current installation method and scope; restart OpenCode afterward"
|
|
120
|
+
}]
|
|
121
|
+
},onSelect:(option)=>option.value==="install"?confirm():props.cancel()
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
111
125
|
function createVersionUpdateActions(api,status,updater,rememberNavigatorVersion){const busy=new Set
|
|
126
|
+
const [navigatorUpdating,setNavigatorUpdating]=createSignal2(false)
|
|
127
|
+
const [navigatorInstalled,setNavigatorInstalled]=createSignal2()
|
|
112
128
|
const installed={}
|
|
113
129
|
let disposed=false
|
|
114
130
|
let confirmation=0
|
|
@@ -124,6 +140,8 @@ return
|
|
|
124
140
|
}
|
|
125
141
|
api.ui.dialog.clear()
|
|
126
142
|
busy.add(kind)
|
|
143
|
+
if(kind==="navigator")
|
|
144
|
+
setNavigatorUpdating(true)
|
|
127
145
|
api.ui.toast({variant:"info",title:`Updating ${label(kind)}`,message:`Installing ${version}...`
|
|
128
146
|
});
|
|
129
147
|
(async ()=>{if(kind==="navigator")
|
|
@@ -132,6 +150,8 @@ if(disposed||version!==target(kind))
|
|
|
132
150
|
throw new Error("Update target changed; check again")
|
|
133
151
|
await updater[kind](version)
|
|
134
152
|
})().then(()=>{installed[kind]=version
|
|
153
|
+
if(kind==="navigator")
|
|
154
|
+
setNavigatorInstalled(version)
|
|
135
155
|
if(disposed)
|
|
136
156
|
return
|
|
137
157
|
api.ui.toast({variant:"success",title:`${label(kind)} updated`,message:"Restart OpenCode to use the new version.",duration:6000
|
|
@@ -140,16 +160,34 @@ api.ui.toast({variant:"success",title:`${label(kind)} updated`,message:"Restart
|
|
|
140
160
|
return
|
|
141
161
|
api.ui.toast({variant:"error",title:`Could not update ${label(kind)}`,message:error instanceof Error?error.message:"Update failed",duration:6000
|
|
142
162
|
})
|
|
143
|
-
}).finally(()=>busy.delete(kind)
|
|
163
|
+
}).finally(()=>{busy.delete(kind)
|
|
164
|
+
if(kind==="navigator")
|
|
165
|
+
setNavigatorUpdating(false)
|
|
166
|
+
})
|
|
144
167
|
}
|
|
145
|
-
function open(kind,version=target(kind)){if(disposed||!version||version!==target(kind)||busy.has(kind))
|
|
168
|
+
function open(kind,version=target(kind),navigation){if(disposed||!version||version!==target(kind)||busy.has(kind))
|
|
146
169
|
return
|
|
147
170
|
if(installed[kind]===version){api.ui.toast({variant:"info",title:`${label(kind)} updated`,message:"Restart OpenCode to use the installed update."
|
|
148
171
|
})
|
|
149
172
|
return
|
|
150
173
|
}
|
|
151
174
|
const id=++confirmation
|
|
152
|
-
|
|
175
|
+
const onConfirm=()=>{if(id!==confirmation)
|
|
176
|
+
return
|
|
177
|
+
confirmation++
|
|
178
|
+
update(kind,version)
|
|
179
|
+
}
|
|
180
|
+
if(navigation){navigation.open(()=>_$createComponent4(NestedVersionConfirmation,{api,get name(){return label(kind)
|
|
181
|
+
},version,current:()=>!disposed&&id===confirmation&&version===target(kind),confirm:onConfirm,cancel:()=>{if(id!==confirmation)
|
|
182
|
+
return
|
|
183
|
+
confirmation++
|
|
184
|
+
navigation.back()
|
|
185
|
+
},dismiss:()=>{if(id===confirmation)
|
|
186
|
+
confirmation++
|
|
187
|
+
}}))
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
api.ui.dialog.replace(()=>_$createComponent4(api.ui.DialogConfirm,{get title(){return `Update ${label(kind)}`
|
|
153
191
|
},message:`Update to ${version} using the current installation method? OpenCode must be restarted afterward.`,onConfirm:()=>{if(id!==confirmation)
|
|
154
192
|
return
|
|
155
193
|
confirmation++
|
|
@@ -169,7 +207,7 @@ const unregister=api.keymap.registerLayer({commands:[{name:`${PLUGIN_ID}.check-u
|
|
|
169
207
|
api.lifecycle.onDispose(()=>{disposed=true
|
|
170
208
|
unregister()
|
|
171
209
|
})
|
|
172
|
-
return{openCode:(version)=>open("openCode",version),navigator:(version)=>open("navigator",version)
|
|
210
|
+
return{openCode:(version)=>open("openCode",version),navigator:(version,navigation)=>open("navigator",version,navigation),navigatorUpdating,navigatorInstalled
|
|
173
211
|
}}
|
|
174
212
|
import {homedir} from "os"
|
|
175
213
|
import {basename,dirname,isAbsolute,join} from "path"
|
|
@@ -241,5 +279,5 @@ if(item.source.target.startsWith("."))
|
|
|
241
279
|
throw new Error("Unrecognized local Navigator source")
|
|
242
280
|
await context.client.plugin.update({location:response.location,targets:[item.source.target]})
|
|
243
281
|
}}}
|
|
244
|
-
export{createOpenCodeV1VersionUpdater,createOpenCodeV2VersionUpdater,createVersionStatus,createVersionUpdateActions
|
|
282
|
+
export{createOpenCodeV1VersionUpdater,createOpenCodeV2VersionUpdater,createVersionStatus,createVersionUpdateActions,parseChangelog2 as parseChangelog,readBundledChangelog2 as readBundledChangelog
|
|
245
283
|
}
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import {SECTION_DEFINITIONS,PLUGIN_ID
|
|
2
|
+
} from "./chunk-bv0nm1tj.js"
|
|
3
|
+
import"./chunk-qmntexwm.js";
|
|
4
|
+
import {createComponent as _$createComponent3} from "@opentui/solid"
|
|
5
|
+
import {effect as _$effect4} from "@opentui/solid"
|
|
6
|
+
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
7
|
+
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
8
|
+
import {insert as _$insert4} from "@opentui/solid"
|
|
9
|
+
import {setProp as _$setProp4} from "@opentui/solid"
|
|
10
|
+
import {createElement as _$createElement4} from "@opentui/solid"
|
|
11
|
+
import {TextAttributes as TextAttributes3} from "@opentui/core"
|
|
12
|
+
import {Show,createSignal as createSignal2,onCleanup as onCleanup3} from "solid-js"
|
|
13
|
+
import {supportsSidebarSection as supportsSidebarSection2} from "./tui.js"
|
|
14
|
+
import {DialogSurface,useDialogs,useIcons as useIcons3} from "./tui.js"
|
|
15
|
+
import {hostCapabilities} from "./tui.js"
|
|
16
|
+
var ONBOARDING_STEPS=[{title:"A control center that stays compact",summary:"Navigator brings session state, search, and controls into OpenCode's existing sidebar.",icon:"help",features:[{icon:"sections",title:"Progressive disclosure",description:"Expand only the context you need right now."},{icon:"scope",title:"Current context",description:"Follow the active session, workspace, and worktree."},{icon:"actions",title:"Mouse and keyboard",description:"Use the same controls with either input method."}]
|
|
17
|
+
},{title:"Stay oriented while agents work",summary:"Keep current work visible without turning the sidebar into another dashboard.",icon:"todo",features:[{icon:"todo",title:"Todo filters",description:"Track active, finished, and cancelled tasks. Edit through chat and the built-in Todo tool."
|
|
18
|
+
},{icon:"subagents",title:"Live subagents",description:"See running, retrying, recent, and failed child sessions; open them directly."
|
|
19
|
+
},{icon:"info",title:"Provider limits",description:"Follow the selected provider and account allowance. Codex linking and banked resets require confirmation."
|
|
20
|
+
}]
|
|
21
|
+
},{title:"Find anything and launch Skills safely",summary:"Search complete source lists without expanding every sidebar section.",icon:"search",features:[{icon:"search",title:"Search Everything",description:"Search Skills, Subagents, MCP, and Actions in shared tabs."
|
|
22
|
+
},{icon:"search",title:"Full source lists",description:"Search beyond sidebar visibility and item limits."},{icon:"skills",title:"Skill confirmation",description:"Review a skill and its source before inserting its command."
|
|
23
|
+
}]
|
|
24
|
+
},{title:"Run actions and check language tools",summary:"Keep frequent commands and private toolbar shortcuts nearby; show only host-supported language-server status.",icon:"actions",features:[{icon:"actions",title:"Quick Actions",description:"Choose visibility and order for rename, timeline, copy, export, compaction and other available commands."
|
|
25
|
+
},{icon:"lsp",title:"Compact LSP status",description:"Spot connected and failed language servers at a glance."
|
|
26
|
+
},{icon:"settings",title:"Private pinned toolbar",description:"Pin Actions or Skills separately from favorites: zero to three icons, optional text, observed-state icons, More or wrapping."
|
|
27
|
+
},{icon:"settings",title:"Session permissions",description:"Toggle auto-approve with the supported OpenCode 1.x command."
|
|
28
|
+
}]
|
|
29
|
+
},{title:"Control MCP without losing context",summary:"Manage individual servers or entire working sets directly from Navigator.",icon:"mcp",features:[{icon:"mcp",title:"Live server controls",description:"Connect, disconnect, filter, and favorite servers."},{icon:"actions",title:"Bulk operations",description:"Activate a group heading to connect or disconnect its full eligible bucket; retry failures in place."
|
|
30
|
+
},{icon:"presets",title:"Safe presets",description:"Preview connections and disconnections before Apply."}]
|
|
31
|
+
},{title:"Make Navigator fit each workspace",summary:"Use the same controls with mouse or keyboard and keep only the context you need.",icon:"settings",features:[{icon:"sections",title:"Flexible layout",description:"Choose section visibility, order, expansion, and item limits."
|
|
32
|
+
},{icon:"presets",title:"Scoped presets",description:"Preview layouts globally or for a worktree. Reload private preferences across running sessions."
|
|
33
|
+
},{icon:"settings",title:"About and changelog",description:"Check versions and updates, reopen notes by version, and prepare an editable Bug report for gh or your browser."
|
|
34
|
+
},{icon:"info",title:"Readable controls",description:"Use Nerd Font icons with the corner font, disable multiline masks, or choose Text fallback. Open Settings with Ctrl+,."
|
|
35
|
+
}]
|
|
36
|
+
}]
|
|
37
|
+
function onboardingSteps(api){const capabilities=hostCapabilities(api)
|
|
38
|
+
return ONBOARDING_STEPS.map((step,index)=>{if(index===1&&capabilities.nativeTodo)
|
|
39
|
+
return{...step,features:[{icon:"todo",title:"Todo filters and enablement",description:"If native Todo is off, use Enable Todo and confirm its server-config change. Edit tasks through chat and todowrite."
|
|
40
|
+
},...step.features.slice(1)]
|
|
41
|
+
}
|
|
42
|
+
if(index===3)
|
|
43
|
+
return{...step,features:step.features.map((feature)=>{if(feature.icon==="lsp"&&!capabilities.lsp)
|
|
44
|
+
return{...feature,title:"Language tools on this host",description:"OpenCode 2.x does not expose LSP status or actions. Use project lint and compiler commands instead."
|
|
45
|
+
}
|
|
46
|
+
if(feature.title==="Session permissions"&&capabilities.permissionMode===false)
|
|
47
|
+
return{...feature,description:"The Permissions action opens host Settings; choose Session \u2192 Permissions there."
|
|
48
|
+
}
|
|
49
|
+
return feature
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
return step
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
import {effect as _$effect2} from "@opentui/solid"
|
|
56
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
57
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
58
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
59
|
+
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
60
|
+
import {insert as _$insert2} from "@opentui/solid"
|
|
61
|
+
import {setProp as _$setProp2} from "@opentui/solid"
|
|
62
|
+
import {createElement as _$createElement2} from "@opentui/solid"
|
|
63
|
+
import {TextAttributes} from "@opentui/core"
|
|
64
|
+
import {For} from "solid-js"
|
|
65
|
+
import {SelectionBox,useIcons} from "./tui.js"
|
|
66
|
+
import {useRenderer} from "@opentui/solid"
|
|
67
|
+
import {createSignal,onCleanup} from "solid-js"
|
|
68
|
+
function useWizardHeight(api){const renderer=api.renderer??useRenderer()
|
|
69
|
+
const [height,setHeight]=createSignal(renderer.height)
|
|
70
|
+
const resize=()=>setHeight(renderer.height)
|
|
71
|
+
renderer.on("resize",resize)
|
|
72
|
+
onCleanup(()=>renderer.off("resize",resize))
|
|
73
|
+
return height
|
|
74
|
+
}
|
|
75
|
+
import {effect as _$effect} from "@opentui/solid"
|
|
76
|
+
import {insert as _$insert} from "@opentui/solid"
|
|
77
|
+
import {use as _$use} from "@opentui/solid"
|
|
78
|
+
import {setProp as _$setProp} from "@opentui/solid"
|
|
79
|
+
import {createElement as _$createElement} from "@opentui/solid"
|
|
80
|
+
import {useRenderer as useRenderer2} from "@opentui/solid"
|
|
81
|
+
import {createEffect,onCleanup as onCleanup2} from "solid-js"
|
|
82
|
+
function WizardScrollBody(props){const renderer=useRenderer2()
|
|
83
|
+
let body
|
|
84
|
+
let pending=true
|
|
85
|
+
createEffect(()=>{pending=props.active!==undefined||props.resetKey!==undefined
|
|
86
|
+
})
|
|
87
|
+
const reveal=()=>{if(!pending||!body||body.isDestroyed||body.scrollHeight===0)
|
|
88
|
+
return
|
|
89
|
+
pending=false
|
|
90
|
+
if(props.active)
|
|
91
|
+
body.scrollChildIntoView(props.active)
|
|
92
|
+
else if(props.resetKey)
|
|
93
|
+
body.scrollTo(0)
|
|
94
|
+
}
|
|
95
|
+
renderer.on("frame",reveal)
|
|
96
|
+
const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1001,commands:[{name:"opencode-navigator.wizard.body.up",run:()=>body?.scrollBy(-Math.max(1,props.height-1))
|
|
97
|
+
},{name:"opencode-navigator.wizard.body.down",run:()=>body?.scrollBy(Math.max(1,props.height-1))
|
|
98
|
+
}],bindings:[{key:"pageup",cmd:"opencode-navigator.wizard.body.up"
|
|
99
|
+
},{key:"pagedown",cmd:"opencode-navigator.wizard.body.down"
|
|
100
|
+
}]
|
|
101
|
+
})
|
|
102
|
+
onCleanup2(()=>{unregister()
|
|
103
|
+
renderer.off("frame",reveal)
|
|
104
|
+
})
|
|
105
|
+
return(()=>{var _el$=_$createElement("scrollbox")
|
|
106
|
+
_$use((node)=>{body=node
|
|
107
|
+
},_el$)
|
|
108
|
+
_$setProp(_el$,"id","opencode-navigator.wizard.body")
|
|
109
|
+
_$setProp(_el$,"flexShrink",0)
|
|
110
|
+
_$setProp(_el$,"scrollX",false)
|
|
111
|
+
_$setProp(_el$,"horizontalScrollbarOptions",{visible:false
|
|
112
|
+
})
|
|
113
|
+
_$insert(_el$,()=>props.children)
|
|
114
|
+
_$effect((_$p)=>_$setProp(_el$,"height",props.height,_$p))
|
|
115
|
+
return _el$
|
|
116
|
+
})()
|
|
117
|
+
}
|
|
118
|
+
function OnboardingStep(props){const icons=useIcons()
|
|
119
|
+
const theme=()=>props.api.theme.current
|
|
120
|
+
const height=useWizardHeight(props.api)
|
|
121
|
+
return(()=>{var _el$=_$createElement2("box"),_el$1=_$createElement2("box")
|
|
122
|
+
_$insertNode(_el$,_el$1)
|
|
123
|
+
_$setProp2(_el$,"gap",1)
|
|
124
|
+
_$insert2(_el$,_$createComponent(WizardScrollBody,{get api(){return props.api
|
|
125
|
+
},get height(){return Math.min(16,Math.max(3,height()-11))
|
|
126
|
+
},get resetKey(){return props.step.title
|
|
127
|
+
},get children(){var _el$2=_$createElement2("box"),_el$3=_$createElement2("text"),_el$4=_$createTextNode(` `),_el$5=_$createElement2("text"),_el$6=_$createElement2("box"),_el$7=_$createElement2("text"),_el$8=_$createTextNode(`Navigator: `),_el$9=_$createTextNode(` \xB7 Focus: `),_el$0=_$createTextNode(` \xB7 Settings: Ctrl+, \xB7 Icons: `)
|
|
128
|
+
_$insertNode(_el$2,_el$3)
|
|
129
|
+
_$insertNode(_el$2,_el$5)
|
|
130
|
+
_$insertNode(_el$2,_el$6)
|
|
131
|
+
_$insertNode(_el$2,_el$7)
|
|
132
|
+
_$setProp2(_el$2,"gap",1)
|
|
133
|
+
_$insertNode(_el$3,_el$4)
|
|
134
|
+
_$insert2(_el$3,()=>icons.icon(props.step.icon),_el$4)
|
|
135
|
+
_$insert2(_el$3,()=>props.step.title,null)
|
|
136
|
+
_$setProp2(_el$5,"wrapMode","word")
|
|
137
|
+
_$insert2(_el$5,()=>props.step.summary)
|
|
138
|
+
_$setProp2(_el$6,"border",["top","bottom"])
|
|
139
|
+
_$setProp2(_el$6,"paddingTop",1)
|
|
140
|
+
_$setProp2(_el$6,"paddingBottom",1)
|
|
141
|
+
_$setProp2(_el$6,"gap",1)
|
|
142
|
+
_$insert2(_el$6,_$createComponent(For,{get each(){return props.step.features
|
|
143
|
+
},children:(feature)=>(()=>{var _el$14=_$createElement2("box"),_el$15=_$createElement2("text"),_el$16=_$createElement2("text"),_el$17=_$createElement2("b"),_el$18=_$createTextNode(` \xB7 `)
|
|
144
|
+
_$insertNode(_el$14,_el$15)
|
|
145
|
+
_$insertNode(_el$14,_el$16)
|
|
146
|
+
_$setProp2(_el$14,"flexDirection","row")
|
|
147
|
+
_$setProp2(_el$14,"gap",1)
|
|
148
|
+
_$setProp2(_el$15,"flexShrink",0)
|
|
149
|
+
_$insert2(_el$15,()=>icons.icon(feature.icon))
|
|
150
|
+
_$insertNode(_el$16,_el$17)
|
|
151
|
+
_$insertNode(_el$16,_el$18)
|
|
152
|
+
_$setProp2(_el$16,"flexGrow",1)
|
|
153
|
+
_$setProp2(_el$16,"minWidth",0)
|
|
154
|
+
_$setProp2(_el$16,"wrapMode","word")
|
|
155
|
+
_$insert2(_el$17,()=>feature.title)
|
|
156
|
+
_$insert2(_el$16,()=>feature.description,null)
|
|
157
|
+
_$effect2((_p$)=>{var _v$6=theme().accent,_v$7=theme().textMuted
|
|
158
|
+
_v$6!==_p$.e&&(_p$.e=_$setProp2(_el$15,"fg",_v$6,_p$.e))
|
|
159
|
+
_v$7!==_p$.t&&(_p$.t=_$setProp2(_el$16,"fg",_v$7,_p$.t))
|
|
160
|
+
return _p$
|
|
161
|
+
},{e:undefined,t:undefined
|
|
162
|
+
})
|
|
163
|
+
return _el$14
|
|
164
|
+
})()
|
|
165
|
+
}))
|
|
166
|
+
_$insertNode(_el$7,_el$8)
|
|
167
|
+
_$insertNode(_el$7,_el$9)
|
|
168
|
+
_$insertNode(_el$7,_el$0)
|
|
169
|
+
_$setProp2(_el$7,"wrapMode","word")
|
|
170
|
+
_$insert2(_el$7,()=>props.preferences.toggleKey(),_el$9)
|
|
171
|
+
_$insert2(_el$7,()=>props.preferences.focusKey(),_el$0)
|
|
172
|
+
_$insert2(_el$7,()=>icons.style()==="text"?"Text fallback":"Nerd Font",null)
|
|
173
|
+
_$effect2((_p$)=>{var _v$=theme().accent,_v$2=TextAttributes.BOLD,_v$3=theme().textMuted,_v$4=theme().borderSubtle,_v$5=theme().textMuted
|
|
174
|
+
_v$!==_p$.e&&(_p$.e=_$setProp2(_el$3,"fg",_v$,_p$.e))
|
|
175
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp2(_el$3,"attributes",_v$2,_p$.t))
|
|
176
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp2(_el$5,"fg",_v$3,_p$.a))
|
|
177
|
+
_v$4!==_p$.o&&(_p$.o=_$setProp2(_el$6,"borderColor",_v$4,_p$.o))
|
|
178
|
+
_v$5!==_p$.i&&(_p$.i=_$setProp2(_el$7,"fg",_v$5,_p$.i))
|
|
179
|
+
return _p$
|
|
180
|
+
},{e:undefined,t:undefined,a:undefined,o:undefined,i:undefined
|
|
181
|
+
})
|
|
182
|
+
return _el$2
|
|
183
|
+
}}),_el$1)
|
|
184
|
+
_$setProp2(_el$1,"flexDirection","row")
|
|
185
|
+
_$setProp2(_el$1,"justifyContent","space-between")
|
|
186
|
+
_$insert2(_el$1,_$createComponent(SelectionBox,{id:"opencode-navigator.wizard.back",paddingLeft:1,paddingRight:1,onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
187
|
+
props.onBack()
|
|
188
|
+
},get children(){var _el$10=_$createElement2("text"),_el$11=_$createTextNode(` Back`)
|
|
189
|
+
_$insertNode(_el$10,_el$11)
|
|
190
|
+
_$insert2(_el$10,()=>icons.icon("left"),_el$11)
|
|
191
|
+
_$effect2((_$p)=>_$setProp2(_el$10,"fg",theme().textMuted,_$p))
|
|
192
|
+
return _el$10
|
|
193
|
+
}}),null)
|
|
194
|
+
_$insert2(_el$1,_$createComponent(SelectionBox,{id:"opencode-navigator.wizard.next",paddingLeft:1,paddingRight:1,get backgroundColor(){return theme().primary
|
|
195
|
+
},onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
196
|
+
props.onAdvance()
|
|
197
|
+
},get children(){var _el$12=_$createElement2("text"),_el$13=_$createTextNode(` `)
|
|
198
|
+
_$insertNode(_el$12,_el$13)
|
|
199
|
+
_$insert2(_el$12,()=>props.final?"Configure sidebar":"Next",_el$13)
|
|
200
|
+
_$insert2(_el$12,()=>icons.icon("right"),null)
|
|
201
|
+
_$effect2((_$p)=>_$setProp2(_el$12,"fg",theme().selectedListItemText,_$p))
|
|
202
|
+
return _el$12
|
|
203
|
+
}}),null)
|
|
204
|
+
return _el$
|
|
205
|
+
})()
|
|
206
|
+
}
|
|
207
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
208
|
+
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
209
|
+
import {memo as _$memo2} from "@opentui/solid"
|
|
210
|
+
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
211
|
+
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
212
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
213
|
+
import {setProp as _$setProp3} from "@opentui/solid"
|
|
214
|
+
import {createElement as _$createElement3} from "@opentui/solid"
|
|
215
|
+
import {TextAttributes as TextAttributes2} from "@opentui/core"
|
|
216
|
+
import {For as For2} from "solid-js"
|
|
217
|
+
import {supportsSidebarSection} from "./tui.js"
|
|
218
|
+
import {SelectionBox as SelectionBox2,useIcons as useIcons2} from "./tui.js"
|
|
219
|
+
function SectionConfig(props){const icons=useIcons2()
|
|
220
|
+
const theme=()=>props.api.theme.current
|
|
221
|
+
const sections=SECTION_DEFINITIONS.filter((section)=>supportsSidebarSection(props.api,section.name))
|
|
222
|
+
const finishIndex=sections.length
|
|
223
|
+
const height=useWizardHeight(props.api)
|
|
224
|
+
return(()=>{var _el$=_$createElement3("box"),_el$2=_$createElement3("text"),_el$3=_$createTextNode2(` Choose your sidebar sections`),_el$4=_$createElement3("text"),_el$7=_$createElement3("box")
|
|
225
|
+
_$insertNode2(_el$,_el$2)
|
|
226
|
+
_$insertNode2(_el$,_el$4)
|
|
227
|
+
_$insertNode2(_el$,_el$7)
|
|
228
|
+
_$setProp3(_el$,"gap",1)
|
|
229
|
+
_$insertNode2(_el$2,_el$3)
|
|
230
|
+
_$setProp3(_el$2,"flexShrink",0)
|
|
231
|
+
_$insert3(_el$2,()=>icons.icon("sections"),_el$3)
|
|
232
|
+
_$insertNode2(_el$4,_$createTextNode2(`Select what appears now. You can change visibility, order, limits, scope, and presets later with the gear button.`))
|
|
233
|
+
_$setProp3(_el$4,"wrapMode","word")
|
|
234
|
+
_$setProp3(_el$4,"flexShrink",0)
|
|
235
|
+
_$insert3(_el$,_$createComponent2(WizardScrollBody,{get api(){return props.api
|
|
236
|
+
},get height(){return Math.min(sections.length*2-1,Math.max(3,height()-15))
|
|
237
|
+
},get active(){return _$memo2(()=>props.active<sections.length)()?`opencode-navigator.wizard.section.${props.active}`:undefined
|
|
238
|
+
},get children(){var _el$6=_$createElement3("box")
|
|
239
|
+
_$setProp3(_el$6,"gap",1)
|
|
240
|
+
_$insert3(_el$6,_$createComponent2(For2,{each:sections,children:(section,index)=>_$createComponent2(SelectionBox2,{get id(){return `opencode-navigator.wizard.section.${index()}`
|
|
241
|
+
},height:1,flexShrink:0,flexDirection:"row",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return _$memo2(()=>props.active===index())()?theme().backgroundElement:undefined
|
|
242
|
+
},onMouseOver:()=>props.onActive(index()),onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
243
|
+
props.preferences.toggleSection(section.name)
|
|
244
|
+
},get children(){return [(()=>{var _el$10=_$createElement3("text")
|
|
245
|
+
_$setProp3(_el$10,"flexShrink",0)
|
|
246
|
+
_$insert3(_el$10,()=>icons.icon(props.preferences.sections()[section.name]?"checked":"unchecked"))
|
|
247
|
+
_$effect3((_$p)=>_$setProp3(_el$10,"fg",props.preferences.sections()[section.name]?theme().accent:theme().textMuted,_$p))
|
|
248
|
+
return _el$10
|
|
249
|
+
})(),(()=>{var _el$11=_$createElement3("text"),_el$12=_$createTextNode2(` `)
|
|
250
|
+
_$insertNode2(_el$11,_el$12)
|
|
251
|
+
_$insert3(_el$11,()=>icons.section(section.name),_el$12)
|
|
252
|
+
_$insert3(_el$11,()=>section.label,null)
|
|
253
|
+
_$effect3((_$p)=>_$setProp3(_el$11,"fg",props.active===index()?theme().text:theme().textMuted,_$p))
|
|
254
|
+
return _el$11
|
|
255
|
+
})()]
|
|
256
|
+
}})
|
|
257
|
+
}))
|
|
258
|
+
return _el$6
|
|
259
|
+
}}),_el$7)
|
|
260
|
+
_$setProp3(_el$7,"flexDirection","row")
|
|
261
|
+
_$setProp3(_el$7,"justifyContent","space-between")
|
|
262
|
+
_$setProp3(_el$7,"flexShrink",0)
|
|
263
|
+
_$insert3(_el$7,_$createComponent2(SelectionBox2,{id:"opencode-navigator.wizard.back",paddingLeft:1,paddingRight:1,onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
264
|
+
props.onBack()
|
|
265
|
+
},get children(){var _el$8=_$createElement3("text"),_el$9=_$createTextNode2(` Back`)
|
|
266
|
+
_$insertNode2(_el$8,_el$9)
|
|
267
|
+
_$insert3(_el$8,()=>icons.icon("left"),_el$9)
|
|
268
|
+
_$effect3((_$p)=>_$setProp3(_el$8,"fg",theme().textMuted,_$p))
|
|
269
|
+
return _el$8
|
|
270
|
+
}}),null)
|
|
271
|
+
_$insert3(_el$7,_$createComponent2(SelectionBox2,{id:"opencode-navigator.wizard.finish",paddingLeft:2,paddingRight:2,get backgroundColor(){return _$memo2(()=>props.active===finishIndex)()?theme().primary:undefined
|
|
272
|
+
},onMouseOver:()=>props.onActive(finishIndex),onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
273
|
+
props.onFinish()
|
|
274
|
+
},get children(){var _el$0=_$createElement3("text"),_el$1=_$createTextNode2(` Finish`)
|
|
275
|
+
_$insertNode2(_el$0,_el$1)
|
|
276
|
+
_$insert3(_el$0,()=>icons.icon("done"),_el$1)
|
|
277
|
+
_$effect3((_$p)=>_$setProp3(_el$0,"fg",props.active===finishIndex?theme().selectedListItemText:theme().textMuted,_$p))
|
|
278
|
+
return _el$0
|
|
279
|
+
}}),null)
|
|
280
|
+
_$effect3((_p$)=>{var _v$=theme().accent,_v$2=TextAttributes2.BOLD,_v$3=theme().textMuted
|
|
281
|
+
_v$!==_p$.e&&(_p$.e=_$setProp3(_el$2,"fg",_v$,_p$.e))
|
|
282
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp3(_el$2,"attributes",_v$2,_p$.t))
|
|
283
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp3(_el$4,"fg",_v$3,_p$.a))
|
|
284
|
+
return _p$
|
|
285
|
+
},{e:undefined,t:undefined,a:undefined
|
|
286
|
+
})
|
|
287
|
+
return _el$
|
|
288
|
+
})()
|
|
289
|
+
}
|
|
290
|
+
function FirstRunWizard(props){const icons=useIcons3()
|
|
291
|
+
const dialogs=useDialogs(props.api)
|
|
292
|
+
const [active,setActive]=createSignal2(0)
|
|
293
|
+
const [step,setStep]=createSignal2(0)
|
|
294
|
+
const theme=()=>props.api.theme.current
|
|
295
|
+
const sections=SECTION_DEFINITIONS.filter((section)=>supportsSidebarSection2(props.api,section.name))
|
|
296
|
+
const steps=onboardingSteps(props.api)
|
|
297
|
+
const finishIndex=sections.length
|
|
298
|
+
const stepCount=steps.length + 1
|
|
299
|
+
const configuring=()=>step()===steps.length
|
|
300
|
+
function finish(){dialogs.back()
|
|
301
|
+
}
|
|
302
|
+
function move(offset){if(configuring())
|
|
303
|
+
setActive((value)=>(value + offset + finishIndex + 1)%(finishIndex + 1))
|
|
304
|
+
else
|
|
305
|
+
setStep((value)=>Math.max(0,Math.min(steps.length,value + offset)))
|
|
306
|
+
}
|
|
307
|
+
function back(){setStep((value)=>Math.max(0,value-1))
|
|
308
|
+
}
|
|
309
|
+
function advance(){if(!configuring())
|
|
310
|
+
setStep((value)=>Math.min(steps.length,value + 1))
|
|
311
|
+
}
|
|
312
|
+
function select(){if(!configuring()){advance()
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
const index=active()
|
|
316
|
+
if(index===finishIndex)
|
|
317
|
+
finish()
|
|
318
|
+
else
|
|
319
|
+
props.preferences.toggleSection(sections[index].name)
|
|
320
|
+
}
|
|
321
|
+
const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,commands:[{name:`${PLUGIN_ID}.wizard.previous`,run(){move(-1)
|
|
322
|
+
}},{name:`${PLUGIN_ID}.wizard.next`,run(){move(1)
|
|
323
|
+
}},{name:`${PLUGIN_ID}.wizard.select`,run:select
|
|
324
|
+
},{name:`${PLUGIN_ID}.wizard.back`,run:back
|
|
325
|
+
},{name:`${PLUGIN_ID}.wizard.forward`,run:advance
|
|
326
|
+
}],bindings:[{key:"up",cmd:`${PLUGIN_ID}.wizard.previous`
|
|
327
|
+
},{key:"down",cmd:`${PLUGIN_ID}.wizard.next`
|
|
328
|
+
},{key:"tab",cmd:`${PLUGIN_ID}.wizard.next`
|
|
329
|
+
},{key:"left",cmd:`${PLUGIN_ID}.wizard.back`
|
|
330
|
+
},{key:"right",cmd:`${PLUGIN_ID}.wizard.forward`
|
|
331
|
+
},{key:"space",cmd:`${PLUGIN_ID}.wizard.select`
|
|
332
|
+
},{key:"return",cmd:`${PLUGIN_ID}.wizard.select`
|
|
333
|
+
}]
|
|
334
|
+
})
|
|
335
|
+
onCleanup3(unregister)
|
|
336
|
+
return _$createComponent3(DialogSurface,{get api(){return props.api
|
|
337
|
+
},lift:true,get children(){return [(()=>{var _el$=_$createElement4("box"),_el$2=_$createElement4("text"),_el$3=_$createTextNode3(` Navigator setup`),_el$4=_$createElement4("text"),_el$5=_$createTextNode3(`Step `),_el$6=_$createTextNode3(`/`),_el$7=_$createTextNode3(` \xB7 `)
|
|
338
|
+
_$insertNode3(_el$,_el$2)
|
|
339
|
+
_$insertNode3(_el$,_el$4)
|
|
340
|
+
_$setProp4(_el$,"id","opencode-navigator.wizard.header")
|
|
341
|
+
_$setProp4(_el$,"flexDirection","row")
|
|
342
|
+
_$setProp4(_el$,"justifyContent","space-between")
|
|
343
|
+
_$insertNode3(_el$2,_el$3)
|
|
344
|
+
_$insert4(_el$2,()=>icons.icon("help"),_el$3)
|
|
345
|
+
_$insertNode3(_el$4,_el$5)
|
|
346
|
+
_$insertNode3(_el$4,_el$6)
|
|
347
|
+
_$insertNode3(_el$4,_el$7)
|
|
348
|
+
_$setProp4(_el$4,"onMouseDown",(event)=>event.stopPropagation())
|
|
349
|
+
_$setProp4(_el$4,"onMouseUp",(event)=>{event.stopPropagation()
|
|
350
|
+
finish()
|
|
351
|
+
})
|
|
352
|
+
_$insert4(_el$4,()=>step() + 1,_el$6)
|
|
353
|
+
_$insert4(_el$4,stepCount,_el$7)
|
|
354
|
+
_$insert4(_el$4,()=>icons.key("esc"),null)
|
|
355
|
+
_$effect4((_p$)=>{var _v$=TextAttributes3.BOLD,_v$2=theme().text,_v$3=theme().textMuted
|
|
356
|
+
_v$!==_p$.e&&(_p$.e=_$setProp4(_el$2,"attributes",_v$,_p$.e))
|
|
357
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp4(_el$2,"fg",_v$2,_p$.t))
|
|
358
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp4(_el$4,"fg",_v$3,_p$.a))
|
|
359
|
+
return _p$
|
|
360
|
+
},{e:undefined,t:undefined,a:undefined
|
|
361
|
+
})
|
|
362
|
+
return _el$
|
|
363
|
+
})(),_$createComponent3(Show,{get when(){return configuring()
|
|
364
|
+
},get fallback(){return _$createComponent3(OnboardingStep,{get api(){return props.api
|
|
365
|
+
},get preferences(){return props.preferences
|
|
366
|
+
},get step(){return steps[step()]
|
|
367
|
+
},get final(){return step()===steps.length-1
|
|
368
|
+
},onBack:back,onAdvance:advance
|
|
369
|
+
})
|
|
370
|
+
},get children(){return _$createComponent3(SectionConfig,{get api(){return props.api
|
|
371
|
+
},get preferences(){return props.preferences
|
|
372
|
+
},get active(){return active()
|
|
373
|
+
},onActive:setActive,onBack:back,onFinish:finish
|
|
374
|
+
})
|
|
375
|
+
}})]
|
|
376
|
+
}})
|
|
377
|
+
}
|
|
378
|
+
export{FirstRunWizard
|
|
379
|
+
}
|
package/dist/provider-limits.js
CHANGED
|
@@ -589,10 +589,10 @@ _$setProp3(_el$,"width","100%")
|
|
|
589
589
|
_$setProp3(_el$,"minWidth",0)
|
|
590
590
|
_$setProp3(_el$,"gap",1)
|
|
591
591
|
_$setProp3(_el$,"overflow","hidden")
|
|
592
|
-
_$insert3(_el$,_$createComponent4(For,{get each(){return props.windows
|
|
593
|
-
},children:(
|
|
594
|
-
},window
|
|
595
|
-
})
|
|
592
|
+
_$insert3(_el$,_$createComponent4(For,{get each(){return props.windows.map((window)=>window.id)
|
|
593
|
+
},children:(_,index)=>_$createComponent4(QuotaWindowRow,{get api(){return props.api
|
|
594
|
+
},get window(){return props.windows[index()]
|
|
595
|
+
}})
|
|
596
596
|
}))
|
|
597
597
|
return _el$
|
|
598
598
|
})()
|
|
@@ -644,7 +644,7 @@ listeners.clear()
|
|
|
644
644
|
return{adapter,onUpdated(listener){listeners.add(listener)
|
|
645
645
|
return()=>listeners.delete(listener)
|
|
646
646
|
}}}
|
|
647
|
-
var rows=[["openai","OpenAI / Codex",["subscription","api-rate-limits"],"Verified Codex account quota shared across models; HTTP response request/token limits for API connections.","https://developers.openai.com/api/docs/guides/rate-limits"],["anthropic","Anthropic / Claude",["api-rate-limits","configured-limits"],"Model HTTP headers; eligible organization/admin credentials can read configured model limits. Claude subscription windows are separate.","https://platform.claude.com/docs/en/manage-claude/rate-limits-api"],["openrouter","OpenRouter",["key-budget","account-balance"],"Inference-key budget; account credits require a management key. Free-model request limits apply only to free variants.","https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key"],["deepseek","DeepSeek",["account-balance"],"Provider-reported USD/CNY available, granted and topped-up balances.","https://api-docs.deepseek.com/api/get-user-balance"],["moonshotai","Moonshot / Kimi API",["account-balance"],"International USD balances; coding subscriptions are a different product.","https://platform.moonshot.ai/docs/api/balance"],["moonshotai-cn","Moonshot / Kimi API China",["account-balance"],"China CNY balances; never reuse an international key against the China endpoint.","https://platform.moonshot.cn/docs/api/balance"],["minimax","MiniMax",["subscription","account-balance"],"Token Plan model rows/explicit percentages; official SDK balance response for pay-as-you-go keys.","https://platform.minimax.io/docs/token-plan/faq"],["minimax-cn","MiniMax China",["subscription","account-balance"],"Region-specific native Token Plan and SDK balance endpoints.","https://github.com/MiniMax-AI/cli/tree/main/src/sdk/quota"],["github-copilot","GitHub Copilot",["subscription"],"Official SDK token-scoped quota/model RPC; no direct copilot_internal calls or ambient CLI login.","https://github.com/github/copilot-sdk/blob/main/docs/features/usage-and-billing.md"],["groq","Groq",["api-rate-limits"],"Native model response headers: requests per day and tokens per minute.","https://console.groq.com/docs/rate-limits"],["fireworks-ai","Fireworks",["configured-limits","api-rate-limits"],"Native model token/second capacities and account monthly spend quota; GPU quotas are excluded.","https://docs.fireworks.ai/serverless/rate-limits"],["siliconflow","SiliconFlow",["account-balance"],"Native current-user balances; retain unknown currency when the API does not report it.","https://docs.siliconflow.com/en/api-reference/userinfo/get-user-info"],["siliconflow-cn","SiliconFlow China",["account-balance"],"Region-specific current-user balances; currency is unknown when the API omits it.","https://docs.siliconflow.cn/"],["novita-ai","Novita",["account-balance"],"Native current-user balances in 1/10000 USD.","https://novita.ai/docs/api-reference/basic-get-user-balance"],["poe","Poe",["account-balance"],"API account point balance; includes plan and add-on points, not session token usage.","https://creator.poe.com/docs/resources/usage-api"],["nano-gpt","NanoGPT",["account-balance","subscription"],"Native USD/Nano balance and documented subscription token windows; null/degraded counters remain unknown.","https://docs.nano-gpt.com/api-reference/endpoint/subscription-usage"],["aihubmix","AIHubMix",["account-balance"],"Current-account balance API needs a Manage Key; inference keys do not grant management access.","https://docs.aihubmix.com/en/api/CliEndpoints/get-self"],["azure","Azure OpenAI",["api-rate-limits"],"Remaining request/token headers for the actual deployment; no ChatGPT subscription or inferred cloud balance.","https://learn.microsoft.com/en-us/azure/ai-foundry/openai/quotas-limits"],["cerebras","Cerebras",["api-rate-limits"],"Only self-describing native counters actually returned for the selected model; console tier examples are not live quota.","https://inference-docs.cerebras.ai/support/rate-limits"],["mistral","Mistral",[],"Documented remaining header lacks a verified unit/window association; no inferred subscription balance.","https://docs.mistral.ai/resources/known-limitations"],["togetherai","Together AI",[],"Dynamic model limits expose retry intervals, not remaining quota; billing UI does not establish a remaining-credit API.","https://docs.together.ai/docs/rate-limits"],["xai","xAI / Grok",[],"Management billing needs separate team credentials; no verified portable remaining API for this inference connection.","https://docs.x.ai/"],["perplexity","Perplexity",[],"No verified remaining-credit API for an inference key. API credits, consumer subscriptions and Computer credits are distinct.","https://www.perplexity.ai/help-center/en/articles/10354847-api-payment-and-billing"],["google","Google Gemini",["configured-limits"],"Native model-matched QuotaFailure responses when provided; cloud quota permissions differ from an inference key.","https://ai.google.dev/gemini-api/docs/rate-limits"],["google-vertex","Google Vertex AI",["configured-limits"],"Native model-matched quota error details; cloud project/region management and dynamic shared quotas are separate.","https://cloud.google.com/vertex-ai/generative-ai/docs/quotas"],["amazon-bedrock","Amazon Bedrock",[],"Service Quotas/CloudWatch require cloud IAM/region/model mapping not exposed by a portable inference connection.","https://docs.aws.amazon.com/bedrock/latest/userguide/quotas.html"],["cloudflare-workers-ai","Cloudflare Workers AI",[],"Account analytics do not prove remaining free allowance; separate account management capability is required.","https://developers.cloudflare.com/workers-ai/platform/limits/"],["huggingface","Hugging Face Inference Providers",[],"Hub request quota is not an inference-model quota or inference-credit balance.","https://huggingface.co/docs/inference-providers/pricing"],["zai","Z.ai / GLM Coding Plan",[],"No verified external quota contract for monitor/dashboard APIs; private endpoints are excluded.","https://docs.z.ai/devpack/overview"],["kimi-for-coding","Kimi Code subscription",[],"Keep separate from Moonshot API balance; an external subscription usage contract/model mapping must be verified.","https://www.kimi.com/code/docs/en/"],["alibaba","Alibaba Cloud / Qwen / DashScope",[],"Cloud account/project billing permissions and model mapping are required; browser OAuth state is not a quota source.","https://www.alibabacloud.com/help/en/model-studio/"],["opencode","OpenCode Console / Go",["workspace-budget","subscription"],"OpenCode 2.2 public usage API: applicable workspace USD budgets and percent-based Go allowance; not a universal account balance API.","https://github.com/anomalyco/opencode/blob/v2.2.
|
|
647
|
+
var rows=[["openai","OpenAI / Codex",["subscription","api-rate-limits"],"Verified Codex account quota shared across models; HTTP response request/token limits for API connections.","https://developers.openai.com/api/docs/guides/rate-limits"],["anthropic","Anthropic / Claude",["api-rate-limits","configured-limits"],"Model HTTP headers; eligible organization/admin credentials can read configured model limits. Claude subscription windows are separate.","https://platform.claude.com/docs/en/manage-claude/rate-limits-api"],["openrouter","OpenRouter",["key-budget","account-balance"],"Inference-key budget; account credits require a management key. Free-model request limits apply only to free variants.","https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key"],["deepseek","DeepSeek",["account-balance"],"Provider-reported USD/CNY available, granted and topped-up balances.","https://api-docs.deepseek.com/api/get-user-balance"],["moonshotai","Moonshot / Kimi API",["account-balance"],"International USD balances; coding subscriptions are a different product.","https://platform.moonshot.ai/docs/api/balance"],["moonshotai-cn","Moonshot / Kimi API China",["account-balance"],"China CNY balances; never reuse an international key against the China endpoint.","https://platform.moonshot.cn/docs/api/balance"],["minimax","MiniMax",["subscription","account-balance"],"Token Plan model rows/explicit percentages; official SDK balance response for pay-as-you-go keys.","https://platform.minimax.io/docs/token-plan/faq"],["minimax-cn","MiniMax China",["subscription","account-balance"],"Region-specific native Token Plan and SDK balance endpoints.","https://github.com/MiniMax-AI/cli/tree/main/src/sdk/quota"],["github-copilot","GitHub Copilot",["subscription"],"Official SDK token-scoped quota/model RPC; no direct copilot_internal calls or ambient CLI login.","https://github.com/github/copilot-sdk/blob/main/docs/features/usage-and-billing.md"],["groq","Groq",["api-rate-limits"],"Native model response headers: requests per day and tokens per minute.","https://console.groq.com/docs/rate-limits"],["fireworks-ai","Fireworks",["configured-limits","api-rate-limits"],"Native model token/second capacities and account monthly spend quota; GPU quotas are excluded.","https://docs.fireworks.ai/serverless/rate-limits"],["siliconflow","SiliconFlow",["account-balance"],"Native current-user balances; retain unknown currency when the API does not report it.","https://docs.siliconflow.com/en/api-reference/userinfo/get-user-info"],["siliconflow-cn","SiliconFlow China",["account-balance"],"Region-specific current-user balances; currency is unknown when the API omits it.","https://docs.siliconflow.cn/"],["novita-ai","Novita",["account-balance"],"Native current-user balances in 1/10000 USD.","https://novita.ai/docs/api-reference/basic-get-user-balance"],["poe","Poe",["account-balance"],"API account point balance; includes plan and add-on points, not session token usage.","https://creator.poe.com/docs/resources/usage-api"],["nano-gpt","NanoGPT",["account-balance","subscription"],"Native USD/Nano balance and documented subscription token windows; null/degraded counters remain unknown.","https://docs.nano-gpt.com/api-reference/endpoint/subscription-usage"],["aihubmix","AIHubMix",["account-balance"],"Current-account balance API needs a Manage Key; inference keys do not grant management access.","https://docs.aihubmix.com/en/api/CliEndpoints/get-self"],["azure","Azure OpenAI",["api-rate-limits"],"Remaining request/token headers for the actual deployment; no ChatGPT subscription or inferred cloud balance.","https://learn.microsoft.com/en-us/azure/ai-foundry/openai/quotas-limits"],["cerebras","Cerebras",["api-rate-limits"],"Only self-describing native counters actually returned for the selected model; console tier examples are not live quota.","https://inference-docs.cerebras.ai/support/rate-limits"],["mistral","Mistral",[],"Documented remaining header lacks a verified unit/window association; no inferred subscription balance.","https://docs.mistral.ai/resources/known-limitations"],["togetherai","Together AI",[],"Dynamic model limits expose retry intervals, not remaining quota; billing UI does not establish a remaining-credit API.","https://docs.together.ai/docs/rate-limits"],["xai","xAI / Grok",[],"Management billing needs separate team credentials; no verified portable remaining API for this inference connection.","https://docs.x.ai/"],["perplexity","Perplexity",[],"No verified remaining-credit API for an inference key. API credits, consumer subscriptions and Computer credits are distinct.","https://www.perplexity.ai/help-center/en/articles/10354847-api-payment-and-billing"],["google","Google Gemini",["configured-limits"],"Native model-matched QuotaFailure responses when provided; cloud quota permissions differ from an inference key.","https://ai.google.dev/gemini-api/docs/rate-limits"],["google-vertex","Google Vertex AI",["configured-limits"],"Native model-matched quota error details; cloud project/region management and dynamic shared quotas are separate.","https://cloud.google.com/vertex-ai/generative-ai/docs/quotas"],["amazon-bedrock","Amazon Bedrock",[],"Service Quotas/CloudWatch require cloud IAM/region/model mapping not exposed by a portable inference connection.","https://docs.aws.amazon.com/bedrock/latest/userguide/quotas.html"],["cloudflare-workers-ai","Cloudflare Workers AI",[],"Account analytics do not prove remaining free allowance; separate account management capability is required.","https://developers.cloudflare.com/workers-ai/platform/limits/"],["huggingface","Hugging Face Inference Providers",[],"Hub request quota is not an inference-model quota or inference-credit balance.","https://huggingface.co/docs/inference-providers/pricing"],["zai","Z.ai / GLM Coding Plan",[],"No verified external quota contract for monitor/dashboard APIs; private endpoints are excluded.","https://docs.z.ai/devpack/overview"],["kimi-for-coding","Kimi Code subscription",[],"Keep separate from Moonshot API balance; an external subscription usage contract/model mapping must be verified.","https://www.kimi.com/code/docs/en/"],["alibaba","Alibaba Cloud / Qwen / DashScope",[],"Cloud account/project billing permissions and model mapping are required; browser OAuth state is not a quota source.","https://www.alibabacloud.com/help/en/model-studio/"],["opencode","OpenCode Console / Go",["workspace-budget","subscription"],"OpenCode 2.2 public usage API: applicable workspace USD budgets and percent-based Go allowance; not a universal account balance API.","https://github.com/anomalyco/opencode/blob/v2.2.5/packages/schema/src/usage-limits.ts"],["cursor","Cursor",[],"Consumer usage needs a supported external API; no cookie or credential-file integrations.","https://docs.cursor.com/"],["windsurf","Windsurf / Codeium",[],"Consumer plan windows need a supported external API; no private account endpoints.","https://docs.windsurf.com/"],["amp","Amp",[],"Product credits need a supported external account API; no cookie or local credential extraction.","https://ampcode.com/manual"],["ollama","Ollama",[],"Local inference has no provider subscription window; cloud products require their own account API.","https://docs.ollama.com/api"],["lmstudio","LM Studio",[],"Local inference has no provider subscription quota to read.","https://lmstudio.ai/docs/developer"],["nvidia","NVIDIA NIM / NGC",[],"Inference access does not identify cloud/trial NGC credit balance or self-hosted resource quota.","https://docs.nvidia.com/nim/"],["cohere","Cohere",[],"No verified native remaining-counter contract for this integration; static organization tier examples are not live quotas.","https://docs.cohere.com/docs/rate-limits"],["ai21","AI21",[],"No verified native remaining-counter contract or subscription balance endpoint for this integration.","https://docs.ai21.com/"],["replicate","Replicate",[],"Prediction cost is not remaining account credit; no inferred balance from execution cost.","https://replicate.com/docs/topics/billing"],["chutes","Chutes",[],"Current-user quota APIs exist, but their public schemas do not establish native units/model allowance semantics yet.","https://chutes.ai/docs/api-reference/users"],["requesty","Requesty",[],"Enterprise management key and key ID are required; dated usage reports alone are not remaining budget.","https://docs.requesty.ai/features/key-management-api"],["baseten","Baseten",[],"No independently verified portable remaining quota API for the configured inference connection.","https://docs.baseten.co/"],["modelscope","ModelScope",[],"No independently verified portable remaining quota API/model mapping for the selected connection.","https://opencode.ai/docs/providers/"],["nebius","Nebius",[],"Cloud billing/management access is separate from a plain inference credential.","https://docs.nebius.com/"],["vultr","Vultr",[],"Cloud management quota/billing permissions are separate from inference access.","https://docs.vultr.com/"],["v0","Vercel v0",[],"Consumer/product credits need their own documented external account API.","https://v0.dev/docs"]]
|
|
648
648
|
var PROVIDER_QUOTA_CAPABILITIES= rows.map(([id,name,sources,reason,url])=>({id,name,sources,reason,documentation:[url]}))
|
|
649
649
|
var aliases={fireworks:"fireworks-ai",novita:"novita-ai",moonshot:"moonshotai","minimax-coding-plan":"minimax","minimax-coding-plan-cn":"minimax-cn",together:"togetherai","silicon-flow":"siliconflow","github-copilot-enterprise":"github-copilot","google-vertex-anthropic":"google-vertex","z-ai":"zai",zhipuai:"zai",dashscope:"alibaba","alibaba-cn":"alibaba",qwen:"alibaba","opencode-go":"opencode","opencode-zen":"opencode",codeium:"windsurf","azure-cognitive-services":"azure"
|
|
650
650
|
}
|
|
@@ -667,7 +667,10 @@ return [item.type,item.name,item.status]
|
|
|
667
667
|
const key=()=>JSON.stringify([location(),connection(),revision()])
|
|
668
668
|
const invalidate=()=>{generation++
|
|
669
669
|
}
|
|
670
|
-
const disposers=[context.data.on("credential.updated",invalidate),context.data.on("integration.updated",
|
|
670
|
+
const disposers=[context.data.on("credential.updated",invalidate),context.data.on("integration.updated",(event)=>{const directory=event.location?.directory
|
|
671
|
+
if(!directory||directory===location().directory)
|
|
672
|
+
invalidate()
|
|
673
|
+
}),context.data.on("credential.switched",(event)=>{if(event.data.integrationID!=="opencode")
|
|
671
674
|
return
|
|
672
675
|
generation++
|
|
673
676
|
setRevision((value)=>value + 1)
|
|
@@ -1172,7 +1175,11 @@ if(lastModel&&!disposed)
|
|
|
1172
1175
|
read(lastModel)
|
|
1173
1176
|
}
|
|
1174
1177
|
const events=["credential.switched","credential.updated","integration.updated","provider.updated","server.connected"]
|
|
1175
|
-
const unsubscribes=events.map((event)=>context.data.on(event,()=>untrack2(()=>
|
|
1178
|
+
const unsubscribes=events.map((event)=>context.data.on(event,(observation)=>untrack2(()=>{const directory=observation?.location?.directory
|
|
1179
|
+
if((event==="provider.updated"||event==="integration.updated")&&directory&&directory!==location().directory)
|
|
1180
|
+
return
|
|
1181
|
+
invalidate(event!=="provider.updated")
|
|
1182
|
+
})))
|
|
1176
1183
|
return{suspend(){if(!lastModel)
|
|
1177
1184
|
return
|
|
1178
1185
|
lastModel=undefined
|