opencode-navigator 0.18.2 → 0.19.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 +12 -0
- package/README.md +30 -3
- package/dist/chunk-r37n7w97.js +24 -0
- package/dist/mcp-groups.js +25 -0
- package/dist/quick-actions-settings.js +162 -0
- package/dist/skill-groups.js +42 -0
- package/dist/tui.js +524 -441
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.19.1] - 2026-10-02
|
|
6
|
+
|
|
7
|
+
- Remember the OpenCode 1.x auto-approve mode as a user-wide default for new sessions, including changes made through the host's permission toggle.
|
|
8
|
+
|
|
9
|
+
## [0.19.0] - 2026-10-02
|
|
10
|
+
|
|
11
|
+
- Connect or disconnect all eligible MCP servers in a group from its heading, including filtered-out items, with keyboard access and failed-only retry.
|
|
12
|
+
- Organize Skills into user-wide groups by source location, with Favorites first and group names searchable across the full catalog.
|
|
13
|
+
- Reload saved Navigator settings from disk in another running OpenCode session without restarting it.
|
|
14
|
+
|
|
5
15
|
## [0.18.2] - 2026-10-02
|
|
6
16
|
|
|
7
17
|
- Open the host Settings dialog from the OpenCode 2.x Permissions Quick Action, where the user can change between `prompt` and `auto accept`; keep the direct auto-approve toggle on OpenCode 1.x.
|
|
@@ -45,6 +55,8 @@
|
|
|
45
55
|
|
|
46
56
|
Earlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).
|
|
47
57
|
|
|
58
|
+
[0.19.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.19.0...v0.19.1
|
|
59
|
+
[0.19.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.2...v0.19.0
|
|
48
60
|
[0.18.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.1...v0.18.2
|
|
49
61
|
[0.18.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.0...v0.18.1
|
|
50
62
|
[0.18.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.3...v0.18.0
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ See the [changelog](CHANGELOG.md) for release-by-release changes.
|
|
|
14
14
|
- First-run setup guide with interactive section settings
|
|
15
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
|
-
- Compact, searchable workspace skill list with user-wide favorites, recent skills, source details, and click-to-confirm slash commands
|
|
17
|
+
- Compact, searchable workspace skill list with user-wide favorites and groups, recent skills, source details, and click-to-confirm slash commands
|
|
18
18
|
- Configurable host quick actions, including OpenCode 1.x's auto-approve toggle and OpenCode 2.x's Permissions settings, with user-wide bookmarks and availability reasons
|
|
19
19
|
- Live LSP connection status with error-first sorting and badges that reveal server names in place
|
|
20
20
|
- Searchable MCP section with live radio-style connection controls
|
|
@@ -85,11 +85,24 @@ muted section dividers share the same narrow sidebar:
|
|
|
85
85
|
MCP groups are managed from **Settings → Sections → MCP → Groups**. Favorites
|
|
86
86
|
remain in a leading bucket; custom groups and their servers sort alphabetically.
|
|
87
87
|
Assignments can select an existing group or open an input to create a new one.
|
|
88
|
+
Click a group heading (including Favorites or Ungrouped), or focus it and press
|
|
89
|
+
`Enter`, to connect its remaining eligible servers. Once none need connecting,
|
|
90
|
+
the same control disconnects its connected servers. This affects the full group
|
|
91
|
+
even when a filter or item limit hides some rows; failed operations retain the
|
|
92
|
+
usual retry control.
|
|
88
93
|
|
|
89
94
|

|
|
90
95
|
|
|
91
96
|

|
|
92
97
|
|
|
98
|
+
Manage Skill groups from **Settings → Sections → Skills → Groups**. Favorites
|
|
99
|
+
stay first, named groups sort alphabetically, and Ungrouped stays last. Groups
|
|
100
|
+
belong to each Skill's exact source path, so assignments survive when a Skill
|
|
101
|
+
is absent from the current workspace. Filters and Search Everything also match
|
|
102
|
+
group names; choosing a group heading never runs its Skills.
|
|
103
|
+
|
|
104
|
+

|
|
105
|
+
|
|
93
106
|
Search Everything preserves one query across Skills, Subagents, MCP, and Actions:
|
|
94
107
|
|
|
95
108
|

|
|
@@ -124,7 +137,7 @@ the uninstalled-font result remains visible rather than being documented only in
|
|
|
124
137
|
|
|
125
138
|

|
|
126
139
|
|
|
127
|
-
The [complete
|
|
140
|
+
The [complete 38-state screenshot gallery](screenshots/README.md) shows every
|
|
128
141
|
Todo and Subagent filter, sidebar section, Search and Settings tab, preset menu
|
|
129
142
|
and preview, confirmation, keyboard-help, setup, and icon-fallback state.
|
|
130
143
|
|
|
@@ -325,6 +338,15 @@ Search Everything. Usage never changes the order. Visibility remains independent
|
|
|
325
338
|
so any action, including a bookmarked one, can be hidden from the sidebar while it
|
|
326
339
|
remains searchable. Unavailable actions stay visible with a route- or host-specific reason.
|
|
327
340
|
|
|
341
|
+
In OpenCode 1.x, Navigator saves changes to the auto-approve mode as a user-wide
|
|
342
|
+
default, including changes made through OpenCode's own command palette. Set the
|
|
343
|
+
default under **Navigator Settings → Behavior → Default auto-approve permissions**;
|
|
344
|
+
new sessions restore it. Until you set a Navigator default, an explicit OpenCode
|
|
345
|
+
startup mode is respected. OpenCode 2.x owns this setting: use the host Settings
|
|
346
|
+
dialog for the current session and `session.permissions` in the user-wide
|
|
347
|
+
`cli.json` (`"prompt"` or `"autoaccept"`) for its startup default. Restart
|
|
348
|
+
OpenCode after changing `cli.json`.
|
|
349
|
+
|
|
328
350
|
## Configuration sources
|
|
329
351
|
|
|
330
352
|
Navigator validates and deep-merges three simultaneous sources in this order:
|
|
@@ -450,8 +472,13 @@ the terminal clipboard. **Import portable settings…** accepts pasted JSON and
|
|
|
450
472
|
opens a preview before writing. Unknown future fields and section IDs are listed
|
|
451
473
|
as skipped; malformed versions or invalid known values are rejected. Apply
|
|
452
474
|
replaces only the supplied layout and MCP blocks in the still-selected scope in
|
|
453
|
-
one atomic preferences update. Paths, shortcuts, favorites, history, trust choices,
|
|
475
|
+
one atomic preferences update. Paths, Skill group assignments, shortcuts, favorites, history, trust choices,
|
|
454
476
|
and other private preferences are never imported or exported.
|
|
477
|
+
**Reload settings from file** reads Navigator's saved private preferences on
|
|
478
|
+
demand. It picks up layout defaults, behavior, favorites, groups, and presets
|
|
479
|
+
saved in another OpenCode session without restarting; temporary layout edits in
|
|
480
|
+
the receiving session are cleared so they cannot hide the reloaded settings.
|
|
481
|
+
Save a session's layout as the default before reloading it elsewhere.
|
|
455
482
|
|
|
456
483
|
## Keyboard controls
|
|
457
484
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {PresetMenu} from "./tui.js"
|
|
2
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
3
|
+
import {useDialogs} from "./tui.js"
|
|
4
|
+
function GroupAssignmentDialog(props){const dialogs=useDialogs(props.api)
|
|
5
|
+
const options=()=>[...props.groups().map((group)=>({title:group,value:`:${group}`,description:group===props.assigned()?"Current":"Existing group"
|
|
6
|
+
})),{title:"Create new group",value:"+",description:"Type a name"
|
|
7
|
+
},{title:"Ungrouped",value:":",description:props.assigned()?"Remove assignment":"No group"
|
|
8
|
+
}]
|
|
9
|
+
return _$createComponent(PresetMenu,{get api(){return props.api
|
|
10
|
+
},get title(){return props.title
|
|
11
|
+
},get options(){return options()
|
|
12
|
+
},onSelect:(option)=>{if(option.value!=="+"){props.onAssign(option.value.slice(1)||undefined)
|
|
13
|
+
dialogs.back()
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
dialogs.prompt({title:props.title,value:"",onConfirm(value){if(!value.trim())
|
|
17
|
+
throw new Error("Group name is required")
|
|
18
|
+
props.onAssign(value)
|
|
19
|
+
dialogs.back()
|
|
20
|
+
dialogs.back()
|
|
21
|
+
}})
|
|
22
|
+
}})
|
|
23
|
+
}
|
|
24
|
+
export{PresetMenu,GroupAssignmentDialog}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {PresetMenu,GroupAssignmentDialog
|
|
2
|
+
} from "./chunk-r37n7w97.js";
|
|
3
|
+
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
4
|
+
import {useDialogs} from "./tui.js"
|
|
5
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
6
|
+
function McpGroupAssignmentDialog(props){return _$createComponent(GroupAssignmentDialog,{get api(){return props.api
|
|
7
|
+
},get title(){return `Group for ${props.server}`
|
|
8
|
+
},assigned:()=>props.preferences.mcpServerGroups?.()[props.server],groups:()=>[...new Set(Object.values(props.preferences.mcpServerGroups?.()??{}))].sort((a,b)=>a.localeCompare(b)),onAssign:(group)=>props.preferences.setMcpServerGroup?.(props.server,group)
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
function McpGroupsDialog(props){const dialogs=useDialogs(props.api)
|
|
12
|
+
const options=()=>{const live=new Set(props.mcp.list(props.mcp.target()).map((item)=>item.name))
|
|
13
|
+
return [...new Set([...live,...Object.keys(props.preferences.mcpServerGroups?.()??{})])].sort((a,b)=>a.localeCompare(b)).map((name)=>({title:name,value:name,description:[props.preferences.mcpServerGroups?.()[name]??"Ungrouped",!live.has(name)&&"not in workspace"].filter(Boolean).join(" \xB7 ")
|
|
14
|
+
}))
|
|
15
|
+
}
|
|
16
|
+
return _$createComponent2(PresetMenu,{get api(){return props.api
|
|
17
|
+
},title:"MCP groups \xB7 user-wide",get options(){return options()
|
|
18
|
+
},onSelect:(option)=>dialogs.open(()=>_$createComponent2(McpGroupAssignmentDialog,{get api(){return props.api
|
|
19
|
+
},get preferences(){return props.preferences
|
|
20
|
+
},get server(){return option.value
|
|
21
|
+
}}))
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
export{McpGroupsDialog
|
|
25
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
2
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
3
|
+
import {use as _$use} from "@opentui/solid"
|
|
4
|
+
import {effect as _$effect} from "@opentui/solid"
|
|
5
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
6
|
+
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
7
|
+
import {insert as _$insert} from "@opentui/solid"
|
|
8
|
+
import {setProp as _$setProp} from "@opentui/solid"
|
|
9
|
+
import {createElement as _$createElement} from "@opentui/solid"
|
|
10
|
+
import {TextAttributes} from "@opentui/core"
|
|
11
|
+
import {useTerminalDimensions} from "@opentui/solid"
|
|
12
|
+
import {For,createEffect,createMemo,onCleanup as onCleanup2} from "solid-js"
|
|
13
|
+
import {createSignal,onCleanup} from "solid-js"
|
|
14
|
+
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"];
|
|
15
|
+
var PLUGIN_ID="opencode-navigator"
|
|
16
|
+
var TOGGLE_COMMAND=`${PLUGIN_ID}.toggle`
|
|
17
|
+
var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
|
|
18
|
+
var SEARCH_COMMAND=`${PLUGIN_ID}.search`;
|
|
19
|
+
var QUICK_ACTION_METADATA=[["\uEA73","Rename"],["\uEA82","Timeline"],["\uEBCC","Copy transcript"],["\uEBAC","Export"],["\uEAF5","Compact"],["\uEBEB","Switch session"],["\uEA60","New session"],["\uEB9E","Fork session"],["\uEBCC","Copy last response"],["\uEAA1","First message"],["\uEA9A","Last message"],["\uEA82","Last user message"],["\uEA9A","Next message"],["\uEAA1","Previous message"],["\uEBB3","Auto-approve permissions"]]
|
|
20
|
+
var QUICK_ACTIONS=QUICK_ACTION_IDS.map((command,index)=>({command,icon:QUICK_ACTION_METADATA[index][0],label:QUICK_ACTION_METADATA[index][1]
|
|
21
|
+
}))
|
|
22
|
+
function quickActionLabel(api,action){if(action.command!=="permission.mode")
|
|
23
|
+
return action.label
|
|
24
|
+
const command=api.keymap.getCommands?.({visibility:"registered"}).find((candidate)=>candidate.name===action.command)
|
|
25
|
+
return typeof command?.title==="string"?command.title:action.label
|
|
26
|
+
}
|
|
27
|
+
import {DialogSurface,SelectionBox,useDialogScroll,useDialogState,useDialogs,useIcons} from "./tui.js"
|
|
28
|
+
function QuickActionsDialog(props){const order=props.preferences.selectedQuickActionOrder
|
|
29
|
+
const dialogs=useDialogs(props.api)
|
|
30
|
+
const scroll=useDialogScroll()
|
|
31
|
+
const [selected,setSelected]=useDialogState("selection",order()[0])
|
|
32
|
+
const actions=createMemo(()=>order().map((id)=>({...QUICK_ACTIONS.find((action)=>action.command===id)
|
|
33
|
+
})))
|
|
34
|
+
const theme=()=>props.api.theme.current
|
|
35
|
+
const icons=useIcons()
|
|
36
|
+
const dimensions=useTerminalDimensions()
|
|
37
|
+
let body
|
|
38
|
+
function move(offset){const index=order().indexOf(selected())
|
|
39
|
+
setSelected(order()[(index + offset + order().length)%order().length])
|
|
40
|
+
}
|
|
41
|
+
const prefix=`${PLUGIN_ID}.quick-actions-settings`
|
|
42
|
+
createEffect(()=>{order()
|
|
43
|
+
const id=selected()
|
|
44
|
+
queueMicrotask(()=>{if(body&&!body.isDestroyed)
|
|
45
|
+
body.scrollChildIntoView(`${prefix}.${id}`)
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,commands:[{name:`${prefix}.previous`,run:()=>move(-1)
|
|
49
|
+
},{name:`${prefix}.next`,run:()=>move(1)
|
|
50
|
+
},{name:`${prefix}.toggle`,run:()=>props.preferences.toggleQuickAction(selected())
|
|
51
|
+
},{name:`${prefix}.up`,run:()=>props.preferences.moveQuickAction(selected(),-1)
|
|
52
|
+
},{name:`${prefix}.down`,run:()=>props.preferences.moveQuickAction(selected(),1)
|
|
53
|
+
},{name:`${prefix}.back`,run:dialogs.back
|
|
54
|
+
}],bindings:[{key:"up",cmd:`${prefix}.previous`
|
|
55
|
+
},{key:"down",cmd:`${prefix}.next`
|
|
56
|
+
},{key:"return",cmd:`${prefix}.toggle`
|
|
57
|
+
},{key:"space",cmd:`${prefix}.toggle`
|
|
58
|
+
},{key:"left",cmd:`${prefix}.up`
|
|
59
|
+
},{key:"right",cmd:`${prefix}.down`
|
|
60
|
+
},{key:"shift+up",cmd:`${prefix}.up`
|
|
61
|
+
},{key:"shift+down",cmd:`${prefix}.down`
|
|
62
|
+
},{key:"escape",cmd:`${prefix}.back`
|
|
63
|
+
}]
|
|
64
|
+
})
|
|
65
|
+
onCleanup2(unregister)
|
|
66
|
+
return _$createComponent(DialogSurface,{get api(){return props.api
|
|
67
|
+
},id:prefix,lift:true,get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` Quick actions`),_el$4=_$createElement("text"),_el$5=_$createTextNode(` Back (`),_el$6=_$createTextNode(`)`)
|
|
68
|
+
_$insertNode(_el$,_el$2)
|
|
69
|
+
_$insertNode(_el$,_el$4)
|
|
70
|
+
_$setProp(_el$,"flexDirection","row")
|
|
71
|
+
_$setProp(_el$,"justifyContent","space-between")
|
|
72
|
+
_$insertNode(_el$2,_el$3)
|
|
73
|
+
_$insert(_el$2,()=>icons.icon("actions"),_el$3)
|
|
74
|
+
_$insertNode(_el$4,_el$5)
|
|
75
|
+
_$insertNode(_el$4,_el$6)
|
|
76
|
+
_$setProp(_el$4,"onMouseUp",(event)=>{event.stopPropagation()
|
|
77
|
+
dialogs.back()
|
|
78
|
+
})
|
|
79
|
+
_$insert(_el$4,()=>icons.icon("left"),_el$5)
|
|
80
|
+
_$insert(_el$4,()=>icons.key("esc"),_el$6)
|
|
81
|
+
_$effect((_p$)=>{var _v$=TextAttributes.BOLD,_v$2=theme().text,_v$3=theme().textMuted
|
|
82
|
+
_v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"attributes",_v$,_p$.e))
|
|
83
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp(_el$2,"fg",_v$2,_p$.t))
|
|
84
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp(_el$4,"fg",_v$3,_p$.a))
|
|
85
|
+
return _p$
|
|
86
|
+
},{e:undefined,t:undefined,a:undefined
|
|
87
|
+
})
|
|
88
|
+
return _el$
|
|
89
|
+
})(),(()=>{var _el$7=_$createElement("text"),_el$8=_$createTextNode(`Scope: `),_el$9=_$createTextNode(`. Changes save immediately.`)
|
|
90
|
+
_$insertNode(_el$7,_el$8)
|
|
91
|
+
_$insertNode(_el$7,_el$9)
|
|
92
|
+
_$setProp(_el$7,"wrapMode","word")
|
|
93
|
+
_$insert(_el$7,()=>props.preferences.preferenceScopeLabel(),_el$9)
|
|
94
|
+
_$effect((_$p)=>_$setProp(_el$7,"fg",theme().textMuted,_$p))
|
|
95
|
+
return _el$7
|
|
96
|
+
})(),(()=>{var _el$0=_$createElement("scrollbox"),_el$1=_$createElement("box")
|
|
97
|
+
_$insertNode(_el$0,_el$1)
|
|
98
|
+
_$use((node)=>{body=node
|
|
99
|
+
scroll.ref(node)
|
|
100
|
+
},_el$0)
|
|
101
|
+
_$setProp(_el$0,"scrollX",false)
|
|
102
|
+
_$setProp(_el$1,"gap",1)
|
|
103
|
+
_$insert(_el$1,_$createComponent(For,{get each(){return actions()
|
|
104
|
+
},children:(action,index)=>_$createComponent(SelectionBox,{get id(){return `${prefix}.${action.command}`
|
|
105
|
+
},flexDirection:"row",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return _$memo(()=>selected()===action.command)()?theme().backgroundElement:undefined
|
|
106
|
+
},onMouseOver:()=>setSelected(action.command),onMouseDown:()=>{setSelected(action.command)
|
|
107
|
+
props.preferences.toggleQuickAction(action.command)
|
|
108
|
+
},get children(){return [(()=>{var _el$16=_$createElement("text"),_el$17=_$createTextNode(` `),_el$18=_$createTextNode(`. `),_el$19=_$createTextNode(` `)
|
|
109
|
+
_$insertNode(_el$16,_el$17)
|
|
110
|
+
_$insertNode(_el$16,_el$18)
|
|
111
|
+
_$insertNode(_el$16,_el$19)
|
|
112
|
+
_$setProp(_el$16,"flexGrow",1)
|
|
113
|
+
_$insert(_el$16,()=>icons.icon(props.preferences.selectedQuickActionVisible(action.command)?"checked":"unchecked"),_el$17)
|
|
114
|
+
_$insert(_el$16,()=>index() + 1,_el$18)
|
|
115
|
+
_$insert(_el$16,()=>icons.action(action.command),_el$19)
|
|
116
|
+
_$insert(_el$16,()=>quickActionLabel(props.api,action),null)
|
|
117
|
+
_$effect((_$p)=>_$setProp(_el$16,"fg",theme().text,_$p))
|
|
118
|
+
return _el$16
|
|
119
|
+
})(),(()=>{var _el$20=_$createElement("text")
|
|
120
|
+
_$setProp(_el$20,"onMouseDown",(event)=>{event.stopPropagation()
|
|
121
|
+
setSelected(action.command)
|
|
122
|
+
props.preferences.moveQuickAction(action.command,-1)
|
|
123
|
+
})
|
|
124
|
+
_$insert(_el$20,()=>icons.icon("up"))
|
|
125
|
+
_$effect((_$p)=>_$setProp(_el$20,"fg",theme().accent,_$p))
|
|
126
|
+
return _el$20
|
|
127
|
+
})(),(()=>{var _el$21=_$createElement("text")
|
|
128
|
+
_$setProp(_el$21,"onMouseDown",(event)=>{event.stopPropagation()
|
|
129
|
+
setSelected(action.command)
|
|
130
|
+
props.preferences.moveQuickAction(action.command,1)
|
|
131
|
+
})
|
|
132
|
+
_$insert(_el$21,()=>icons.icon("down"))
|
|
133
|
+
_$effect((_$p)=>_$setProp(_el$21,"fg",theme().accent,_$p))
|
|
134
|
+
return _el$21
|
|
135
|
+
})()]
|
|
136
|
+
}})
|
|
137
|
+
}))
|
|
138
|
+
_$effect((_p$)=>{var{restore:_v$4,save:_v$5}=scroll,_v$6=Math.min(actions().length*2-1,Math.max(3,Math.floor(dimensions().height*0.75)-8))
|
|
139
|
+
_v$4!==_p$.e&&(_p$.e=_$setProp(_el$0,"renderBefore",_v$4,_p$.e))
|
|
140
|
+
_v$5!==_p$.t&&(_p$.t=_$setProp(_el$0,"renderAfter",_v$5,_p$.t))
|
|
141
|
+
_v$6!==_p$.a&&(_p$.a=_$setProp(_el$0,"height",_v$6,_p$.a))
|
|
142
|
+
return _p$
|
|
143
|
+
},{e:undefined,t:undefined,a:undefined
|
|
144
|
+
})
|
|
145
|
+
return _el$0
|
|
146
|
+
})(),(()=>{var _el$10=_$createElement("text"),_el$11=_$createTextNode(` navigate \xB7 `),_el$12=_$createTextNode(` toggle \xB7 `),_el$13=_$createTextNode(` or `),_el$15=_$createTextNode(` reorder`)
|
|
147
|
+
_$insertNode(_el$10,_el$11)
|
|
148
|
+
_$insertNode(_el$10,_el$12)
|
|
149
|
+
_$insertNode(_el$10,_el$13)
|
|
150
|
+
_$insertNode(_el$10,_el$15)
|
|
151
|
+
_$setProp(_el$10,"wrapMode","word")
|
|
152
|
+
_$insert(_el$10,()=>icons.key("up/down"),_el$11)
|
|
153
|
+
_$insert(_el$10,()=>icons.key("enter"),_el$12)
|
|
154
|
+
_$insert(_el$10,()=>icons.key("left/right"),_el$13)
|
|
155
|
+
_$insert(_el$10,()=>icons.key("shift+up/down"),_el$15)
|
|
156
|
+
_$effect((_$p)=>_$setProp(_el$10,"fg",theme().textMuted,_$p))
|
|
157
|
+
return _el$10
|
|
158
|
+
})()]
|
|
159
|
+
}})
|
|
160
|
+
}
|
|
161
|
+
export{QuickActionsDialog
|
|
162
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {PresetMenu,GroupAssignmentDialog
|
|
2
|
+
} from "./chunk-r37n7w97.js";
|
|
3
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
4
|
+
import {useDialogs} from "./tui.js"
|
|
5
|
+
import {createEffect,createMemo,untrack} from "solid-js"
|
|
6
|
+
function createSkillGroupsModel(skills,preferences){const target=createMemo(()=>skills.target())
|
|
7
|
+
createEffect(()=>{const current=target()
|
|
8
|
+
untrack(()=>void skills.refresh(current).catch(()=>{}))
|
|
9
|
+
})
|
|
10
|
+
const options=createMemo(()=>{const live=new Map(skills.list(target()).map((skill)=>[skill.location,skill]))
|
|
11
|
+
const assigned=preferences.skillGroups?.()??{}
|
|
12
|
+
const entries=[...new Set([...live.keys(),...Object.keys(assigned)])].filter(Boolean).sort((left,right)=>{const label=(location)=>live.get(location)?.name??location.split("/").at(-2)??location
|
|
13
|
+
return label(left).localeCompare(label(right))||left.localeCompare(right)
|
|
14
|
+
}).map((location)=>({title:live.get(location)?.name??location.split("/").at(-2)??location,value:location,description:[assigned[location]??"Ungrouped",!live.has(location)&&"not in workspace",location].filter(Boolean).join(" \xB7 ")
|
|
15
|
+
}))
|
|
16
|
+
const state=skills.state(target())
|
|
17
|
+
if(state.error)
|
|
18
|
+
entries.push({title:"Retry loading skills",value:"__retry__",description:state.error.message})
|
|
19
|
+
if(entries.length===0)
|
|
20
|
+
entries.push({title:state.status==="loading"?"Loading skills\u2026":"No skills in this workspace",value:"__empty__",description:""
|
|
21
|
+
})
|
|
22
|
+
return entries
|
|
23
|
+
})
|
|
24
|
+
return{options,retry:()=>skills.refresh(target(),true)}}
|
|
25
|
+
function SkillGroupsDialog(props){const dialogs=useDialogs(props.api)
|
|
26
|
+
const model=createSkillGroupsModel(props.skills,props.preferences)
|
|
27
|
+
return _$createComponent(PresetMenu,{get api(){return props.api
|
|
28
|
+
},title:"Skill groups \xB7 user-wide",get options(){return model.options()
|
|
29
|
+
},onSelect:(option)=>{if(option.value==="__retry__"){model.retry().catch(()=>{})
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
if(option.value==="__empty__")
|
|
33
|
+
return
|
|
34
|
+
const location=option.value
|
|
35
|
+
dialogs.open(()=>_$createComponent(GroupAssignmentDialog,{get api(){return props.api
|
|
36
|
+
},get title(){return `Group for ${option.title}`
|
|
37
|
+
},assigned:()=>props.preferences.skillGroups?.()[location],groups:()=>[...new Set(Object.values(props.preferences.skillGroups?.()??{}))].sort((a,b)=>a.localeCompare(b)),onAssign:(group)=>props.preferences.setSkillGroup?.(location,group)
|
|
38
|
+
}))
|
|
39
|
+
}})
|
|
40
|
+
}
|
|
41
|
+
export{SkillGroupsDialog
|
|
42
|
+
}
|