opencode-navigator 0.18.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +26 -6
- 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 +457 -425
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.19.0] - 2026-10-02
|
|
6
|
+
|
|
7
|
+
- Connect or disconnect all eligible MCP servers in a group from its heading, including filtered-out items, with keyboard access and failed-only retry.
|
|
8
|
+
- Organize Skills into user-wide groups by source location, with Favorites first and group names searchable across the full catalog.
|
|
9
|
+
- Reload saved Navigator settings from disk in another running OpenCode session without restarting it.
|
|
10
|
+
|
|
11
|
+
## [0.18.2] - 2026-10-02
|
|
12
|
+
|
|
13
|
+
- 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.
|
|
14
|
+
|
|
5
15
|
## [0.18.1] - 2026-10-01
|
|
6
16
|
|
|
7
17
|
- 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.
|
|
@@ -41,6 +51,8 @@
|
|
|
41
51
|
|
|
42
52
|
Earlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).
|
|
43
53
|
|
|
54
|
+
[0.19.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.2...v0.19.0
|
|
55
|
+
[0.18.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.1...v0.18.2
|
|
44
56
|
[0.18.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.18.0...v0.18.1
|
|
45
57
|
[0.18.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.3...v0.18.0
|
|
46
58
|
[0.17.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.17.2...v0.17.3
|
package/README.md
CHANGED
|
@@ -14,8 +14,8 @@ 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
|
|
18
|
-
- Configurable host quick actions, including
|
|
17
|
+
- Compact, searchable workspace skill list with user-wide favorites and groups, recent skills, source details, and click-to-confirm slash commands
|
|
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
|
|
21
21
|
- Click any MCP row to connect or disconnect it
|
|
@@ -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
|
|
|
@@ -316,8 +329,10 @@ On the Quick Actions row, click `Actions` or press `A` to choose individual
|
|
|
316
329
|
actions and their order. Enter toggles visibility; Left/Right or Shift+Up/Down
|
|
317
330
|
reorders the selected action. Changes save in the selected Global or Current
|
|
318
331
|
worktree scope. Escape returns to the Quick Actions row in Sections. Navigator
|
|
319
|
-
keeps an explicit allowlist of argument-free host commands
|
|
320
|
-
|
|
332
|
+
keeps an explicit allowlist of argument-free host commands. On OpenCode 1.x,
|
|
333
|
+
`permission.mode` toggles auto-approve directly. On OpenCode 2.x, the same
|
|
334
|
+
Quick Action opens the host Settings dialog, where **Session → Permissions**
|
|
335
|
+
switches between `prompt` and `auto accept`. Bookmarks are user-wide and move
|
|
321
336
|
selected actions to the front in their configured order in both the sidebar and
|
|
322
337
|
Search Everything. Usage never changes the order. Visibility remains independent,
|
|
323
338
|
so any action, including a bookmarked one, can be hidden from the sidebar while it
|
|
@@ -448,8 +463,13 @@ the terminal clipboard. **Import portable settings…** accepts pasted JSON and
|
|
|
448
463
|
opens a preview before writing. Unknown future fields and section IDs are listed
|
|
449
464
|
as skipped; malformed versions or invalid known values are rejected. Apply
|
|
450
465
|
replaces only the supplied layout and MCP blocks in the still-selected scope in
|
|
451
|
-
one atomic preferences update. Paths, shortcuts, favorites, history, trust choices,
|
|
466
|
+
one atomic preferences update. Paths, Skill group assignments, shortcuts, favorites, history, trust choices,
|
|
452
467
|
and other private preferences are never imported or exported.
|
|
468
|
+
**Reload settings from file** reads Navigator's saved private preferences on
|
|
469
|
+
demand. It picks up layout defaults, behavior, favorites, groups, and presets
|
|
470
|
+
saved in another OpenCode session without restarting; temporary layout edits in
|
|
471
|
+
the receiving session are cleared so they cannot hide the reloaded settings.
|
|
472
|
+
Save a session's layout as the default before reloading it elsewhere.
|
|
453
473
|
|
|
454
474
|
## Keyboard controls
|
|
455
475
|
|
|
@@ -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
|
+
}
|