opencode-navigator 0.27.1 → 0.27.2
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 +8 -0
- package/HOST_API.md +22 -3
- package/README.md +18 -2
- package/dist/gui-experimental.cjs +973 -502
- package/dist/navigator-updates.js +85 -29
- package/dist/tui.js +155 -76
- package/package.json +1 -1
- package/scripts/update-local-snapshot.mjs +13 -1
|
@@ -61,29 +61,38 @@ return reading
|
|
|
61
61
|
}
|
|
62
62
|
refreshNavigator()
|
|
63
63
|
return{openCodeUpdate,navigatorUpdate,refreshNavigator,navigatorCheckState}}
|
|
64
|
-
import {effect as _$
|
|
64
|
+
import {effect as _$effect4} from "@opentui/solid"
|
|
65
|
+
import {insertNode as _$insertNode4} from "@opentui/solid"
|
|
66
|
+
import {createComponent as _$createComponent3} from "@opentui/solid"
|
|
67
|
+
import {insert as _$insert4} from "@opentui/solid"
|
|
68
|
+
import {setProp as _$setProp4} from "@opentui/solid"
|
|
69
|
+
import {createElement as _$createElement4} from "@opentui/solid"
|
|
70
|
+
import {createTextNode as _$createTextNode3} from "@opentui/solid"
|
|
65
71
|
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
66
|
-
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
67
|
-
import {insert as _$insert3} from "@opentui/solid"
|
|
68
72
|
import {setProp as _$setProp3} from "@opentui/solid"
|
|
73
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
74
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
75
|
+
import {memo as _$memo2} from "@opentui/solid"
|
|
76
|
+
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
69
77
|
import {createElement as _$createElement3} from "@opentui/solid"
|
|
70
78
|
import {effect as _$effect2} from "@opentui/solid"
|
|
71
|
-
import {insert as _$insert2} from "@opentui/solid"
|
|
72
79
|
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
73
80
|
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
74
81
|
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
82
|
+
import {insert as _$insert2} from "@opentui/solid"
|
|
83
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
75
84
|
import {setProp as _$setProp2} from "@opentui/solid"
|
|
76
85
|
import {createElement as _$createElement2} from "@opentui/solid"
|
|
86
|
+
import {useIcons} from "./tui.js"
|
|
87
|
+
import {setProp as _$setProp} from "@opentui/solid"
|
|
77
88
|
import {effect as _$effect} from "@opentui/solid"
|
|
78
|
-
import {memo as _$memo} from "@opentui/solid"
|
|
79
89
|
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
80
90
|
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
81
91
|
import {insert as _$insert} from "@opentui/solid"
|
|
82
|
-
import {setProp as _$setProp} from "@opentui/solid"
|
|
83
92
|
import {createElement as _$createElement} from "@opentui/solid"
|
|
84
|
-
import {
|
|
85
|
-
import {createComponent as _$
|
|
86
|
-
import {createSignal as
|
|
93
|
+
import {createEffect,createSignal as createSignal2,onCleanup} from "solid-js"
|
|
94
|
+
import {createComponent as _$createComponent5} from "@opentui/solid"
|
|
95
|
+
import {createSignal as createSignal3} from "solid-js"
|
|
87
96
|
function createManualUpdateCheck(api,status,current,onUpdate){let checking=false
|
|
88
97
|
async function read(){try{return await status.refreshNavigator?.()??"unavailable"
|
|
89
98
|
} catch{return "unavailable"
|
|
@@ -103,17 +112,17 @@ api.ui.toast({variant:result==="unavailable"?"warning":"info",title:"Navigator u
|
|
|
103
112
|
})
|
|
104
113
|
} finally{checking=false
|
|
105
114
|
}}}}
|
|
106
|
-
import {createComponent as _$
|
|
107
|
-
import {onCleanup} from "solid-js"
|
|
115
|
+
import {createComponent as _$createComponent4} from "@opentui/solid"
|
|
116
|
+
import {onCleanup as onCleanup2} from "solid-js"
|
|
108
117
|
import {GuardedConfirmation,SelectionMenu} from "./tui.js"
|
|
109
|
-
function NestedVersionConfirmation(props){
|
|
110
|
-
return _$
|
|
118
|
+
function NestedVersionConfirmation(props){onCleanup2(props.dismiss)
|
|
119
|
+
return _$createComponent4(GuardedConfirmation,{get api(){return props.api
|
|
111
120
|
},get current(){return props.current
|
|
112
121
|
},get title(){return `Update ${props.name}`
|
|
113
122
|
},get message(){return `Install ${props.version} using the current installation method?`
|
|
114
123
|
},get onConfirm(){return props.confirm
|
|
115
124
|
},render:({confirm
|
|
116
|
-
})=>_$
|
|
125
|
+
})=>_$createComponent4(SelectionMenu,{get api(){return props.api
|
|
117
126
|
},get title(){return `Update ${props.name}`
|
|
118
127
|
},get options(){return [{title:"Cancel",value:"cancel",description:"Return without installing an update"
|
|
119
128
|
},{title:`Install ${props.name} ${props.version}`,value:"install",description:"Keep the current installation method and scope; restart OpenCode afterward"
|
|
@@ -123,8 +132,9 @@ return _$createComponent3(GuardedConfirmation,{get api(){return props.api
|
|
|
123
132
|
})
|
|
124
133
|
}
|
|
125
134
|
function createVersionUpdateActions(api,status,updater,rememberNavigatorVersion){const busy=new Set
|
|
126
|
-
const [navigatorUpdating,setNavigatorUpdating]=
|
|
127
|
-
const [navigatorInstalled,setNavigatorInstalled]=
|
|
135
|
+
const [navigatorUpdating,setNavigatorUpdating]=createSignal3(false)
|
|
136
|
+
const [navigatorInstalled,setNavigatorInstalled]=createSignal3()
|
|
137
|
+
const [progress,setProgress]=createSignal3({})
|
|
128
138
|
const installed={}
|
|
129
139
|
let disposed=false
|
|
130
140
|
let confirmation=0
|
|
@@ -140,6 +150,8 @@ return
|
|
|
140
150
|
}
|
|
141
151
|
api.ui.dialog.clear()
|
|
142
152
|
busy.add(kind)
|
|
153
|
+
setProgress((previous)=>({...previous,[kind]:{phase:"preparing"
|
|
154
|
+
}}))
|
|
143
155
|
if(kind==="navigator")
|
|
144
156
|
setNavigatorUpdating(true)
|
|
145
157
|
api.ui.toast({variant:"info",title:`Updating ${label(kind)}`,message:`Installing ${version}...`
|
|
@@ -148,7 +160,13 @@ api.ui.toast({variant:"info",title:`Updating ${label(kind)}`,message:`Installing
|
|
|
148
160
|
await rememberNavigatorVersion?.()
|
|
149
161
|
if(disposed||version!==target(kind))
|
|
150
162
|
throw new Error("Update target changed; check again")
|
|
151
|
-
|
|
163
|
+
const report=(value)=>{if(!disposed&&busy.has(kind))
|
|
164
|
+
setProgress((previous)=>({...previous,[kind]:value
|
|
165
|
+
}))
|
|
166
|
+
}
|
|
167
|
+
report({phase:"installing"
|
|
168
|
+
})
|
|
169
|
+
await updater[kind](version,report)
|
|
152
170
|
})().then(()=>{installed[kind]=version
|
|
153
171
|
if(kind==="navigator")
|
|
154
172
|
setNavigatorInstalled(version)
|
|
@@ -161,6 +179,8 @@ return
|
|
|
161
179
|
api.ui.toast({variant:"error",title:`Could not update ${label(kind)}`,message:error instanceof Error?error.message:"Update failed",duration:6000
|
|
162
180
|
})
|
|
163
181
|
}).finally(()=>{busy.delete(kind)
|
|
182
|
+
setProgress((previous)=>({...previous,[kind]:undefined
|
|
183
|
+
}))
|
|
164
184
|
if(kind==="navigator")
|
|
165
185
|
setNavigatorUpdating(false)
|
|
166
186
|
})
|
|
@@ -177,7 +197,7 @@ return
|
|
|
177
197
|
confirmation++
|
|
178
198
|
update(kind,version)
|
|
179
199
|
}
|
|
180
|
-
if(navigation){navigation.open(()=>_$
|
|
200
|
+
if(navigation){navigation.open(()=>_$createComponent5(NestedVersionConfirmation,{api,get name(){return label(kind)
|
|
181
201
|
},version,current:()=>!disposed&&id===confirmation&&version===target(kind),confirm:onConfirm,cancel:()=>{if(id!==confirmation)
|
|
182
202
|
return
|
|
183
203
|
confirmation++
|
|
@@ -187,7 +207,7 @@ confirmation++
|
|
|
187
207
|
}}))
|
|
188
208
|
return
|
|
189
209
|
}
|
|
190
|
-
api.ui.dialog.replace(()=>_$
|
|
210
|
+
api.ui.dialog.replace(()=>_$createComponent5(api.ui.DialogConfirm,{get title(){return `Update ${label(kind)}`
|
|
191
211
|
},message:`Update to ${version} using the current installation method? OpenCode must be restarted afterward.`,onConfirm:()=>{if(id!==confirmation)
|
|
192
212
|
return
|
|
193
213
|
confirmation++
|
|
@@ -207,16 +227,47 @@ const unregister=api.keymap.registerLayer({commands:[{name:`${PLUGIN_ID}.check-u
|
|
|
207
227
|
api.lifecycle.onDispose(()=>{disposed=true
|
|
208
228
|
unregister()
|
|
209
229
|
})
|
|
210
|
-
return{openCode:(version)=>open("openCode",version),navigator:(version,navigation)=>open("navigator",version,navigation),navigatorUpdating,navigatorInstalled
|
|
230
|
+
return{openCode:(version)=>open("openCode",version),navigator:(version,navigation)=>open("navigator",version,navigation),navigatorUpdating,navigatorInstalled,navigatorProgress:()=>progress().navigator,openCodeProgress:()=>progress().openCode
|
|
211
231
|
}}
|
|
212
232
|
import {homedir} from "os"
|
|
213
233
|
import {basename,dirname,isAbsolute,join} from "path"
|
|
214
234
|
import {fileURLToPath} from "url"
|
|
235
|
+
var prefix="navigator-update-progress:"
|
|
236
|
+
function reportLine(line,report){if(!line.startsWith(prefix)||line.length>1024)
|
|
237
|
+
return
|
|
238
|
+
try{const data=JSON.parse(line.slice(prefix.length))
|
|
239
|
+
if(["preparing","downloading","installing","verifying"].includes(data.phase??""))
|
|
240
|
+
report({phase:data.phase})
|
|
241
|
+
} catch{}}
|
|
242
|
+
async function runSnapshotUpdate(command,report){const child=Bun.spawn([...command],{stdout:"pipe",stderr:"pipe"})
|
|
243
|
+
const error=new Response(child.stderr).text()
|
|
244
|
+
const reader=child.stdout.getReader()
|
|
245
|
+
const decoder=new TextDecoder
|
|
246
|
+
let buffer=""
|
|
247
|
+
const reading=(async ()=>{while(true){const{done,value}=await reader.read()
|
|
248
|
+
if(done)
|
|
249
|
+
return
|
|
250
|
+
buffer += decoder.decode(value,{stream:true})
|
|
251
|
+
const lines=buffer.split(`
|
|
252
|
+
`)
|
|
253
|
+
buffer=(lines.pop()??"").slice(-1024)
|
|
254
|
+
for(const line of lines)
|
|
255
|
+
reportLine(line,report)
|
|
256
|
+
}})().catch(()=>{})
|
|
257
|
+
const exit=await child.exited
|
|
258
|
+
await reader.cancel().catch(()=>{})
|
|
259
|
+
await reading
|
|
260
|
+
const message=await error
|
|
261
|
+
if(exit!==0)
|
|
262
|
+
throw new Error(message.trim()||`Snapshot installer failed (${exit})`)
|
|
263
|
+
}
|
|
215
264
|
async function upgradeHost(current,target,execute){if(!isSameMajorVersion(current,target))
|
|
216
265
|
throw new Error("OpenCode updates must stay on the current major version")
|
|
217
266
|
await execute([process.execPath,"upgrade",target])
|
|
218
267
|
}
|
|
219
|
-
var run=async (command)=>{
|
|
268
|
+
var run=async (command,progress)=>{if(progress&&command[1]?.endsWith("/update-local-snapshot.mjs"))
|
|
269
|
+
return runSnapshotUpdate(command,progress)
|
|
270
|
+
const child=Bun.spawn([...command],{stdout:"ignore",stderr:"pipe"})
|
|
220
271
|
const error=new Response(child.stderr).text()
|
|
221
272
|
const exitCode=await child.exited
|
|
222
273
|
if(exitCode===0)
|
|
@@ -227,10 +278,13 @@ throw new Error(message.trim()||`Command failed with exit code ${child.exitCode}
|
|
|
227
278
|
var readConfig=async (path)=>{const file=Bun.file(path)
|
|
228
279
|
return await file.exists()?Bun.JSONC.parse(await file.text()):undefined
|
|
229
280
|
}
|
|
230
|
-
function pinnedUpdate(wrapper,target,execute){if(basename(wrapper)!=="tui.js"||basename(dirname(wrapper))!=="opencode-navigator")
|
|
281
|
+
function pinnedUpdate(wrapper,target,execute,progress){if(basename(wrapper)!=="tui.js"||basename(dirname(wrapper))!=="opencode-navigator")
|
|
231
282
|
throw new Error("Unrecognized local Navigator source")
|
|
232
283
|
const installer=fileURLToPath(new URL("../scripts/update-local-snapshot.mjs",import.meta.url))
|
|
233
|
-
|
|
284
|
+
const command=["node",installer,wrapper,target]
|
|
285
|
+
if(progress)
|
|
286
|
+
return execute([...command,"--progress-json"],progress)
|
|
287
|
+
return execute(command)
|
|
234
288
|
}
|
|
235
289
|
function configHasPlugin(value,spec){if(!value||typeof value!=="object")
|
|
236
290
|
return false
|
|
@@ -253,8 +307,8 @@ if(configHasPlugin(await read(path),spec))
|
|
|
253
307
|
return false
|
|
254
308
|
return configHasPlugin(await read(global),spec)
|
|
255
309
|
}
|
|
256
|
-
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>upgradeHost(api.app.version,target,execute),async navigator(target){if(meta.source==="file"){const wrapper=meta.spec.startsWith("file://")?fileURLToPath(meta.spec):meta.spec
|
|
257
|
-
return pinnedUpdate(wrapper,target,execute)
|
|
310
|
+
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>upgradeHost(api.app.version,target,execute),async navigator(target,progress){if(meta.source==="file"){const wrapper=meta.spec.startsWith("file://")?fileURLToPath(meta.spec):meta.spec
|
|
311
|
+
return pinnedUpdate(wrapper,target,execute,progress)
|
|
258
312
|
}
|
|
259
313
|
if(meta.source!=="npm")
|
|
260
314
|
throw new Error("Unrecognized local Navigator source")
|
|
@@ -263,20 +317,22 @@ const result=await api.plugins.install(`opencode-navigator@${target}`,{global:aw
|
|
|
263
317
|
if(!result.ok)
|
|
264
318
|
throw new Error(result.message)
|
|
265
319
|
}}}
|
|
266
|
-
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>upgradeHost(context.app.version,target,execute),async navigator(target){
|
|
320
|
+
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>upgradeHost(context.app.version,target,execute),async navigator(target,progress){progress?.({phase:"preparing"})
|
|
321
|
+
const response=await context.client.plugin.list(context.location?{location:context.location}:{})
|
|
267
322
|
const item=response.data.find((plugin)=>plugin.id===PLUGIN_ID)
|
|
268
323
|
if(!item)
|
|
269
324
|
throw new Error("Navigator is not in the active plugin list")
|
|
270
325
|
if(item.source.type==="local")
|
|
271
|
-
return pinnedUpdate(basename(item.source.path)==="tui.js"?item.source.path:join(item.source.path,"tui.js"),target,execute)
|
|
326
|
+
return pinnedUpdate(basename(item.source.path)==="tui.js"?item.source.path:join(item.source.path,"tui.js"),target,execute,progress)
|
|
272
327
|
if(item.source.type!=="package")
|
|
273
328
|
throw new Error("Unrecognized local Navigator source")
|
|
274
329
|
if(isAbsolute(item.source.target))
|
|
275
|
-
return pinnedUpdate(join(item.source.target,"tui.js"),target,execute)
|
|
330
|
+
return pinnedUpdate(join(item.source.target,"tui.js"),target,execute,progress)
|
|
276
331
|
if(item.source.target.startsWith("file://"))
|
|
277
|
-
return pinnedUpdate(join(fileURLToPath(item.source.target),"tui.js"),target,execute)
|
|
332
|
+
return pinnedUpdate(join(fileURLToPath(item.source.target),"tui.js"),target,execute,progress)
|
|
278
333
|
if(item.source.target.startsWith("."))
|
|
279
334
|
throw new Error("Unrecognized local Navigator source")
|
|
335
|
+
progress?.({phase:"installing"})
|
|
280
336
|
await context.client.plugin.update({location:response.location,targets:[item.source.target]})
|
|
281
337
|
}}}
|
|
282
338
|
export{createOpenCodeV1VersionUpdater,createOpenCodeV2VersionUpdater,createVersionStatus,createVersionUpdateActions,parseChangelog2 as parseChangelog,readBundledChangelog2 as readBundledChangelog
|