opencode-navigator 0.17.3 → 0.18.1
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 +13 -0
- package/README.md +32 -5
- package/dist/rpc.js +15 -0
- package/dist/server.js +72 -0
- package/dist/tui.js +217 -53
- package/package.json +12 -4
- package/rpc.js +1 -0
- package/server.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.18.1] - 2026-10-01
|
|
6
|
+
|
|
7
|
+
- Show calm Todo setup guidance in OpenCode 2.x when Navigator's server plugin is absent, without a request error or Retry control. Actual server failures still offer Retry.
|
|
8
|
+
- Keep Quick Action names readable in narrow sidebars by placing unavailable reasons below them and showing shortcuts only when they fit.
|
|
9
|
+
|
|
10
|
+
## [0.18.0] - 2026-10-01
|
|
11
|
+
|
|
12
|
+
- Add durable per-session Todo lists to OpenCode 2.x through a separately configured Navigator server plugin and an agent Todo tool.
|
|
13
|
+
- Update Todo in the sidebar as tasks change, and offer an off-by-default per-session switch for model-context Todo instructions.
|
|
14
|
+
- Keep Todo visible with setup guidance when the OpenCode 2.x server plugin is missing.
|
|
15
|
+
|
|
5
16
|
## [0.17.3] - 2026-09-30
|
|
6
17
|
|
|
7
18
|
## [0.17.2] - 2026-09-30
|
|
@@ -30,6 +41,8 @@
|
|
|
30
41
|
|
|
31
42
|
Earlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).
|
|
32
43
|
|
|
44
|
+
[0.18.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.0...v0.18.1
|
|
45
|
+
[0.18.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.3...v0.18.0
|
|
33
46
|
[0.17.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.2...v0.17.3
|
|
34
47
|
[0.17.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.1...v0.17.2
|
|
35
48
|
[0.17.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.0...v0.17.1
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ See the [changelog](CHANGELOG.md) for release-by-release changes.
|
|
|
12
12
|
|
|
13
13
|
- Theme-aware session title with the session creation date
|
|
14
14
|
- First-run setup guide with interactive section settings
|
|
15
|
-
- Collapsible Todo section with status filters, grouped tasks, progress and priority indicators
|
|
15
|
+
- Collapsible Todo section with status filters, grouped tasks, progress and priority indicators; OpenCode 2 adds session-owned tasks and optional model-context instructions
|
|
16
16
|
- Active subagent list with live statuses and click-to-open navigation, including dev-team workers running in separate local processes
|
|
17
17
|
- Compact, searchable workspace skill list with user-wide favorites, recent skills, source details, and click-to-confirm slash commands
|
|
18
18
|
- Configurable host quick actions, including the auto-approve toggle, with user-wide bookmarks and availability reasons
|
|
@@ -42,8 +42,9 @@ collapsed. Use `Save current layout as default` in sidebar settings to reuse the
|
|
|
42
42
|
current visible/hidden, expanded/collapsed, and ordering states in new sessions.
|
|
43
43
|
|
|
44
44
|
Supports OpenCode 1.18.30 and newer, including OpenCode 2.x. OpenCode 2.0.16 does
|
|
45
|
-
not expose Todo or LSP data to TUI plugins. Navigator
|
|
46
|
-
|
|
45
|
+
not expose host Todo or LSP data to TUI plugins. Navigator supplies its own
|
|
46
|
+
session Todo list through a separately configured server plugin in 2.x. Without
|
|
47
|
+
that plugin, Todo stays visible with setup guidance. LSP is hidden on 2.x while retaining Subagents,
|
|
47
48
|
Skills, Quick Actions, MCP, Search, settings, and presets. All interface icons use Nerd Font glyphs by
|
|
48
49
|
default (Codicons for controls, keyboard symbols for hints, language logos for LSP). Use a Nerd Fonts v3
|
|
49
50
|
terminal font, or select **Settings → Behavior → Icon style → Text fallback**.
|
|
@@ -168,6 +169,32 @@ OpenCode 2.x CLI plugins are global terminal settings; there is no project-local
|
|
|
168
169
|
plugin overrides are required. OpenCode validates `cli.json` strictly, so keep it
|
|
169
170
|
within the linked schema and restart OpenCode after changing it.
|
|
170
171
|
|
|
172
|
+
To enable Todo in OpenCode 2.x, also install the **server** half of Navigator.
|
|
173
|
+
Add the same package to `~/.config/opencode/opencode.json` (or the project
|
|
174
|
+
`opencode.json`):
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"$schema": "https://opencode.ai/config.json",
|
|
179
|
+
"plugin": ["opencode-navigator"]
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
For a local source installation, use the directory containing Navigator's
|
|
184
|
+
`server.js` in the `plugin` array. Keep the TUI package in `cli.json` as above;
|
|
185
|
+
the server configuration alone does not replace it. Restart OpenCode after
|
|
186
|
+
configuring both. Todo items belong to the current session, survive restarts,
|
|
187
|
+
and update in the sidebar when the agent calls `navigator_todo_write`. The
|
|
188
|
+
**Todo instructions: Off/On** control in the Todo section is session-scoped and
|
|
189
|
+
starts **Off**: tasks and the agent tool work without adding Todo instructions
|
|
190
|
+
to the model's context. OpenCode 1.x continues to show the host's Todo list.
|
|
191
|
+
|
|
192
|
+
If you use both OpenCode 1.x and 2.x with the same global `opencode.json`, keep
|
|
193
|
+
that shared server config compatible with 1.x. Place the server-plugin entry
|
|
194
|
+
in a separate JSON file and set `OPENCODE_CONFIG` to its path **only when
|
|
195
|
+
launching OpenCode 2.x**. The TUI configuration in `cli.json` remains separate;
|
|
196
|
+
the OpenCode 1.x launch must not load Navigator's 2.x server plugin.
|
|
197
|
+
|
|
171
198
|
### Install the corner font
|
|
172
199
|
|
|
173
200
|
**Required for rounded multiline selections in Nerd Font mode.** Run the font
|
|
@@ -509,8 +536,8 @@ root order. Activate any badge, including a custom server, to toggle its full ID
|
|
|
509
536
|
in place. Navigator does not open a root/status dialog because OpenCode may report
|
|
510
537
|
an empty root and does not expose the underlying diagnostic error text.
|
|
511
538
|
|
|
512
|
-
Todo priorities are read-only
|
|
513
|
-
|
|
539
|
+
Todo priorities are read-only in the sidebar. OpenCode 1.x provides host Todo
|
|
540
|
+
data without a TUI mutation API; on 2.x, Navigator's agent tool writes tasks.
|
|
514
541
|
|
|
515
542
|
Todo offers `All`, `Active`, and `Finished` views with counts. Active shows running
|
|
516
543
|
tasks before pending tasks. Finished contains separate Completed and Cancelled
|
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
var item={type:"object",properties:{content:{type:"string",minLength:1,maxLength:512},status:{type:"string",enum:["pending","in_progress","completed","cancelled"]},priority:{type:"string",enum:["high","medium","low"]}},required:["content","status"],additionalProperties:false
|
|
2
|
+
}
|
|
3
|
+
var todos={type:"array",items:item,maxItems:100}
|
|
4
|
+
var sessionID={type:"string",minLength:1}
|
|
5
|
+
var output={type:"object",properties:{todos,guidance:{type:"boolean"}},required:["todos","guidance"],additionalProperties:false
|
|
6
|
+
}
|
|
7
|
+
var NavigatorTodoRpc={id:"opencode-navigator.todo",methods:{list:{input:{type:"object",properties:{sessionID},required:["sessionID"],additionalProperties:false},output
|
|
8
|
+
},replace:{input:{type:"object",properties:{sessionID,todos},required:["sessionID","todos"],additionalProperties:false
|
|
9
|
+
},output
|
|
10
|
+
},guidance:{input:{type:"object",properties:{sessionID,enabled:{type:"boolean"}},required:["sessionID","enabled"],additionalProperties:false
|
|
11
|
+
},output
|
|
12
|
+
}},events:{updated:{schema:{type:"object",properties:{sessionID,todos,guidance:{type:"boolean"}},required:["sessionID","todos","guidance"],additionalProperties:false
|
|
13
|
+
}}}}
|
|
14
|
+
export{NavigatorTodoRpc
|
|
15
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {Plugin} from "@opencode/plugin"
|
|
2
|
+
function normalizeTodoState(value){if(!value||typeof value!=="object")
|
|
3
|
+
return{todos:[],guidance:false}
|
|
4
|
+
const state=value
|
|
5
|
+
const statuses=new Set(["pending","in_progress","completed","cancelled"])
|
|
6
|
+
const priorities=new Set(["high","medium","low"])
|
|
7
|
+
const todos=Array.isArray(state.todos)?state.todos.filter((item)=>item&&typeof item.content==="string"&&item.content.trim().length>0&&item.content.length<=512&&statuses.has(item.status)).slice(0,100).map((item)=>({content:item.content.trim(),status:item.status,...priorities.has(item.priority??"")&&{priority:item.priority}})):[]
|
|
8
|
+
return{todos,guidance:state.guidance===true}}
|
|
9
|
+
function todoGuidance(state){const lines=state.todos.map((todo)=>`- [${todo.status}] ${todo.content}`)
|
|
10
|
+
return ["Navigator Todo: when work has multiple steps, use navigator_todo_write to keep the session Todo list current.","Mark work in progress, completed, or cancelled as it changes; avoid claiming unfinished work is done.",...lines.length>0?["Current Navigator Todo items:",...lines]:[]].join(`
|
|
11
|
+
`)
|
|
12
|
+
}
|
|
13
|
+
function key(sessionID){return `session.todo.${sessionID}`
|
|
14
|
+
}
|
|
15
|
+
function createManagedTodos(storage,onChange){const pending=new Map
|
|
16
|
+
async function list(sessionID){return normalizeTodoState(await storage.get(key(sessionID)))
|
|
17
|
+
}
|
|
18
|
+
function change(sessionID,apply){const request=(pending.get(sessionID)??Promise.resolve()).catch(()=>{}).then(async ()=>{const next=apply(await list(sessionID))
|
|
19
|
+
await storage.set(key(sessionID),next)
|
|
20
|
+
await onChange(sessionID,next)
|
|
21
|
+
return next
|
|
22
|
+
})
|
|
23
|
+
pending.set(sessionID,request)
|
|
24
|
+
const clear=()=>{if(pending.get(sessionID)===request)
|
|
25
|
+
pending.delete(sessionID)
|
|
26
|
+
}
|
|
27
|
+
request.then(clear).catch(clear)
|
|
28
|
+
return request
|
|
29
|
+
}
|
|
30
|
+
return{list,replace(sessionID,todos){return change(sessionID,(current)=>({...current,todos:normalizeTodoState({todos}).todos}))
|
|
31
|
+
},guidance(sessionID,enabled){return change(sessionID,(current)=>({...current,guidance:enabled}))
|
|
32
|
+
}}}
|
|
33
|
+
var item={type:"object",properties:{content:{type:"string",minLength:1,maxLength:512},status:{type:"string",enum:["pending","in_progress","completed","cancelled"]},priority:{type:"string",enum:["high","medium","low"]}},required:["content","status"],additionalProperties:false
|
|
34
|
+
}
|
|
35
|
+
var todos={type:"array",items:item,maxItems:100}
|
|
36
|
+
var sessionID={type:"string",minLength:1}
|
|
37
|
+
var output={type:"object",properties:{todos,guidance:{type:"boolean"}},required:["todos","guidance"],additionalProperties:false
|
|
38
|
+
}
|
|
39
|
+
var NavigatorTodoRpc={id:"opencode-navigator.todo",methods:{list:{input:{type:"object",properties:{sessionID},required:["sessionID"],additionalProperties:false},output
|
|
40
|
+
},replace:{input:{type:"object",properties:{sessionID,todos},required:["sessionID","todos"],additionalProperties:false
|
|
41
|
+
},output
|
|
42
|
+
},guidance:{input:{type:"object",properties:{sessionID,enabled:{type:"boolean"}},required:["sessionID","enabled"],additionalProperties:false
|
|
43
|
+
},output
|
|
44
|
+
}},events:{updated:{schema:{type:"object",properties:{sessionID,todos,guidance:{type:"boolean"}},required:["sessionID","todos","guidance"],additionalProperties:false
|
|
45
|
+
}}}};
|
|
46
|
+
var input={type:"object",properties:{todos:NavigatorTodoRpc.methods.replace.input.properties.todos
|
|
47
|
+
},required:["todos"],additionalProperties:false
|
|
48
|
+
}
|
|
49
|
+
var noNotify=async ()=>{}
|
|
50
|
+
var todo_server_default=Plugin.define({id:"opencode-navigator.todo-server",async setup(host){let notify=noNotify
|
|
51
|
+
const todos=createManagedTodos({get:(key)=>host.storage.get(key),set:(key,value)=>host.storage.set(key,value)
|
|
52
|
+
},(sessionID,state)=>notify(sessionID,state))
|
|
53
|
+
const rpc=await host.rpc.register(NavigatorTodoRpc,{list:async (value)=>todos.list(value.sessionID),replace:async (value)=>{const{sessionID,todos:items}=value
|
|
54
|
+
return todos.replace(sessionID,items)
|
|
55
|
+
},guidance:async (value)=>{const{sessionID,enabled}=value
|
|
56
|
+
return todos.guidance(sessionID,enabled)
|
|
57
|
+
}})
|
|
58
|
+
notify=(sessionID,state)=>rpc.events.emit("updated",{sessionID,...state})
|
|
59
|
+
const tools=await host.tool.transform((editor)=>{editor.namespace({name:"navigator",description:"Navigator session tasks"})
|
|
60
|
+
editor.add({name:"todo_write",description:"Replace the Navigator Todo list for this session with the current tasks and their statuses.",input,options:{namespace:"navigator"},execute:async (value,context)=>{const state=await todos.replace(context.sessionID,value.todos)
|
|
61
|
+
return{content:`Navigator Todo updated: ${state.todos.length} tasks.`}}})
|
|
62
|
+
})
|
|
63
|
+
const context=await host.session.hook("context",async (event)=>{const state=await todos.list(event.sessionID)
|
|
64
|
+
if(state.guidance)
|
|
65
|
+
event.system.push({type:"text",text:todoGuidance(state)})
|
|
66
|
+
})
|
|
67
|
+
return async ()=>{await context.dispose()
|
|
68
|
+
await tools.dispose()
|
|
69
|
+
await rpc.dispose()
|
|
70
|
+
}}})
|
|
71
|
+
export{todo_server_default as default
|
|
72
|
+
}
|
package/dist/tui.js
CHANGED
|
@@ -2,7 +2,7 @@ import {insert as _$insert,setProp as _$setProp,createElement as _$createElement
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
import {createSignal as createSignal2,createSignal,createEffect,onCleanup,createContext,useContext,createContext as createContext2,createSignal as createSignal3,useContext as useContext2,createEffect as createEffect2,splitProps,untrack,splitProps as splitProps2,For,createEffect as createEffect3,onCleanup as onCleanup2,Show,splitProps as splitProps3,createSignal as createSignal4,createSignal as createSignal5,createSignal as createSignal6,onCleanup as onCleanup3,batch,createSignal as createSignal8,createSignal as createSignal7,createEffect as createEffect4,createSignal as createSignal9,onCleanup as onCleanup4,createSignal as createSignal10,Index,createSignal as
|
|
5
|
+
import {createSignal as createSignal2,createSignal,createEffect,onCleanup,createContext,useContext,createContext as createContext2,createSignal as createSignal3,useContext as useContext2,createEffect as createEffect2,splitProps,untrack,splitProps as splitProps2,For,createEffect as createEffect3,onCleanup as onCleanup2,Show,splitProps as splitProps3,createSignal as createSignal4,createSignal as createSignal5,createSignal as createSignal6,onCleanup as onCleanup3,batch,createSignal as createSignal8,createSignal as createSignal7,createEffect as createEffect4,createSignal as createSignal9,onCleanup as onCleanup4,createSignal as createSignal10,createSignal as createSignal11,Index,createSignal as createSignal12,onCleanup as onCleanup5,createEffect as createEffect6,onCleanup as onCleanup7,batch as batch2,createEffect as createEffect5,createMemo,createSignal as createSignal13,onCleanup as onCleanup6,onMount,For as For2,For as For3,Show as Show2,createMemo as createMemo2,Show as Show3,createSignal as createSignal14,onCleanup as onCleanup8,For as For4,For as For5,For as For8,createMemo as createMemo4,onMount as onMount3,For as For7,createMemo as createMemo3,onMount as onMount2,Show as Show5,createEffect as createEffect7,createSignal as createSignal15,onCleanup as onCleanup9,Show as Show4,For as For6,For as For9,createEffect as createEffect8,createMemo as createMemo5,onCleanup as onCleanup10,For as For10,createEffect as createEffect9,createMemo as createMemo8,onCleanup as onCleanup11,onMount as onMount4,createMemo as createMemo6,createMemo as createMemo7,Show as Show6,onCleanup as onCleanup12,createSignal as createSignal16,createEffect as createEffect10,onCleanup as onCleanup13,onMount as onMount5,onCleanup as onCleanup14,onMount as onMount6,For as For11,createSignal as createSignal17,createSignal as createSignal18,Show as Show7,createSignal as createSignal20,createSignal as createSignal19,onCleanup as onCleanup15,For as For12,Show as Show10,createMemo as createMemo10,createComputed,createMemo as createMemo9,createSignal as createSignal21,untrack as untrack2,Show as Show8,createComputed as createComputed2,untrack as untrack3,Show as Show9,createEffect as createEffect11,createSignal as createSignal22,createMemo as createMemo12,createSignal as createSignal24,createMemo as createMemo11,For as For13,Show as Show13,Show as Show11,Show as Show12,createSignal as createSignal23,onCleanup as onCleanup16,For as For14,Show as Show15,createMemo as createMemo14,Show as Show14,createMemo as createMemo13,createSignal as createSignal25,createEffect as createEffect12,onCleanup as onCleanup17,For as For19,Match,Switch,createMemo as createMemo18,onCleanup as onCleanup21,For as For15,Show as Show16,createSignal as createSignal26,createEffect as createEffect13,createMemo as createMemo15,onCleanup as onCleanup18,untrack as untrack4,For as For17,Show as Show19,createEffect as createEffect14,createMemo as createMemo16,createSignal as createSignal27,onCleanup as onCleanup19,untrack as untrack5,For as For16,Show as Show18,Show as Show17,Show as Show23,createEffect as createEffect15,createMemo as createMemo17,createSignal as createSignal28,onCleanup as onCleanup20,untrack as untrack6,For as For18,Show as Show21,Show as Show20,Show as Show22,createEffect as createEffect16,createMemo as createMemo19,onCleanup as onCleanup22,untrack as untrack7,Show as Show24,createMemo as createMemo20,onCleanup as onCleanup23,createSignal as createSignal29,onCleanup as onCleanup24,onMount as onMount7} from "solid-js"
|
|
6
6
|
var SIDEBAR_SECTIONS=["todo","subagents","skills","quick_actions","lsp","mcp"]
|
|
7
7
|
var QUICK_ACTION_IDS=["session.rename","session.timeline","session.copy","session.export","session.compact","session.list","session.new","session.fork","messages.copy","session.first","session.last","session.messages_last_user","session.message.next","session.message.previous","permission.mode"]
|
|
8
8
|
function preferencesScope(path){return path.worktree||path.directory||"global"
|
|
@@ -2619,6 +2619,107 @@ activeTarget=undefined
|
|
|
2619
2619
|
requests.abortAll()
|
|
2620
2620
|
refreshing.clear()
|
|
2621
2621
|
}}}}
|
|
2622
|
+
function normalizeTodoState(value){if(!value||typeof value!=="object")
|
|
2623
|
+
return{todos:[],guidance:false}
|
|
2624
|
+
const state=value
|
|
2625
|
+
const statuses=new Set(["pending","in_progress","completed","cancelled"])
|
|
2626
|
+
const priorities=new Set(["high","medium","low"])
|
|
2627
|
+
const todos=Array.isArray(state.todos)?state.todos.filter((item)=>item&&typeof item.content==="string"&&item.content.trim().length>0&&item.content.length<=512&&statuses.has(item.status)).slice(0,100).map((item)=>({content:item.content.trim(),status:item.status,...priorities.has(item.priority??"")&&{priority:item.priority}})):[]
|
|
2628
|
+
return{todos,guidance:state.guidance===true}}
|
|
2629
|
+
|
|
2630
|
+
var item={type:"object",properties:{content:{type:"string",minLength:1,maxLength:512},status:{type:"string",enum:["pending","in_progress","completed","cancelled"]},priority:{type:"string",enum:["high","medium","low"]}},required:["content","status"],additionalProperties:false
|
|
2631
|
+
}
|
|
2632
|
+
var todos={type:"array",items:item,maxItems:100}
|
|
2633
|
+
var sessionID={type:"string",minLength:1}
|
|
2634
|
+
var output={type:"object",properties:{todos,guidance:{type:"boolean"}},required:["todos","guidance"],additionalProperties:false
|
|
2635
|
+
}
|
|
2636
|
+
var NavigatorTodoRpc={id:"opencode-navigator.todo",methods:{list:{input:{type:"object",properties:{sessionID},required:["sessionID"],additionalProperties:false},output
|
|
2637
|
+
},replace:{input:{type:"object",properties:{sessionID,todos},required:["sessionID","todos"],additionalProperties:false
|
|
2638
|
+
},output
|
|
2639
|
+
},guidance:{input:{type:"object",properties:{sessionID,enabled:{type:"boolean"}},required:["sessionID","enabled"],additionalProperties:false
|
|
2640
|
+
},output
|
|
2641
|
+
}},events:{updated:{schema:{type:"object",properties:{sessionID,todos,guidance:{type:"boolean"}},required:["sessionID","todos","guidance"],additionalProperties:false
|
|
2642
|
+
}}}};
|
|
2643
|
+
function isMissingServer(error){return typeof error==="object"&&error!==null&&"type" in error&&error.type==="rpc.unavailable"
|
|
2644
|
+
}
|
|
2645
|
+
function createNavigatorTodoController(context,api){const rpc=context.client.rpc(NavigatorTodoRpc)
|
|
2646
|
+
const [sessions,setSessions]=createSignal11({})
|
|
2647
|
+
const [saving,setSaving]=createSignal11({})
|
|
2648
|
+
const [errors,setErrors]=createSignal11({})
|
|
2649
|
+
const [missing,setMissing]=createSignal11({})
|
|
2650
|
+
const requests=createRequestState(api.lifecycle.signal)
|
|
2651
|
+
const refreshing=new Map
|
|
2652
|
+
const revisions=new Map
|
|
2653
|
+
let activeTarget
|
|
2654
|
+
function target(sessionID){const session=api.state.session.get(sessionID)
|
|
2655
|
+
const directory=session?.directory??api.state.path.directory
|
|
2656
|
+
const workspace=session?.workspaceID
|
|
2657
|
+
return{key:JSON.stringify([sessionID,directory,workspace??null]),sessionID,routing:{directory}}}
|
|
2658
|
+
function set(key,value){setSessions((current)=>({...current,[key]:normalizeTodoState(value)}))
|
|
2659
|
+
}
|
|
2660
|
+
function refresh(sessionID,force=false){const current=target(sessionID)
|
|
2661
|
+
const pending=refreshing.get(current.key)
|
|
2662
|
+
if(pending&&!force)
|
|
2663
|
+
return pending
|
|
2664
|
+
const revision=revisions.get(current.key)??0
|
|
2665
|
+
const requestState=requests.start(current.key,"refresh Navigator todos",current.key in sessions(),force)
|
|
2666
|
+
if(!requestState)
|
|
2667
|
+
return pending
|
|
2668
|
+
const request=rpc.list({sessionID},{location:current.routing,signal:requestState.signal}).then((value)=>{const state=normalizeTodoState(value)
|
|
2669
|
+
if(requestState.isCurrent()){setMissing((values)=>({...values,[current.key]:false}))
|
|
2670
|
+
if((revisions.get(current.key)??0)===revision)
|
|
2671
|
+
set(current.key,state)
|
|
2672
|
+
}
|
|
2673
|
+
requestState.succeed()
|
|
2674
|
+
return state
|
|
2675
|
+
}).catch((error)=>{if(requestState.isCurrent()&&!requestState.signal.aborted)
|
|
2676
|
+
setMissing((values)=>({...values,[current.key]:isMissingServer(error)}))
|
|
2677
|
+
requestState.fail(error)
|
|
2678
|
+
throw error
|
|
2679
|
+
}).finally(()=>{requestState.finish()
|
|
2680
|
+
if(refreshing.get(current.key)===request)
|
|
2681
|
+
refreshing.delete(current.key)
|
|
2682
|
+
})
|
|
2683
|
+
refreshing.set(current.key,request)
|
|
2684
|
+
return request
|
|
2685
|
+
}
|
|
2686
|
+
const unsubscribe=rpc.events.on("updated",(event)=>{const{sessionID}=event.data
|
|
2687
|
+
if(typeof sessionID!=="string")
|
|
2688
|
+
return
|
|
2689
|
+
const current=target(sessionID)
|
|
2690
|
+
if(event.location.directory!==current.routing.directory)
|
|
2691
|
+
return
|
|
2692
|
+
revisions.set(current.key,(revisions.get(current.key)??0) + 1)
|
|
2693
|
+
set(current.key,normalizeTodoState(event.data))
|
|
2694
|
+
})
|
|
2695
|
+
api.lifecycle.onDispose(unsubscribe)
|
|
2696
|
+
return{target,list(sessionID){return sessions()[target(sessionID).key]?.todos??[]
|
|
2697
|
+
},refresh,state(sessionID){return requests.state(target(sessionID).key)
|
|
2698
|
+
},missing(sessionID){return missing()[target(sessionID).key]??false
|
|
2699
|
+
},retry(sessionID){return refresh(sessionID,true)
|
|
2700
|
+
},guidance(sessionID){const key=target(sessionID).key
|
|
2701
|
+
return{enabled:sessions()[key]?.guidance??false,saving:saving()[key]??false,error:errors()[key],available:key in sessions()
|
|
2702
|
+
}},async setGuidance(sessionID,enabled){const current=target(sessionID)
|
|
2703
|
+
if(!(current.key in sessions())||saving()[current.key])
|
|
2704
|
+
return
|
|
2705
|
+
setSaving((value)=>({...value,[current.key]:true}))
|
|
2706
|
+
setErrors((value)=>({...value,[current.key]:undefined}))
|
|
2707
|
+
try{const state=await rpc.guidance({sessionID,enabled},{location:current.routing})
|
|
2708
|
+
revisions.set(current.key,(revisions.get(current.key)??0) + 1)
|
|
2709
|
+
set(current.key,normalizeTodoState(state))
|
|
2710
|
+
} catch(error){setErrors((value)=>({...value,[current.key]:error instanceof Error?error.message:String(error)}))
|
|
2711
|
+
} finally{setSaving((value)=>({...value,[current.key]:false}))
|
|
2712
|
+
}},activate(sessionID){const key=target(sessionID).key
|
|
2713
|
+
if(activeTarget!==key){requests.abortAll()
|
|
2714
|
+
refreshing.clear()
|
|
2715
|
+
activeTarget=key
|
|
2716
|
+
}
|
|
2717
|
+
return()=>{if(activeTarget!==key)
|
|
2718
|
+
return
|
|
2719
|
+
activeTarget=undefined
|
|
2720
|
+
requests.abortAll()
|
|
2721
|
+
refreshing.clear()
|
|
2722
|
+
}}}}
|
|
2622
2723
|
function buildTodoView(todos,mode){const active=[...todos.filter((item)=>item.status==="in_progress"),...todos.filter((item)=>item.status==="pending")]
|
|
2623
2724
|
const completed=todos.filter((item)=>item.status==="completed")
|
|
2624
2725
|
const cancelled=todos.filter((item)=>item.status==="cancelled")
|
|
@@ -2673,7 +2774,7 @@ return action.label
|
|
|
2673
2774
|
const command=api.keymap.getCommands?.({visibility:"registered"}).find((candidate)=>candidate.name===action.command)
|
|
2674
2775
|
return typeof command?.title==="string"?command.title:action.label
|
|
2675
2776
|
}
|
|
2676
|
-
function createQuickActionRevision(api){const [revision,setRevision]=
|
|
2777
|
+
function createQuickActionRevision(api){const [revision,setRevision]=createSignal12(0)
|
|
2677
2778
|
const unsubscribe=api.keymap.on?.("state",()=>setRevision((value)=>value + 1))
|
|
2678
2779
|
if(unsubscribe)
|
|
2679
2780
|
onCleanup5(unsubscribe)
|
|
@@ -2771,7 +2872,7 @@ const [selectedID,setSelectedID]=useDialogState("selection",undefined)
|
|
|
2771
2872
|
const [views]=useDialogState("tab-views",new Map)
|
|
2772
2873
|
const tabViews=views()
|
|
2773
2874
|
const [scrollTop,setScrollTop]=useDialogState("scroll",0)
|
|
2774
|
-
const [refreshing,setRefreshing]=
|
|
2875
|
+
const [refreshing,setRefreshing]=createSignal13(false)
|
|
2775
2876
|
const theme=()=>props.api.theme.current
|
|
2776
2877
|
const icons=useIcons()
|
|
2777
2878
|
const commandRevision=createQuickActionRevision(props.api)
|
|
@@ -3397,8 +3498,8 @@ return _el$
|
|
|
3397
3498
|
}
|
|
3398
3499
|
function FirstRunWizard(props){const icons=useIcons()
|
|
3399
3500
|
const dialogs=useDialogs(props.api)
|
|
3400
|
-
const [active,setActive]=
|
|
3401
|
-
const [step,setStep]=
|
|
3501
|
+
const [active,setActive]=createSignal14(0)
|
|
3502
|
+
const [step,setStep]=createSignal14(0)
|
|
3402
3503
|
const theme=()=>props.api.theme.current
|
|
3403
3504
|
const sections=SECTION_DEFINITIONS.filter((section)=>supportsSidebarSection(props.api,section.name))
|
|
3404
3505
|
const finishIndex=sections.length
|
|
@@ -3586,7 +3687,7 @@ const dialogs=useDialogs(props.api)
|
|
|
3586
3687
|
const theme=()=>props.api.theme.current
|
|
3587
3688
|
const dimensions=useTerminalDimensions4()
|
|
3588
3689
|
const scroll=useDialogScroll()
|
|
3589
|
-
const [active,setActive]=
|
|
3690
|
+
const [active,setActive]=createSignal15("apply")
|
|
3590
3691
|
let body
|
|
3591
3692
|
const prefix=`${PLUGIN_ID}.preset-preview`
|
|
3592
3693
|
function activate(action){if(!props.valid()){dialogs.close()
|
|
@@ -4628,7 +4729,7 @@ return _$createElement("box")
|
|
|
4628
4729
|
|
|
4629
4730
|
|
|
4630
4731
|
function SettingsFooterButton(props){const icons=useIcons()
|
|
4631
|
-
const [hovered,setHovered]=
|
|
4732
|
+
const [hovered,setHovered]=createSignal16(false)
|
|
4632
4733
|
const theme=()=>props.api.theme.current
|
|
4633
4734
|
return _$createComponent(IconControl,{id:`${PLUGIN_ID}.settings.footer`,get icon(){return icons.icon("settings")
|
|
4634
4735
|
},get foregroundColor(){return _$memo(()=>!!hovered())()?theme().text:theme().textMuted
|
|
@@ -4849,8 +4950,8 @@ return _$createElement("box")
|
|
|
4849
4950
|
|
|
4850
4951
|
var NAVIGATOR_PACKAGE_URL="https://registry.npmjs.org/opencode-navigator/latest"
|
|
4851
4952
|
var REQUEST_TIMEOUT_MS=5000
|
|
4852
|
-
function createVersionStatus(api,navigatorVersion,request=fetch){const [openCodeUpdate,setOpenCodeUpdate]=
|
|
4853
|
-
const [navigatorUpdate,setNavigatorUpdate]=
|
|
4953
|
+
function createVersionStatus(api,navigatorVersion,request=fetch){const [openCodeUpdate,setOpenCodeUpdate]=createSignal17()
|
|
4954
|
+
const [navigatorUpdate,setNavigatorUpdate]=createSignal17()
|
|
4854
4955
|
const controller=new AbortController
|
|
4855
4956
|
const timeout=setTimeout(()=>controller.abort(),REQUEST_TIMEOUT_MS)
|
|
4856
4957
|
const unsubscribe=api.event.on("installation.update-available",(event)=>{const version=event.properties.version
|
|
@@ -5013,9 +5114,9 @@ return false
|
|
|
5013
5114
|
return true
|
|
5014
5115
|
}
|
|
5015
5116
|
function createSidebarInteraction(api,showHelp=()=>openKeyboardHelp(api)){const descriptors=new Map
|
|
5016
|
-
const [selectedId,setSelectedId]=
|
|
5017
|
-
const [focusWithin,setFocusWithin]=
|
|
5018
|
-
const [revision,setRevision]=
|
|
5117
|
+
const [selectedId,setSelectedId]=createSignal18()
|
|
5118
|
+
const [focusWithin,setFocusWithin]=createSignal18(false)
|
|
5119
|
+
const [revision,setRevision]=createSignal18(0)
|
|
5019
5120
|
let titleRoot
|
|
5020
5121
|
let contentRoot
|
|
5021
5122
|
let targetedRoot
|
|
@@ -5284,7 +5385,7 @@ else if(highlighted)
|
|
|
5284
5385
|
foregroundColor=theme.selectedListItemText
|
|
5285
5386
|
return{backgroundColor,foregroundColor}}
|
|
5286
5387
|
function useSidebarItem(api,interaction,descriptor,normalColor=()=>api.theme.current.text,mode="row"){let unregister
|
|
5287
|
-
const [hovered,setHovered]=
|
|
5388
|
+
const [hovered,setHovered]=createSignal19(false)
|
|
5288
5389
|
const disabled=()=>descriptor.disabled?.()===true
|
|
5289
5390
|
const focused=()=>Boolean(interaction?.ownsFocus()&&interaction.isSelected(descriptor.id))
|
|
5290
5391
|
const colors=()=>sidebarInteractiveColors(api.theme.current,{focused:focused(),hovered:hovered(),disabled:disabled()},normalColor(),mode)
|
|
@@ -5302,7 +5403,7 @@ return true
|
|
|
5302
5403
|
}}}
|
|
5303
5404
|
function LspBadge(props){const icons=useIcons()
|
|
5304
5405
|
const isKnown=lspIconName(props.id)!==undefined
|
|
5305
|
-
const [showName,setShowName]=
|
|
5406
|
+
const [showName,setShowName]=createSignal20(false)
|
|
5306
5407
|
const statusColor=()=>props.status==="connected"?props.api.theme.current.success:props.api.theme.current.error
|
|
5307
5408
|
if(!isKnown){return(()=>{var _el$=_$createElement("text")
|
|
5308
5409
|
_$setProp(_el$,"flexShrink",1)
|
|
@@ -5345,7 +5446,7 @@ return _el$3
|
|
|
5345
5446
|
|
|
5346
5447
|
|
|
5347
5448
|
|
|
5348
|
-
function createListVisibility(options){const [expanded,setExpanded]=
|
|
5449
|
+
function createListVisibility(options){const [expanded,setExpanded]=createSignal21(false)
|
|
5349
5450
|
let previousKey
|
|
5350
5451
|
let previousLimit
|
|
5351
5452
|
const canToggle=createMemo9(()=>options.limit()>0&&options.items().length>options.limit())
|
|
@@ -5427,7 +5528,7 @@ result += segment
|
|
|
5427
5528
|
return result + ellipsis
|
|
5428
5529
|
}
|
|
5429
5530
|
function Section(props){const icons=useIcons()
|
|
5430
|
-
const [actionWidth,setActionWidth]=
|
|
5531
|
+
const [actionWidth,setActionWidth]=createSignal22()
|
|
5431
5532
|
const icon=()=>props.section?icons.section(props.section):props.icon
|
|
5432
5533
|
const theme=()=>props.api.theme.current
|
|
5433
5534
|
const item=useSidebarItem(props.api,props.interaction,{id:props.sectionId??`section.${props.title}`,position:()=>({section:props.navigationSection??0,row:0,column:0
|
|
@@ -5778,7 +5879,7 @@ return _el$2
|
|
|
5778
5879
|
function SectionFilter(props){const icons=useIcons()
|
|
5779
5880
|
let input
|
|
5780
5881
|
let unregisterInput
|
|
5781
|
-
const [inputFocused,setInputFocused]=
|
|
5882
|
+
const [inputFocused,setInputFocused]=createSignal23(false)
|
|
5782
5883
|
const theme=()=>props.api.theme.current
|
|
5783
5884
|
const item=useSidebarItem(props.api,props.interaction,{id:props.id??`filter.${props.placeholder}`,position:()=>props.position??{section:0,row:0,column:0
|
|
5784
5885
|
},activate:()=>{if(!input)
|
|
@@ -5953,7 +6054,7 @@ return _el$
|
|
|
5953
6054
|
}})
|
|
5954
6055
|
}
|
|
5955
6056
|
function McpSection(props){const icons=useIcons()
|
|
5956
|
-
const [query,setQuery]=
|
|
6057
|
+
const [query,setQuery]=createSignal24("")
|
|
5957
6058
|
const model=createMcpSectionModel(props,query)
|
|
5958
6059
|
const navigationSection=()=>props.navigationSection??6
|
|
5959
6060
|
const summary=createMemo12(()=>`${model.active()}/${model.list().length}${model.errors() ? ` \xB7 ${model.errors()} ${icons.icon("error")}` : ""}`)
|
|
@@ -5990,10 +6091,14 @@ return _$createComponent(SectionWithHeaderAction,{get api(){return props.api
|
|
|
5990
6091
|
|
|
5991
6092
|
function QuickActionRow(props){const icons=useIcons()
|
|
5992
6093
|
const theme=()=>props.api.theme.current
|
|
6094
|
+
const [width,setWidth]=createSignal25(0)
|
|
5993
6095
|
const shortcut=createMemo13(()=>{const bindings=props.api.keymap.getCommandBindings({visibility:"registered",commands:[props.action.command]
|
|
5994
6096
|
})
|
|
5995
6097
|
return props.api.keys.formatBindings(bindings.get(props.action.command))
|
|
5996
6098
|
})
|
|
6099
|
+
const visibleShortcut=createMemo13(()=>{const value=shortcut()
|
|
6100
|
+
return value&&width()>=Bun.stringWidth(props.action.label) + Bun.stringWidth(value) + 9?value:undefined
|
|
6101
|
+
})
|
|
5997
6102
|
function run(){if(props.action.command==="session.new"&&props.onNewSession?.())
|
|
5998
6103
|
return
|
|
5999
6104
|
const result=props.interaction?props.interaction.dispatchFromReturnTarget(props.action.command):props.api.keymap.dispatchCommand(props.action.command)
|
|
@@ -6014,6 +6119,7 @@ return background==="transparent"?row.backgroundColor():background
|
|
|
6014
6119
|
}
|
|
6015
6120
|
return _$createComponent(ListRow,{ref:(node)=>row.ref(node),get id(){return id()
|
|
6016
6121
|
},paddingLeft:1,paddingRight:1,get marginTop(){return props.separator?1:0
|
|
6122
|
+
},onSizeChange:function(){setWidth(this.width)
|
|
6017
6123
|
},get backgroundColor(){return row.backgroundColor()
|
|
6018
6124
|
},get onMouseOver(){return row.onMouseOver
|
|
6019
6125
|
},get onMouseOut(){return row.onMouseOut
|
|
@@ -6027,14 +6133,11 @@ return _el$
|
|
|
6027
6133
|
_$setProp(_el$2,"flexGrow",1)
|
|
6028
6134
|
_$setProp(_el$2,"wrapMode","none")
|
|
6029
6135
|
_$setProp(_el$2,"truncate",true)
|
|
6030
|
-
_$insert(_el$2,()=>props.action.label
|
|
6031
|
-
_$insert(_el$2,(()=>{var _c$=_$memo(()=>!!props.disabled)
|
|
6032
|
-
return()=>_c$()?` \xB7 ${props.disabled}`:""
|
|
6033
|
-
})(),null)
|
|
6136
|
+
_$insert(_el$2,()=>props.action.label)
|
|
6034
6137
|
_$effect((_$p)=>_$setProp(_el$2,"fg",row.foregroundColor(),_$p))
|
|
6035
6138
|
return _el$2
|
|
6036
6139
|
})()
|
|
6037
|
-
},get metadata(){return _$createComponent(Show14,{get when(){return
|
|
6140
|
+
},get metadata(){return _$createComponent(Show14,{get when(){return visibleShortcut()
|
|
6038
6141
|
},children:(value)=>(()=>{var _el$3=_$createElement("text")
|
|
6039
6142
|
_$setProp(_el$3,"flexShrink",0)
|
|
6040
6143
|
_$setProp(_el$3,"wrapMode","none")
|
|
@@ -6043,6 +6146,14 @@ _$effect((_$p)=>_$setProp(_el$3,"fg",row.focused()?row.foregroundColor():theme()
|
|
|
6043
6146
|
return _el$3
|
|
6044
6147
|
})()
|
|
6045
6148
|
})
|
|
6149
|
+
},get details(){return _$createComponent(Show14,{get when(){return props.disabled
|
|
6150
|
+
},children:(reason)=>(()=>{var _el$4=_$createElement("text")
|
|
6151
|
+
_$setProp(_el$4,"wrapMode","word")
|
|
6152
|
+
_$insert(_el$4,reason)
|
|
6153
|
+
_$effect((_$p)=>_$setProp(_el$4,"fg",row.focused()?row.foregroundColor():theme().textMuted,_$p))
|
|
6154
|
+
return _el$4
|
|
6155
|
+
})()
|
|
6156
|
+
})
|
|
6046
6157
|
},get trailing(){return _$createComponent(BookmarkControl,{ref:(node)=>favorite.ref(node),get id(){return `${id()}.favorite`
|
|
6047
6158
|
},get bookmarked(){return props.favorite
|
|
6048
6159
|
},get backgroundColor(){return controlBackground()
|
|
@@ -6299,7 +6410,7 @@ return _el$2
|
|
|
6299
6410
|
}})
|
|
6300
6411
|
}
|
|
6301
6412
|
function SkillsSection(props){const dialogs=useDialogs(props.api)
|
|
6302
|
-
const [query,setQuery]=
|
|
6413
|
+
const [query,setQuery]=createSignal26("")
|
|
6303
6414
|
const model=createSkillSectionModel(props,query)
|
|
6304
6415
|
const navigationSection=()=>props.navigationSection??3
|
|
6305
6416
|
function selectSkill(item){if(!props.preferences.shouldConfirmSkill(item)){model.useSkill(item)
|
|
@@ -6374,8 +6485,8 @@ return _el$
|
|
|
6374
6485
|
function createSubagentSectionModel(props){const list=createMemo16(()=>props.controller.list(props.sessionID))
|
|
6375
6486
|
const recent=createMemo16(()=>props.controller.recent?.(props.sessionID)??[])
|
|
6376
6487
|
const rows=createMemo16(()=>buildSubagentView(list(),recent()))
|
|
6377
|
-
const [query,setQuery]=
|
|
6378
|
-
const [mode,setMode]=
|
|
6488
|
+
const [query,setQuery]=createSignal27("")
|
|
6489
|
+
const [mode,setMode]=createSignal27("all")
|
|
6379
6490
|
const counts=createMemo16(()=>countSubagentView(rows(),query()))
|
|
6380
6491
|
const tabs=createMemo16(()=>["all","active","recent",...counts().errors>0?["errors"]:[]])
|
|
6381
6492
|
const filtered=createMemo16(()=>filterSubagentView(rows(),mode(),query()))
|
|
@@ -6657,6 +6768,7 @@ return _el$
|
|
|
6657
6768
|
})()
|
|
6658
6769
|
}
|
|
6659
6770
|
function TodoContents(props){const navigationSection=()=>props.navigationSection??1
|
|
6771
|
+
const tabsRow=()=>props.managed?3:2
|
|
6660
6772
|
return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("box")
|
|
6661
6773
|
_$insertNode(_el$,_el$2)
|
|
6662
6774
|
_$setProp(_el$,"gap",1)
|
|
@@ -6664,7 +6776,7 @@ _$setProp(_el$2,"flexDirection","row")
|
|
|
6664
6776
|
_$setProp(_el$2,"flexWrap","wrap")
|
|
6665
6777
|
_$insert(_el$2,_$createComponent(For18,{each:["all","active","finished"],children:(value,index)=>_$createComponent(SectionTab,{get api(){return props.api
|
|
6666
6778
|
},get interaction(){return props.interaction
|
|
6667
|
-
},id:`${PLUGIN_ID}.todo.filter.${value}`,get position(){return{section:navigationSection(),row:
|
|
6779
|
+
},id:`${PLUGIN_ID}.todo.filter.${value}`,get position(){return{section:navigationSection(),row:tabsRow(),column:index()
|
|
6668
6780
|
}},get label(){return value[0].toUpperCase() + value.slice(1)
|
|
6669
6781
|
},get count(){return props.view.counts[value]
|
|
6670
6782
|
},get selected(){return props.mode===value
|
|
@@ -6698,7 +6810,8 @@ return _el$3
|
|
|
6698
6810
|
_$insert(_el$,_$createComponent(ListVisibilityControl,{get api(){return props.api
|
|
6699
6811
|
},get interaction(){return props.interaction
|
|
6700
6812
|
},section:"todo",get navigationSection(){return navigationSection()
|
|
6701
|
-
},
|
|
6813
|
+
},get row(){return tabsRow() + 1
|
|
6814
|
+
},get visibility(){return props.visibility
|
|
6702
6815
|
}}),null)
|
|
6703
6816
|
return _el$
|
|
6704
6817
|
})()
|
|
@@ -6709,10 +6822,39 @@ _$effect((_$p)=>_$setProp(_el$6,"fg",props.api.theme.current.textMuted,_$p))
|
|
|
6709
6822
|
return _el$6
|
|
6710
6823
|
})()
|
|
6711
6824
|
}
|
|
6825
|
+
|
|
6826
|
+
|
|
6827
|
+
|
|
6828
|
+
|
|
6829
|
+
|
|
6830
|
+
|
|
6831
|
+
function TodoGuidanceControl(props){const state=()=>props.controller.guidance(props.sessionID)
|
|
6832
|
+
return _$createComponent(Show22,{get when(){return state().available
|
|
6833
|
+
},get children(){var _el$=_$createElement("box")
|
|
6834
|
+
_$insert(_el$,_$createComponent(SectionTab,{get api(){return props.api
|
|
6835
|
+
},get interaction(){return props.interaction
|
|
6836
|
+
},id:`${PLUGIN_ID}.todo.guidance`,get position(){return{section:props.navigationSection,row:2,column:0
|
|
6837
|
+
}},get label(){return `Todo instructions: ${state().enabled ? "On" : "Off"}`
|
|
6838
|
+
},get selected(){return state().enabled
|
|
6839
|
+
},get disabled(){return state().saving
|
|
6840
|
+
},onActivate:()=>void props.controller.setGuidance(props.sessionID,!state().enabled)
|
|
6841
|
+
}),null)
|
|
6842
|
+
_$insert(_el$,_$createComponent(Show22,{get when(){return state().error
|
|
6843
|
+
},children:(message)=>(()=>{var _el$2=_$createElement("text")
|
|
6844
|
+
_$setProp(_el$2,"wrapMode","word")
|
|
6845
|
+
_$insert(_el$2,message)
|
|
6846
|
+
_$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.error,_$p))
|
|
6847
|
+
return _el$2
|
|
6848
|
+
})()
|
|
6849
|
+
}),null)
|
|
6850
|
+
return _el$
|
|
6851
|
+
}})
|
|
6852
|
+
}
|
|
6712
6853
|
function TodoSection(props){const list=createMemo17(()=>props.controller.list(props.sessionID))
|
|
6713
6854
|
const icons=useIcons()
|
|
6714
6855
|
const unavailable=()=>hostCapabilityUnavailable(props.api,"todo")
|
|
6715
|
-
const
|
|
6856
|
+
const managed=()=>("guidance" in props.controller)?props.controller:undefined
|
|
6857
|
+
const [mode,setMode]=createSignal28("all")
|
|
6716
6858
|
const targetKey=createMemo17(()=>props.controller.target?.(props.sessionID).key??props.sessionID)
|
|
6717
6859
|
createEffect15(()=>{targetKey()
|
|
6718
6860
|
setMode("all")
|
|
@@ -6733,30 +6875,51 @@ const navigationSection=()=>props.navigationSection??1
|
|
|
6733
6875
|
return _$createComponent(Section,{get api(){return props.api
|
|
6734
6876
|
},get interaction(){return props.interaction
|
|
6735
6877
|
},sectionId:`${PLUGIN_ID}.section.todo`,get navigationSection(){return navigationSection()
|
|
6736
|
-
},title:"TODO",section:"todo",get summary(){return _$memo(()=>!!unavailable())()?"\u2014":`${view().counts.completed}/${list().length}`
|
|
6878
|
+
},title:"TODO",section:"todo",get summary(){return _$memo(()=>!!(unavailable()||managed()?.missing(props.sessionID)))()?"\u2014":`${view().counts.completed}/${list().length}`
|
|
6737
6879
|
},get open(){return props.preferences.expanded().todo
|
|
6738
|
-
},onToggle:()=>props.preferences.toggleSectionExpanded("todo"),get children(){return _$createComponent(
|
|
6880
|
+
},onToggle:()=>props.preferences.toggleSectionExpanded("todo"),get children(){return _$createComponent(Show23,{get when(){return unavailable()
|
|
6881
|
+
},get fallback(){return(()=>{var _el$=_$createElement("box")
|
|
6882
|
+
_$setProp(_el$,"gap",1)
|
|
6883
|
+
_$insert(_el$,_$createComponent(Show23,{get when(){return managed()?.guidance(props.sessionID).available
|
|
6884
|
+
},get children(){return _$createComponent(TodoGuidanceControl,{get api(){return props.api
|
|
6885
|
+
},get controller(){return managed()
|
|
6886
|
+
},get sessionID(){return props.sessionID
|
|
6887
|
+
},get interaction(){return props.interaction
|
|
6888
|
+
},get navigationSection(){return navigationSection()
|
|
6889
|
+
}})
|
|
6890
|
+
}}),null)
|
|
6891
|
+
_$insert(_el$,_$createComponent(Show23,{get when(){return managed()?.missing(props.sessionID)
|
|
6739
6892
|
},get fallback(){return _$createComponent(SectionRequestBody,{get api(){return props.api
|
|
6740
6893
|
},get interaction(){return props.interaction
|
|
6741
6894
|
},id:`${PLUGIN_ID}.retry.todo`,get position(){return{section:navigationSection(),row:1,column:0
|
|
6742
6895
|
}},get state(){return state()
|
|
6743
6896
|
},get hasItems(){return list().length>0
|
|
6744
|
-
},empty:"No tasks yet",loading:"Loading tasks\u2026",onRetry:()=>void props.controller.retry(props.sessionID),get children(){return _$createComponent(TodoContents,{get api(){return props.api
|
|
6897
|
+
},empty:"No tasks yet",loading:"Loading tasks\u2026",onRetry:()=>void props.controller.retry(props.sessionID).catch(()=>{}),get children(){return _$createComponent(TodoContents,{get api(){return props.api
|
|
6745
6898
|
},get interaction(){return props.interaction
|
|
6746
6899
|
},get navigationSection(){return props.navigationSection
|
|
6747
6900
|
},get mode(){return mode()
|
|
6748
6901
|
},setMode,get view(){return view()
|
|
6749
6902
|
},visibility,get density(){return props.preferences.rowDensity?.()??"compact"
|
|
6903
|
+
},get managed(){return Boolean(managed())
|
|
6750
6904
|
}})
|
|
6751
6905
|
}})
|
|
6752
|
-
},children
|
|
6753
|
-
_$insertNode(_el
|
|
6754
|
-
_$setProp(_el
|
|
6755
|
-
_$insert(_el
|
|
6756
|
-
_$
|
|
6757
|
-
|
|
6906
|
+
},get children(){var _el$2=_$createElement("text"),_el$3=_$createTextNode(` Navigator Todo needs a separate OpenCode 2 server plugin. See the README setup steps and restart OpenCode.`)
|
|
6907
|
+
_$insertNode(_el$2,_el$3)
|
|
6908
|
+
_$setProp(_el$2,"wrapMode","word")
|
|
6909
|
+
_$insert(_el$2,()=>icons.icon("info"),_el$3)
|
|
6910
|
+
_$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.textMuted,_$p))
|
|
6911
|
+
return _el$2
|
|
6912
|
+
}}),null)
|
|
6758
6913
|
return _el$
|
|
6759
6914
|
})()
|
|
6915
|
+
},children:(message)=>(()=>{var _el$4=_$createElement("text"),_el$5=_$createTextNode(` `)
|
|
6916
|
+
_$insertNode(_el$4,_el$5)
|
|
6917
|
+
_$setProp(_el$4,"wrapMode","word")
|
|
6918
|
+
_$insert(_el$4,()=>icons.icon("info"),_el$5)
|
|
6919
|
+
_$insert(_el$4,message,null)
|
|
6920
|
+
_$effect((_$p)=>_$setProp(_el$4,"fg",props.api.theme.current.textMuted,_$p))
|
|
6921
|
+
return _el$4
|
|
6922
|
+
})()
|
|
6760
6923
|
})
|
|
6761
6924
|
}})
|
|
6762
6925
|
}
|
|
@@ -6868,7 +7031,7 @@ _$setProp(_el$2,"flexDirection","row")
|
|
|
6868
7031
|
_$setProp(_el$2,"justifyContent","space-between")
|
|
6869
7032
|
_$setProp(_el$2,"gap",1)
|
|
6870
7033
|
_$setProp(_el$3,"flexGrow",1)
|
|
6871
|
-
_$insert(_el$3,_$createComponent(
|
|
7034
|
+
_$insert(_el$3,_$createComponent(Show24,{get when(){return props.preferences.showSessionTitle()
|
|
6872
7035
|
},get children(){var _el$4=_$createElement("text"),_el$5=_$createElement("b")
|
|
6873
7036
|
_$insertNode(_el$4,_el$5)
|
|
6874
7037
|
_$setProp(_el$4,"wrapMode","word")
|
|
@@ -6876,7 +7039,7 @@ _$insert(_el$5,()=>props.title)
|
|
|
6876
7039
|
_$effect((_$p)=>_$setProp(_el$4,"fg",theme().text,_$p))
|
|
6877
7040
|
return _el$4
|
|
6878
7041
|
}}),null)
|
|
6879
|
-
_$insert(_el$3,_$createComponent(
|
|
7042
|
+
_$insert(_el$3,_$createComponent(Show24,{get when(){return _$memo(()=>!!props.preferences.showSessionDate())()&&created()
|
|
6880
7043
|
},children:(value)=>(()=>{var _el$6=_$createElement("text")
|
|
6881
7044
|
_$insert(_el$6,value)
|
|
6882
7045
|
_$effect((_$p)=>_$setProp(_el$6,"fg",theme().textMuted,_$p))
|
|
@@ -7007,7 +7170,7 @@ return false
|
|
|
7007
7170
|
}
|
|
7008
7171
|
function enabled(value){return typeof value==="function"?value():value!==false
|
|
7009
7172
|
}
|
|
7010
|
-
function createV2Keymap(context){const [revision,setRevision]=
|
|
7173
|
+
function createV2Keymap(context){const [revision,setRevision]=createSignal29(0)
|
|
7011
7174
|
const layers=new Map
|
|
7012
7175
|
let sequence=0
|
|
7013
7176
|
function layerActive(layer){const mode=layer.mode??"base"
|
|
@@ -7191,8 +7354,8 @@ context.ui.router.navigate({type:"plugin",name,data:params})
|
|
|
7191
7354
|
},attention:context.attention,lifecycle:{signal:controller.signal,onDispose}}
|
|
7192
7355
|
api.slots=createV2Slots(context,keymap,(dispose)=>{onDispose(dispose)
|
|
7193
7356
|
})
|
|
7194
|
-
setHostCapabilities(api,{todo:true,lsp:false,titleVisibility:false
|
|
7195
|
-
}
|
|
7357
|
+
setHostCapabilities(api,{todo:true,lsp:false,titleVisibility:false
|
|
7358
|
+
})
|
|
7196
7359
|
return{api,async dispose(){controller.abort()
|
|
7197
7360
|
for(let index=disposers.length-1;index>=0; index--)
|
|
7198
7361
|
await disposers[index]()
|
|
@@ -7264,9 +7427,9 @@ if(item.source.target.startsWith("."))
|
|
|
7264
7427
|
throw new Error("Unrecognized local Navigator source")
|
|
7265
7428
|
await context.client.plugin.update({location:response.location,targets:[item.source.target]})
|
|
7266
7429
|
}}}
|
|
7267
|
-
async function setupNavigator(api,options,readProject){const config=pluginConfig(undefined)
|
|
7430
|
+
async function setupNavigator(api,options,readProject,managedTodo){const config=pluginConfig(undefined)
|
|
7268
7431
|
const configured=await loadConfiguredDefaults(api,options,readProject)
|
|
7269
|
-
const todo=createTodoController(api)
|
|
7432
|
+
const todo=managedTodo??createTodoController(api)
|
|
7270
7433
|
const subagents=createSubagentController(api)
|
|
7271
7434
|
const skills=createSkillController(api)
|
|
7272
7435
|
const preferences=createPreferencesController(api,config,createPreferencesStore(api.state.path.state),configured)
|
|
@@ -7293,7 +7456,7 @@ api.slots.register({order:100,slots:{app(){return _$createComponent(IconProvider
|
|
|
7293
7456
|
},interaction,skills,subagents,mcp
|
|
7294
7457
|
}),_$createComponent(FirstRunWizardPersistence,{api,preferences
|
|
7295
7458
|
}),_$createComponent(StartupSessionBinding,{api,controller:startup
|
|
7296
|
-
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.
|
|
7459
|
+
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.18.1"
|
|
7297
7460
|
}),_$createComponent(McpPersistence,{api,controller:mcp
|
|
7298
7461
|
})]
|
|
7299
7462
|
}})
|
|
@@ -7323,33 +7486,34 @@ throw result.error
|
|
|
7323
7486
|
}
|
|
7324
7487
|
return result.data?.type==="text"?result.data.content:undefined
|
|
7325
7488
|
})
|
|
7326
|
-
const versionStatus=createVersionStatus(api,"0.
|
|
7327
|
-
const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.
|
|
7489
|
+
const versionStatus=createVersionStatus(api,"0.18.1")
|
|
7490
|
+
const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.18.1"))
|
|
7328
7491
|
api.slots.register({order:90,slots:{sidebar_footer(_context,props){return _$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7329
7492
|
},get multilineCorners(){return preferences.cornerFont
|
|
7330
7493
|
},get children(){return _$createComponent(VersionFooter,{api,get sessionID(){return props.session_id
|
|
7331
|
-
},navigatorVersion:"0.
|
|
7494
|
+
},navigatorVersion:"0.18.1",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7332
7495
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7333
7496
|
}})
|
|
7334
7497
|
}})
|
|
7335
7498
|
}}})
|
|
7336
7499
|
}
|
|
7337
7500
|
var setupOpenCodeV2=async (context)=>{const adapter=createOpenCodeV2Api(context)
|
|
7501
|
+
const todo=createNavigatorTodoController(context,adapter.api)
|
|
7338
7502
|
const{mcp,preferences
|
|
7339
7503
|
}=await setupNavigator(adapter.api,context.options,async ()=>{if(!context.client.file?.read)
|
|
7340
7504
|
return
|
|
7341
7505
|
return new TextDecoder().decode(await context.client.file.read({location:context.location,path:".opencode/navigator.json"
|
|
7342
7506
|
}))
|
|
7343
|
-
})
|
|
7344
|
-
const versionStatus=createVersionStatus(adapter.api,"0.
|
|
7345
|
-
const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.
|
|
7507
|
+
},todo)
|
|
7508
|
+
const versionStatus=createVersionStatus(adapter.api,"0.18.1")
|
|
7509
|
+
const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.18.1"))
|
|
7346
7510
|
const disposeFooter=context.ui.slot({append:"sidebar.footer",render:()=>_$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7347
7511
|
},get multilineCorners(){return preferences.cornerFont
|
|
7348
7512
|
},get children(){var _el$=_$createElement("box")
|
|
7349
7513
|
_$setProp(_el$,"flexDirection","row")
|
|
7350
7514
|
_$setProp(_el$,"justifyContent","space-between")
|
|
7351
7515
|
_$insert(_el$,_$createComponent(VersionSummary,{get api(){return adapter.api
|
|
7352
|
-
},navigatorVersion:"0.
|
|
7516
|
+
},navigatorVersion:"0.18.1",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7353
7517
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7354
7518
|
}}),null)
|
|
7355
7519
|
_$insert(_el$,_$createComponent(SettingsFooterButton,{get api(){return adapter.api
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-navigator",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.1",
|
|
5
5
|
"description": "Search, navigate, and manage OpenCode sessions from the TUI",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.4.2",
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
],
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
|
+
"server.js",
|
|
31
|
+
"rpc.js",
|
|
30
32
|
"assets",
|
|
31
33
|
"scripts/install-font.mjs",
|
|
32
34
|
"scripts/update-local-snapshot.mjs",
|
|
@@ -40,6 +42,12 @@
|
|
|
40
42
|
"exports": {
|
|
41
43
|
"./tui": {
|
|
42
44
|
"import": "./dist/tui.js"
|
|
45
|
+
},
|
|
46
|
+
"./server": {
|
|
47
|
+
"import": "./dist/server.js"
|
|
48
|
+
},
|
|
49
|
+
"./rpc": {
|
|
50
|
+
"import": "./dist/rpc.js"
|
|
43
51
|
}
|
|
44
52
|
},
|
|
45
53
|
"publishConfig": {
|
|
@@ -94,9 +102,9 @@
|
|
|
94
102
|
}
|
|
95
103
|
},
|
|
96
104
|
"devDependencies": {
|
|
97
|
-
"@opencode-ai/plugin": "1.18.
|
|
98
|
-
"@opencode-ai/sdk": "1.18.
|
|
99
|
-
"@opencode/plugin": "2.0.
|
|
105
|
+
"@opencode-ai/plugin": "1.18.34",
|
|
106
|
+
"@opencode-ai/sdk": "1.18.34",
|
|
107
|
+
"@opencode/plugin": "2.0.21",
|
|
100
108
|
"@opentui/core": "0.5.12",
|
|
101
109
|
"@opentui/keymap": "0.5.12",
|
|
102
110
|
"@opentui/solid": "0.5.12",
|
package/rpc.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NavigatorTodoRpc } from './dist/rpc.js'
|
package/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './dist/server.js'
|