opencode-navigator 0.21.8 → 0.23.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/dist/tui.js CHANGED
@@ -1,9 +1,9 @@
1
- import {insert as _$insert,setProp as _$setProp,createElement as _$createElement,memo as _$memo,createComponent as _$createComponent,mergeProps as _$mergeProps,effect as _$effect,createTextNode as _$createTextNode,insertNode as _$insertNode,use as _$use,spread as _$spread,useTerminalDimensions,useTerminalDimensions as useTerminalDimensions2,useTerminalDimensions as useTerminalDimensions3,useTerminalDimensions as useTerminalDimensions4,useTerminalDimensions as useTerminalDimensions5,useTerminalDimensions as useTerminalDimensions6,useTerminalDimensions as useTerminalDimensions7} from "@opentui/solid"
1
+ import {insert as _$insert,setProp as _$setProp,createElement as _$createElement,memo as _$memo,createComponent as _$createComponent,mergeProps as _$mergeProps,useRenderer,effect as _$effect,createTextNode as _$createTextNode,insertNode as _$insertNode,use as _$use,spread as _$spread,useTerminalDimensions,useTerminalDimensions as useTerminalDimensions2,useTerminalDimensions as useTerminalDimensions3,useTerminalDimensions as useTerminalDimensions4,useRenderer as useRenderer2,useTerminalDimensions as useTerminalDimensions5,useTerminalDimensions as useTerminalDimensions6,useTerminalDimensions as useTerminalDimensions7,useTerminalDimensions as useTerminalDimensions8,useTerminalDimensions as useTerminalDimensions9} from "@opentui/solid"
2
2
 
3
3
 
4
4
 
5
5
 
6
- 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,createEffect as createEffect4,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 createEffect5,createSignal as createSignal9,onCleanup as onCleanup4,createSignal as createSignal10,createSignal as createSignal11,Index,createSignal as createSignal12,onCleanup as onCleanup5,createEffect as createEffect7,onCleanup as onCleanup7,batch as batch2,createEffect as createEffect6,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 createEffect8,createSignal as createSignal15,onCleanup as onCleanup9,Show as Show4,For as For6,For as For9,createEffect as createEffect9,createMemo as createMemo5,onCleanup as onCleanup10,createEffect as createEffect10,createMemo as createMemo6,untrack as untrack2,For as For10,createEffect as createEffect11,createMemo as createMemo8,onCleanup as onCleanup11,onMount as onMount4,createMemo as createMemo7,Show as Show6,onCleanup as onCleanup12,createEffect as createEffect12,onCleanup as onCleanup13,createSignal as createSignal16,createMemo as createMemo9,createEffect as createEffect13,onCleanup as onCleanup14,onMount as onMount5,onCleanup as onCleanup15,onMount as onMount6,For as For11,createSignal as createSignal17,createSignal as createSignal18,Show as Show7,createSignal as createSignal20,createSignal as createSignal19,onCleanup as onCleanup16,For as For12,Show as Show10,createMemo as createMemo11,createComputed,createMemo as createMemo10,createSignal as createSignal21,untrack as untrack3,Show as Show8,createComputed as createComputed2,untrack as untrack4,Show as Show9,createSignal as createSignal23,createEffect as createEffect14,createSignal as createSignal22,on,createMemo as createMemo13,createSignal as createSignal26,createMemo as createMemo12,For as For13,Show as Show14,Show as Show11,Show as Show12,createSignal as createSignal24,createContext as createContext3,useContext as useContext3,Show as Show13,createSignal as createSignal25,onCleanup as onCleanup17,Show as Show20,createSignal as createSignal27,untrack as untrack5,createSignal as createSignal28,createSignal as createSignal29,createEffect as createEffect15,For as For15,Show as Show15,For as For14,Show as Show16,Show as Show17,Show as Show18,Show as Show19,For as For16,Show as Show22,createMemo as createMemo15,Show as Show21,createMemo as createMemo14,createSignal as createSignal30,createEffect as createEffect16,onCleanup as onCleanup18,For as For21,Match,Switch,createMemo as createMemo19,onCleanup as onCleanup22,For as For17,Show as Show23,createSignal as createSignal31,createEffect as createEffect17,createMemo as createMemo16,onCleanup as onCleanup19,untrack as untrack6,For as For19,Show as Show26,createEffect as createEffect18,createMemo as createMemo17,createSignal as createSignal32,onCleanup as onCleanup20,untrack as untrack7,For as For18,Show as Show25,Show as Show24,Show as Show30,createEffect as createEffect19,createMemo as createMemo18,createSignal as createSignal33,onCleanup as onCleanup21,untrack as untrack8,For as For20,Show as Show28,Show as Show27,Show as Show29,createEffect as createEffect20,createMemo as createMemo20,onCleanup as onCleanup23,untrack as untrack9,Show as Show31,createMemo as createMemo21,onCleanup as onCleanup24,createEffect as createEffect21,createMemo as createMemo22,on as on2,onCleanup as onCleanup25,createSignal as createSignal34,onCleanup as onCleanup26,onMount as onMount7} from "solid-js"
6
+ import {createSignal as createSignal2,createSignal,createEffect,onCleanup,createContext,useContext,createContext as createContext2,createSignal as createSignal3,onCleanup as onCleanup2,useContext as useContext2,createEffect as createEffect2,splitProps,untrack,splitProps as splitProps2,For,createEffect as createEffect3,onCleanup as onCleanup3,createEffect as createEffect4,Show,splitProps as splitProps3,Suspense,lazy,createSignal as createSignal4,createSignal as createSignal5,onCleanup as onCleanup4,Show as Show2,batch,createSignal as createSignal7,createSignal as createSignal6,createEffect as createEffect5,createSignal as createSignal8,onCleanup as onCleanup5,createSignal as createSignal9,createSignal as createSignal10,Suspense as Suspense2,lazy as lazy2,Index,onCleanup as onCleanup6,createSignal as createSignal11,onCleanup as onCleanup7,createEffect as createEffect7,onCleanup as onCleanup9,batch as batch2,createEffect as createEffect6,createMemo,createSignal as createSignal12,onCleanup as onCleanup8,onMount,For as For2,For as For3,Show as Show3,createMemo as createMemo2,Show as Show4,createSignal as createSignal13,onCleanup as onCleanup10,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 Show6,createEffect as createEffect8,createSignal as createSignal14,onCleanup as onCleanup11,Show as Show5,For as For6,For as For9,createEffect as createEffect9,createMemo as createMemo5,onCleanup as onCleanup12,createEffect as createEffect10,createMemo as createMemo6,untrack as untrack2,Suspense as Suspense3,lazy as lazy3,onCleanup as onCleanup13,createEffect as createEffect11,onCleanup as onCleanup14,createSignal as createSignal15,createMemo as createMemo7,createSignal as createSignal16,lazy as lazy4,Show as Show9,For as For10,Show as Show8,Show as Show7,createEffect as createEffect12,onCleanup as onCleanup15,onMount as onMount4,onCleanup as onCleanup16,onMount as onMount5,For as For11,createSignal as createSignal17,createSignal as createSignal18,Show as Show10,createSignal as createSignal20,createSignal as createSignal19,onCleanup as onCleanup17,For as For12,Show as Show13,createMemo as createMemo9,createComputed,createMemo as createMemo8,createSignal as createSignal21,untrack as untrack3,Show as Show11,createComputed as createComputed2,untrack as untrack4,Show as Show12,createSignal as createSignal23,createEffect as createEffect13,createSignal as createSignal22,on,createMemo as createMemo11,createSignal as createSignal26,createMemo as createMemo10,For as For13,Show as Show17,Show as Show14,Show as Show15,createSignal as createSignal24,createContext as createContext3,useContext as useContext3,Show as Show16,createSignal as createSignal25,onCleanup as onCleanup18,Show as Show23,createSignal as createSignal27,untrack as untrack5,createSignal as createSignal28,createSignal as createSignal29,createEffect as createEffect14,For as For15,Show as Show18,For as For14,createSignal as createSignal30,Show as Show19,Show as Show20,Show as Show21,Show as Show22,For as For16,Show as Show25,createMemo as createMemo13,Show as Show24,createMemo as createMemo12,createSignal as createSignal31,createContext as createContext4,useContext as useContext4,Show as Show26,Suspense as Suspense4,createEffect as createEffect15,onCleanup as onCleanup19,untrack as untrack6,For as For22,Match,Switch,createMemo as createMemo19,onCleanup as onCleanup25,For as For17,Show as Show27,createMemo as createMemo15,createSignal as createSignal33,createEffect as createEffect16,createMemo as createMemo14,onCleanup as onCleanup20,untrack as untrack7,createEffect as createEffect17,createSignal as createSignal32,onCleanup as onCleanup21,For as For18,Show as Show29,createSignal as createSignal34,createEffect as createEffect18,createMemo as createMemo16,onCleanup as onCleanup22,untrack as untrack8,Show as Show28,For as For20,Show as Show32,createEffect as createEffect19,createMemo as createMemo17,createSignal as createSignal35,onCleanup as onCleanup23,untrack as untrack9,For as For19,Show as Show31,Show as Show30,Show as Show36,createEffect as createEffect20,createMemo as createMemo18,createSignal as createSignal36,onCleanup as onCleanup24,untrack as untrack10,For as For21,Show as Show34,Show as Show33,Show as Show35,createEffect as createEffect21,createMemo as createMemo20,onCleanup as onCleanup26,untrack as untrack11,Show as Show37,createMemo as createMemo21,onCleanup as onCleanup27,createEffect as createEffect22,createMemo as createMemo22,on as on2,onCleanup as onCleanup28,createRoot,createSignal as createSignal37,getOwner,createSignal as createSignal38,onCleanup as onCleanup29,onMount as onMount6} from "solid-js"
7
7
  var SIDEBAR_SECTIONS=["limits","todo","subagents","skills","quick_actions","lsp","mcp"]
8
8
  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"]
9
9
  function preferencesScope(path){return path.worktree||path.directory||"global"
@@ -77,7 +77,7 @@ var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
77
77
  var SEARCH_COMMAND=`${PLUGIN_ID}.search`
78
78
  var DEFAULT_SEARCH_KEY="ctrl+shift+k";
79
79
  function pluginConfig(options){const iconStyle=options?.icon_style==="nerd"||options?.icon_style==="text"?options.icon_style:options?.lsp_icon_style
80
- return{toggleKey:typeof options?.toggle_key==="string"&&options.toggle_key.trim()?options.toggle_key.trim():"ctrl+shift+b",focusKey:typeof options?.focus_key==="string"&&options.focus_key.trim()?options.focus_key.trim():"ctrl+shift+f",searchKey:typeof options?.search_key==="string"&&options.search_key.trim()?options.search_key.trim():DEFAULT_SEARCH_KEY,persistMcp:options?.persist_mcp!==false,limitsRefreshMinutes:parseLimitsRefreshMinutes(options?.limits_refresh_minutes)??DEFAULT_LIMITS_REFRESH_MINUTES,startInChat:options?.start_in_chat===true,showSessionTitle:options?.show_session_title!==false,showSessionDate:options?.show_session_date!==false,cornerFont:options?.corner_font!==false,sections:parseSectionVisibility(options?.sections),sectionOrder:parseSectionOrder(options?.section_order)??[...SIDEBAR_SECTIONS],lspIconStyle:iconStyle==="text"?"text":"nerd",rowDensity:options?.row_density==="comfortable"?"comfortable":"compact",sectionItemLimits:parseSectionItemLimits(options?.section_item_limits),quickActionOrder:parseQuickActionOrder(options?.quick_action_order)??[...QUICK_ACTION_IDS],quickActionVisibility:parseQuickActionVisibility(options?.quick_action_visibility)
80
+ return{toggleKey:typeof options?.toggle_key==="string"&&options.toggle_key.trim()?options.toggle_key.trim():"ctrl+shift+b",focusKey:typeof options?.focus_key==="string"&&options.focus_key.trim()?options.focus_key.trim():"ctrl+shift+f",searchKey:typeof options?.search_key==="string"&&options.search_key.trim()?options.search_key.trim():DEFAULT_SEARCH_KEY,persistMcp:options?.persist_mcp!==false,limitsRefreshMinutes:parseLimitsRefreshMinutes(options?.limits_refresh_minutes)??DEFAULT_LIMITS_REFRESH_MINUTES,startInChat:options?.start_in_chat===true,showSessionTitle:options?.show_session_title!==false,showSessionDate:options?.show_session_date!==false,cornerFont:options?.corner_font!==false,sections:parseSectionVisibility(options?.sections),sectionOrder:parseSectionOrder(options?.section_order)??[...SIDEBAR_SECTIONS],lspIconStyle:iconStyle==="text"?"text":"nerd",rowDensity:options?.row_density==="comfortable"?"comfortable":"compact",toolbarOverflow:options?.toolbar_overflow==="wrap"?"wrap":"menu",sectionItemLimits:parseSectionItemLimits(options?.section_item_limits),quickActionOrder:parseQuickActionOrder(options?.quick_action_order)??[...QUICK_ACTION_IDS],quickActionVisibility:parseQuickActionVisibility(options?.quick_action_visibility)
81
81
  }}
82
82
  function currentLocation(api){const route=api.route.current
83
83
  const params="params" in route?route.params:undefined
@@ -230,7 +230,7 @@ return
230
230
  const error=status.error
231
231
  return typeof error==="string"?error:undefined
232
232
  }
233
- function createMcpController(api,persist,preferences){const [snapshots,setSnapshots]=createSignal2({})
233
+ function createMcpController(api,persist,preferences,source){const [snapshots,setSnapshots]=createSignal2({})
234
234
  const [mutationCounts,setMutationCounts]=createSignal2({})
235
235
  const [bulkStates,setBulkStates]=createSignal2({})
236
236
  const [selectedPresets,setSelectedPresets]=createSignal2({})
@@ -303,7 +303,7 @@ const failed=state.failed.filter((candidate)=>candidate!==name)
303
303
  bulkRetries.set(current.key,(bulkRetries.get(current.key)??[]).filter((candidate)=>candidate.name!==name))
304
304
  return{...values,[current.key]:{...state,status:failed.length>0?"error":"ready",failed}}})
305
305
  }
306
- function list(current=target()){return snapshots()[current.key]??api.state.mcp()
306
+ function list(current=target()){return source?source.list(current):snapshots()[current.key]??api.state.mcp()
307
307
  }
308
308
  async function refresh(current=target(),force=false){const pending=refreshing.get(current.key)
309
309
  if(pending&&!force)
@@ -311,8 +311,7 @@ return pending
311
311
  const requestState=requests.start(current.key,"refresh MCP servers",current.key in snapshots(),force)
312
312
  if(!requestState)
313
313
  return pending
314
- const request=api.client.mcp.status(current.routing,{throwOnError:true,signal:requestState.signal}).then((result)=>{const items=Object.entries(result.data??{}).map(([name,status])=>({name,status:status.status,error:statusError(status)})).sort((a,b)=>a.name.localeCompare(b.name))
315
- if(requestState.isCurrent())
314
+ const request=(source?source.refresh(current,force,requestState.signal):api.client.mcp.status(current.routing,{throwOnError:true,signal:requestState.signal}).then((result)=>Object.entries(result.data??{}).map(([name,status])=>({name,status:status.status,error:statusError(status)})).sort((a,b)=>a.name.localeCompare(b.name)))).then((items)=>{if(!source&&requestState.isCurrent())
316
315
  setSnapshots((value)=>({...value,[current.key]:items}))
317
316
  if(requestState.isCurrent())
318
317
  reconcileSelectedPreset(current,items)
@@ -684,6 +683,7 @@ return _$createComponent(DialogContext.Provider,{get value(){return props.scope
684
683
  }})
685
684
  }
686
685
 
686
+
687
687
  function useDialogs(api){const scope=useContext2(DialogContext)
688
688
  const icons=useIcons()
689
689
  if(scope?.api===api)
@@ -700,17 +700,31 @@ const state=createSignal3(initial)
700
700
  scope.frame.state.set(key,state)
701
701
  return state
702
702
  }
703
- function useDialogScroll(key="scroll"){const [position,setPosition]=useDialogState(key,0)
703
+ function useDialogScroll(key="scroll"){const renderer=useRenderer()
704
+ const [position,setPosition]=useDialogState(key,0)
704
705
  let body
705
706
  let isPending=true
706
- return{ref(node){body=node
707
- },restore(){if(!isPending||!body)
707
+ function restore(){if(!isPending||!body||body.isDestroyed)
708
+ return
709
+ if(position()>0&&body.scrollHeight===0)
708
710
  return
709
711
  isPending=false
710
712
  body.scrollTo(position())
711
- },save(){if(body&&!body.isDestroyed)
713
+ }
714
+ function save(){if(!isPending&&body&&!body.isDestroyed)
712
715
  setPosition(body.scrollTop)
713
- }}}
716
+ }
717
+ const frame=()=>{restore()
718
+ save()
719
+ }
720
+ renderer.on("frame",frame)
721
+ onCleanup2(()=>{save()
722
+ renderer.off("frame",frame)
723
+ })
724
+ return{ref(node){body=node
725
+ renderer.requestRender()
726
+ },restore,save
727
+ }}
714
728
 
715
729
 
716
730
 
@@ -724,8 +738,13 @@ setPosition(body.scrollTop)
724
738
 
725
739
 
726
740
 
727
- import {RGBA,TextAttributes,TextAttributes as TextAttributes2,TextAttributes as TextAttributes3,RGBA as RGBA2,parseColor,TextAttributes as TextAttributes6,TextAttributes as TextAttributes4,TextAttributes as TextAttributes5,TextAttributes as TextAttributes7,RGBA as RGBA3,parseColor as parseColor2,TextAttributes as TextAttributes8,TextAttributes as TextAttributes9,TextAttributes as TextAttributes12,TextAttributes as TextAttributes10,TextAttributes as TextAttributes11,TextAttributes as TextAttributes13,TextAttributes as TextAttributes14,TextAttributes as TextAttributes16,TextAttributes as TextAttributes15,TextAttributes as TextAttributes17,ScrollBoxRenderable,TextAttributes as TextAttributes18} from "@opentui/core"
741
+ import {BoxRenderable,RGBA,TextAttributes,TextAttributes as TextAttributes2,TextAttributes as TextAttributes3,RGBA as RGBA2,parseColor,TextAttributes as TextAttributes4,TextAttributes as TextAttributes5,TextAttributes as TextAttributes6,TextAttributes as TextAttributes7,RGBA as RGBA3,parseColor as parseColor2,TextAttributes as TextAttributes8,TextAttributes as TextAttributes9,TextAttributes as TextAttributes12,TextAttributes as TextAttributes10,TextAttributes as TextAttributes11,TextAttributes as TextAttributes13,TextAttributes as TextAttributes14,TextAttributes as TextAttributes16,TextAttributes as TextAttributes15,TextAttributes as TextAttributes17,ScrollBoxRenderable,TextAttributes as TextAttributes18} from "@opentui/core"
728
742
 
743
+ function selectionBackdrop(node){for(let parent=node.parent;parent; parent=parent.parent){if(parent instanceof BoxRenderable&&parent.backgroundColor.a>0)
744
+ return parent.backgroundColor
745
+ }
746
+ return RGBA.fromValues(0,0,0,1)
747
+ }
729
748
  function SelectionBox(props){const icons=useIcons()
730
749
  const [local,boxProps]=splitProps(props,["ref","iconOnly"])
731
750
  let node
@@ -743,11 +762,9 @@ const right=left + this.width-1
743
762
  const top=this.screenY
744
763
  const bottom=top + this.height-1
745
764
  const positions=this.height===1?[[left,top,"selectionLeft"],[right,top,"selectionRight"]]:[[left,top,"selectionTopLeft"],[right,top,"selectionTopRight"],[left,bottom,"selectionBottomLeft"],[right,bottom,"selectionBottomRight"]]
746
- const background=buffer.buffers.bg
765
+ const backdrop=selectionBackdrop(this)
747
766
  for(const [x,y,icon] of positions){if(x<0||y<0||x>=buffer.width||y>=buffer.height)
748
767
  continue
749
- const offset=(y*buffer.width + x)*4
750
- const backdrop=new RGBA(background.slice(offset,offset + 4))
751
768
  if(!this.backgroundColor.equals(backdrop))
752
769
  corners.push({x,y,icon,backdrop
753
770
  })
@@ -921,9 +938,11 @@ return _el$
921
938
 
922
939
 
923
940
 
941
+
924
942
  function SelectionMenu(props){const icons=useIcons()
925
943
  const dialogs=useDialogs(props.api)
926
944
  const scroll=useDialogScroll()
945
+ const dimensions=useTerminalDimensions2()
927
946
  const [active,setActive]=useDialogState("selection",0)
928
947
  const theme=()=>props.api.theme.current
929
948
  let body
@@ -946,8 +965,9 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
946
965
  },{key:"space",cmd:`${prefix}.select`
947
966
  }]
948
967
  })
949
- onCleanup2(unregister)
968
+ onCleanup3(unregister)
950
969
  return _$createComponent(DialogSurface,{get api(){return props.api
970
+ },get lift(){return props.lift
951
971
  },get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` `),_el$4=_$createElement("text")
952
972
  _$insertNode(_el$,_el$2)
953
973
  _$insertNode(_el$,_el$4)
@@ -985,9 +1005,9 @@ _$insert(_el$1,(()=>{var _c$=_$memo(()=>!!option.icon)
985
1005
  return()=>_c$()?`${icons.icon(option.icon)} `:""
986
1006
  })(),null)
987
1007
  _$insert(_el$1,()=>option.title,null)
988
- _$effect((_p$)=>{var _v$8=active()===index()?TextAttributes2.BOLD:undefined,_v$9=theme().text
989
- _v$8!==_p$.e&&(_p$.e=_$setProp(_el$1,"attributes",_v$8,_p$.e))
990
- _v$9!==_p$.t&&(_p$.t=_$setProp(_el$1,"fg",_v$9,_p$.t))
1008
+ _$effect((_p$)=>{var _v$5=active()===index()?TextAttributes2.BOLD:undefined,_v$6=theme().text
1009
+ _v$5!==_p$.e&&(_p$.e=_$setProp(_el$1,"attributes",_v$5,_p$.e))
1010
+ _v$6!==_p$.t&&(_p$.t=_$setProp(_el$1,"fg",_v$6,_p$.t))
991
1011
  return _p$
992
1012
  },{e:undefined,t:undefined
993
1013
  })
@@ -1000,13 +1020,7 @@ return _el$10
1000
1020
  })()]
1001
1021
  }})
1002
1022
  }))
1003
- _$effect((_p$)=>{var{restore:_v$5,save:_v$6}=scroll,_v$7=props.height??Math.min(props.options.length*3,15)
1004
- _v$5!==_p$.e&&(_p$.e=_$setProp(_el$5,"renderBefore",_v$5,_p$.e))
1005
- _v$6!==_p$.t&&(_p$.t=_$setProp(_el$5,"renderAfter",_v$6,_p$.t))
1006
- _v$7!==_p$.a&&(_p$.a=_$setProp(_el$5,"height",_v$7,_p$.a))
1007
- return _p$
1008
- },{e:undefined,t:undefined,a:undefined
1009
- })
1023
+ _$effect((_$p)=>_$setProp(_el$5,"height",props.adaptive?Math.min(props.height??Math.min(props.options.length*3,15),Math.max(2,Math.floor(dimensions().height*0.75)-8)):props.height??Math.min(props.options.length*3,15),_$p))
1010
1024
  return _el$5
1011
1025
  })(),(()=>{var _el$7=_$createElement("text"),_el$8=_$createTextNode(` navigate \xB7 `),_el$9=_$createTextNode(` select \xB7 `),_el$0=_$createTextNode(` close`)
1012
1026
  _$insertNode(_el$7,_el$8)
@@ -1085,6 +1099,27 @@ function subtleLineColor(background,border){const from=parseColor(background)
1085
1099
  const to=parseColor(border)
1086
1100
  return RGBA2.fromValues(from.r + (to.r-from.r)*0.45,from.g + (to.g-from.g)*0.45,from.b + (to.b-from.b)*0.45)
1087
1101
  }
1102
+
1103
+
1104
+
1105
+
1106
+ var PickerComponent=lazy(async ()=>{const path=import.meta.url.includes("/dist/tui.js")?"./icon-picker.js":"./icon-picker/icon-picker"
1107
+ const module=await import(path)
1108
+ return{default:module.IconPicker
1109
+ }})
1110
+ function IconPicker(props){return(()=>{var _el$=_$createElement("box")
1111
+ _$insert(_el$,_$createComponent(Suspense,{get children(){return _$createComponent(PickerComponent,props)
1112
+ }}))
1113
+ return _el$
1114
+ })()
1115
+ }
1116
+ var glyphs={plus:["\uEA60","+"],check:["\uEAB2","v"],circle:["\uEAEE","o"],star:["\uEA6A","*"],pin:["\uEBAB","^"],bolt:["\uEA86","!"],book:["\uEAA4","B"],search:["\uEA6D","?"],code:["\uEAC4","#"],terminal:["\uEA85",">"],gear:["\uEB51","G"],shield:["\uEBB3","S"],lock:["\uEA75","L"],unlock:["\uEB74","U"],eye:["\uEA70","E"],clock:["\uEA82","T"],refresh:["\uEAF5","R"],history:["\uEA82","H"],copy:["\uEBCC","C"],export:["\uEBAC","X"],edit:["\uEA73","/"],fork:["\uEB9E","F"],list:["\uEBEB","="],play:["\uEB2C",">"],pause:["\uEAD1","|"],stop:["\uEAD7","s"],rocket:["\uEB44","r"],bug:["\uEAAF","b"],beaker:["\uEA79","t"],wand:["\uEAB6","w"],cloud:["\uEABA","c"],server:["\uEB50","s"],folder:["\uEA83","D"],file:["\uEA7B","f"],heart:["\uEB05","h"],lightbulb:["\uEA61","i"],"arrow-up":["\uEAA1","^"],"arrow-down":["\uEA9A","v"],warning:["\uEA6C","!"],close:["\uEA76","x"]
1117
+ }
1118
+ var terminalIconIDs=Object.keys(glyphs)
1119
+ function terminalIcon(id,style){return(glyphs[id]??glyphs.bolt)[style==="nerd"?0:1]
1120
+ }
1121
+ function terminalIconLabel(id){return id.replaceAll("-"," ")
1122
+ }
1088
1123
  function McpErrorDialog(props){return _$createComponent(SelectionMenu,{get api(){return props.api
1089
1124
  },get title(){return `MCP error \xB7 ${props.name}`
1090
1125
  },height:12,get options(){return [{title:`Status \xB7 ${props.status}`,value:"error",description:props.error,icon:"error"
@@ -1192,22 +1227,95 @@ throw new Error(`Expected format ${PORTABLE_SETTINGS_FORMAT}`)
1192
1227
  if(input.version!==1)
1193
1228
  throw new Error(`Unsupported settings version ${String(input.version)}`)
1194
1229
  const unsupported=[]
1195
- unknownKeys(input,["format","version","layout","mcp"],"",unsupported)
1230
+ unknownKeys(input,["format","version","layout","mcp","behavior"],"",unsupported)
1196
1231
  const hasLayout=Object.hasOwn(input,"layout")
1197
1232
  const hasMcp=Object.hasOwn(input,"mcp")
1198
- if(!hasLayout&&!hasMcp)
1233
+ const behavior={}
1234
+ if(input.behavior!==undefined){const raw=object(input.behavior,"/behavior")
1235
+ unknownKeys(raw,["toolbarOverflow"],"/behavior",unsupported)
1236
+ if(raw.toolbarOverflow!==undefined){if(raw.toolbarOverflow!=="menu"&&raw.toolbarOverflow!=="wrap")
1237
+ throw new Error("/behavior/toolbarOverflow must be menu or wrap")
1238
+ behavior.toolbarOverflow=raw.toolbarOverflow
1239
+ }}
1240
+ if(!hasLayout&&!hasMcp&&!behavior.toolbarOverflow)
1199
1241
  throw new Error("Settings JSON contains no supported settings")
1200
- const settings={format:PORTABLE_SETTINGS_FORMAT,version:1,...hasLayout&&{layout:parseLayout(input.layout,unsupported)},...hasMcp&&{mcp:parseMcp(input.mcp)}}
1242
+ const settings={format:PORTABLE_SETTINGS_FORMAT,version:1,...hasLayout&&{layout:parseLayout(input.layout,unsupported)},...hasMcp&&{mcp:parseMcp(input.mcp)},...behavior.toolbarOverflow&&{behavior}}
1201
1243
  unsupported.sort()
1202
1244
  return{settings,unsupported}}
1203
- function serializePortableSettings(layout,mcp){return `${JSON.stringify({
1245
+ function serializePortableSettings(layout,mcp,behavior){return `${JSON.stringify({
1204
1246
  format: PORTABLE_SETTINGS_FORMAT,
1205
1247
  version: 1,
1206
1248
  layout,
1249
+ ...behavior && { behavior },
1207
1250
  mcp: Object.fromEntries(Object.entries(mcp).sort(([left], [right]) => left.localeCompare(right)))
1208
1251
  }, undefined, 2)}
1209
1252
  `
1210
1253
  }
1254
+ function toolbarPinKey(pin){return pin.kind==="action"?`action:${pin.id}`:`skill:${pin.location}`
1255
+ }
1256
+ function identifier(value){return typeof value==="string"&&/^[a-z][a-z\d-]{0,47}$/u.test(value)
1257
+ }
1258
+ function parsePin(value){if(!value||typeof value!=="object")
1259
+ return
1260
+ const input=value
1261
+ if(!identifier(input.icon))
1262
+ return
1263
+ const stateIcons=Object.fromEntries(Object.entries(input.stateIcons&&typeof input.stateIcons==="object"?input.stateIcons:{}).filter(([key,icon])=>identifier(key)&&identifier(icon)))
1264
+ const icons={icon:input.icon,...Object.keys(stateIcons).length>0&&{stateIcons}}
1265
+ if(input.kind==="action"&&QUICK_ACTION_IDS.includes(input.id))
1266
+ return{kind:"action",id:input.id,...icons}
1267
+ if(input.kind==="skill"&&typeof input.location==="string"&&input.location.trim()&&typeof input.name==="string"&&input.name.trim())
1268
+ return{kind:"skill",location:input.location,name:input.name.trim().slice(0,128),...icons}
1269
+ return
1270
+ }
1271
+ function parseToolbarPins(value){if(!Array.isArray(value))
1272
+ return []
1273
+ const keys=new Set
1274
+ return value.flatMap((candidate)=>{const pin=parsePin(candidate)
1275
+ if(!pin||keys.has(toolbarPinKey(pin))||keys.size>=100)
1276
+ return []
1277
+ keys.add(toolbarPinKey(pin))
1278
+ return [pin]
1279
+ })
1280
+ }
1281
+ function changeToolbarPins(current=[],change){const pins=parseToolbarPins(current)
1282
+ if(change.operation==="pin"){const pin=parsePin(change.pin)
1283
+ if(!pin)
1284
+ throw new Error("Invalid toolbar pin")
1285
+ if(pins.some((item)=>toolbarPinKey(item)===toolbarPinKey(pin)))
1286
+ throw new Error("This item is already pinned")
1287
+ if(pins.length>=100)
1288
+ throw new Error("You can pin at most 100 items")
1289
+ return [...pins,pin]
1290
+ }
1291
+ const index=pins.findIndex((pin)=>toolbarPinKey(pin)===change.key)
1292
+ if(index===-1){if(change.operation==="configure")
1293
+ throw new Error("Pin no longer exists; reopen the toolbar manager")
1294
+ return pins
1295
+ }
1296
+ if(change.operation==="configure"){if(change.expected&&change.expected!==JSON.stringify(pins[index]))
1297
+ throw new Error("Pin changed; reopen its configuration")
1298
+ const stateIcons={...pins[index].stateIcons}
1299
+ const changes=Object.entries(change.stateIcons??{})
1300
+ for(const [state,icon] of changes){if(!identifier(state)||icon!==null&&!identifier(icon))
1301
+ throw new Error("Invalid state icon")
1302
+ if(icon===null)
1303
+ delete stateIcons[state]
1304
+ else
1305
+ stateIcons[state]=icon
1306
+ }
1307
+ const pin=parsePin({...pins[index],icon:change.icon,stateIcons})
1308
+ if(!pin)
1309
+ throw new Error("Invalid toolbar icon")
1310
+ pins[index]=pin
1311
+ return pins
1312
+ }
1313
+ const [pin]=pins.splice(index,1)
1314
+ if(change.operation==="move"){const destination=pins.findIndex((item)=>toolbarPinKey(item)===change.before)
1315
+ pins.splice(destination===-1?pins.length:destination,0,pin)
1316
+ }
1317
+ return pins
1318
+ }
1211
1319
  function record(value){if(!value||typeof value!=="object"||Array.isArray(value))
1212
1320
  return
1213
1321
  return value
@@ -1216,7 +1324,8 @@ function parsePluginSettings(value){const input=record(value)
1216
1324
  if(!input)
1217
1325
  return{}
1218
1326
  return{...typeof input.toggleKey==="string"&&input.toggleKey.trim()&&{toggleKey:input.toggleKey.trim()},...typeof input.focusKey==="string"&&input.focusKey.trim()&&{focusKey:input.focusKey.trim()},...typeof input.searchKey==="string"&&input.searchKey.trim()&&{searchKey:input.searchKey.trim()},...typeof input.persistMcp==="boolean"&&{persistMcp:input.persistMcp},...parseLimitsRefreshMinutes(input.limitsRefreshMinutes)!==undefined&&{limitsRefreshMinutes:parseLimitsRefreshMinutes(input.limitsRefreshMinutes)
1219
- },...typeof input.startInChat==="boolean"&&{startInChat:input.startInChat},...typeof input.showSessionTitle==="boolean"&&{showSessionTitle:input.showSessionTitle},...typeof input.showSessionDate==="boolean"&&{showSessionDate:input.showSessionDate},...typeof input.cornerFont==="boolean"&&{cornerFont:input.cornerFont},...(input.lspIconStyle==="nerd"||input.lspIconStyle==="text")&&{lspIconStyle:input.lspIconStyle},...(input.rowDensity==="compact"||input.rowDensity==="comfortable")&&{rowDensity:input.rowDensity
1327
+ },...typeof input.startInChat==="boolean"&&{startInChat:input.startInChat},...(input.toolbarOverflow==="menu"||input.toolbarOverflow==="wrap")&&{toolbarOverflow:input.toolbarOverflow
1328
+ },...typeof input.showSessionTitle==="boolean"&&{showSessionTitle:input.showSessionTitle},...typeof input.showSessionDate==="boolean"&&{showSessionDate:input.showSessionDate},...typeof input.cornerFont==="boolean"&&{cornerFont:input.cornerFont},...(input.lspIconStyle==="nerd"||input.lspIconStyle==="text")&&{lspIconStyle:input.lspIconStyle},...(input.rowDensity==="compact"||input.rowDensity==="comfortable")&&{rowDensity:input.rowDensity
1220
1329
  },...Object.keys(parseSectionItemLimits(input.sectionItemLimits)).length>0&&{sectionItemLimits:parseSectionItemLimits(input.sectionItemLimits)
1221
1330
  },...parseQuickActionOrder(input.quickActionOrder)&&{quickActionOrder:parseQuickActionOrder(input.quickActionOrder)
1222
1331
  },...Object.keys(parseQuickActionVisibility(input.quickActionVisibility)).length>0&&{quickActionVisibility:parseQuickActionVisibility(input.quickActionVisibility)
@@ -1322,7 +1431,8 @@ return{global:{...Object.keys(behavior).length>0&&{behavior},...layout&&{layout}
1322
1431
  },...typeof userInput?.lastNavigatorVersion==="string"&&{lastNavigatorVersion:userInput.lastNavigatorVersion
1323
1432
  },...typeof userInput?.previousNavigatorVersion==="string"&&{previousNavigatorVersion:userInput.previousNavigatorVersion
1324
1433
  },...Object.keys(layoutPresets).length>0&&{layoutPresets},...Object.keys(mcpPresets).length>0&&{mcpPresets},...favoriteSkills&&{favoriteSkills},...favoriteMcpServers?.length&&{favoriteMcpServers},...favoriteQuickActions.length>0&&{favoriteQuickActions},...recentSkills.length>0&&{recentSkills},...recentQuickActions.length>0&&{recentQuickActions},...Object.keys(mcpServerGroups).length>0&&{mcpServerGroups},...Object.keys(skillGroups).length>0&&{skillGroups},...Object.keys(codexAccountBindings).length>0&&{codexAccountBindings},...pendingResetAttempt&&{pendingResetAttempt},...typeof userInput?.autoApprovePermissions==="boolean"&&{autoApprovePermissions:userInput.autoApprovePermissions
1325
- },...Object.keys(workspaceProfiles).length>0&&{workspaceProfiles}}}}
1434
+ },...Object.keys(workspaceProfiles).length>0&&{workspaceProfiles},...parseToolbarPins(userInput?.toolbarPins).length>0&&{toolbarPins:parseToolbarPins(userInput?.toolbarPins)
1435
+ }}}}
1326
1436
  function parseValues(value){if(!value)
1327
1437
  return{}
1328
1438
  return{behavior:parsePluginSettings(value.behavior),layout:{sections:parseSectionPreferences(value.layout?.sections),expanded:parseSectionPreferences(value.layout?.expanded),...parseSectionOrder(value.layout?.order)&&{order:parseSectionOrder(value.layout?.order)}},desiredMcpStates:parseDesiredMcpStates(value.desiredMcpStates)
@@ -1369,7 +1479,7 @@ delete profiles[layout]
1369
1479
  }}
1370
1480
  function applyPreferencesUpdate(current,update){const target=update.target??(update.mcp?.scope?targetForLegacyScope(update.mcp.scope):{kind:"global"})
1371
1481
  const existing=targetPreferences(current,target)
1372
- if(update.expectedScope&&update.expectedScope!==JSON.stringify({layout:existing.layout,mcp:existing.mcp})){throw new Error("Settings changed after this preview; reopen the import preview")
1482
+ if(update.expectedScope&&update.expectedScope!==JSON.stringify({layout:existing.layout,mcp:existing.mcp,behavior:existing.behavior})){throw new Error("Settings changed after this preview; reopen the import preview")
1373
1483
  }
1374
1484
  const behavior={...!update.clearBehavior&&existing.behavior,...parsePluginSettings(update.behavior)
1375
1485
  }
@@ -1489,8 +1599,9 @@ favoriteSkills.splice(index,1)
1489
1599
  favoriteSkills.sort()
1490
1600
  }
1491
1601
  const onboardingCompleted=typeof update.user?.onboardingCompleted==="boolean"?update.user.onboardingCompleted:current.user.onboardingCompleted
1602
+ const toolbarPins=update.user?.toolbarPin?changeToolbarPins(current.user.toolbarPins,update.user.toolbarPin):current.user.toolbarPins
1492
1603
  return{global:target.kind==="global"?scope:current.global,worktrees,user:{...skippedSkillConfirmations.size>0&&{skippedSkillConfirmations:[...skippedSkillConfirmations].sort()
1493
- },...typeof onboardingCompleted==="boolean"&&{onboardingCompleted},...(update.user?.lastNavigatorVersion??current.user.lastNavigatorVersion)&&{lastNavigatorVersion:update.user?.lastNavigatorVersion??current.user.lastNavigatorVersion
1604
+ },...typeof onboardingCompleted==="boolean"&&{onboardingCompleted},...toolbarPins?.length&&{toolbarPins},...(update.user?.lastNavigatorVersion??current.user.lastNavigatorVersion)&&{lastNavigatorVersion:update.user?.lastNavigatorVersion??current.user.lastNavigatorVersion
1494
1605
  },...(update.user?.previousNavigatorVersion??current.user.previousNavigatorVersion)&&{previousNavigatorVersion:update.user?.previousNavigatorVersion??current.user.previousNavigatorVersion
1495
1606
  },...Object.keys(parsedLayoutPresets).length>0&&{layoutPresets:parsedLayoutPresets},...Object.keys(parsedMcpPresets).length>0&&{mcpPresets:parsedMcpPresets},...Object.keys(workspaceProfiles).length>0&&{workspaceProfiles:parseWorkspaceProfiles(workspaceProfiles)
1496
1607
  },...favoriteSkills.length>0&&{favoriteSkills},...favoriteMcpServers.size>0&&{favoriteMcpServers:[...favoriteMcpServers].sort()},...favoriteQuickActions.size>0&&{favoriteQuickActions:parseFavoriteQuickActions([...favoriteQuickActions])
@@ -1648,7 +1759,7 @@ return{behavior:scope.behavior,layout:scope.layout,desiredMcpStates:scope.mcp
1648
1759
  }}
1649
1760
  function mergeSessionLayout(base,session){const order=session.order??base?.order
1650
1761
  return{sections:{...base?.sections,...session.sections},expanded:{...base?.expanded,...session.expanded},...order&&{order:[...order]}}}
1651
- function createPreferencesController(api,defaults,store,configured={}){const builtIns={behavior:{toggleKey:defaults.toggleKey,focusKey:defaults.focusKey,searchKey:defaults.searchKey,persistMcp:defaults.persistMcp,limitsRefreshMinutes:defaults.limitsRefreshMinutes,startInChat:defaults.startInChat,showSessionTitle:defaults.showSessionTitle,showSessionDate:defaults.showSessionDate,cornerFont:defaults.cornerFont,lspIconStyle:defaults.lspIconStyle,rowDensity:defaults.rowDensity,sectionItemLimits:defaults.sectionItemLimits,quickActionOrder:defaults.quickActionOrder,quickActionVisibility:defaults.quickActionVisibility
1762
+ function createPreferencesController(api,defaults,store,configured={}){const builtIns={behavior:{toggleKey:defaults.toggleKey,focusKey:defaults.focusKey,searchKey:defaults.searchKey,persistMcp:defaults.persistMcp,limitsRefreshMinutes:defaults.limitsRefreshMinutes,startInChat:defaults.startInChat,showSessionTitle:defaults.showSessionTitle,showSessionDate:defaults.showSessionDate,cornerFont:defaults.cornerFont,lspIconStyle:defaults.lspIconStyle,rowDensity:defaults.rowDensity,toolbarOverflow:defaults.toolbarOverflow,sectionItemLimits:defaults.sectionItemLimits,quickActionOrder:defaults.quickActionOrder,quickActionVisibility:defaults.quickActionVisibility
1652
1763
  },layout:{sections:defaults.sections,expanded:DEFAULT_SECTION_EXPANSION,order:defaults.sectionOrder??[...SIDEBAR_SECTIONS]
1653
1764
  },desiredMcpStates:{}}
1654
1765
  const [resolved,setResolved]=createSignal4(resolvePreferences({builtIns,pluginOptions:configured}))
@@ -1714,7 +1825,7 @@ return resolveTarget(selectedTarget())
1714
1825
  function workspaceProfiles(){revision()
1715
1826
  return{...configured.workspaceProfiles,...document.user.workspaceProfiles}}
1716
1827
  function scopeSnapshot(target=selectedTarget()){const scope=target.kind==="global"?document.global:document.worktrees[target.key]
1717
- return JSON.stringify({layout:scope?.layout,mcp:scope?.mcp})
1828
+ return JSON.stringify({layout:scope?.layout,mcp:scope?.mcp,behavior:scope?.behavior})
1718
1829
  }
1719
1830
  function update(change){updateRevision++
1720
1831
  document=applyPreferencesUpdate(document,change)
@@ -1891,9 +2002,15 @@ next.add(id)
1891
2002
  setFavoriteQuickActions(next)
1892
2003
  update({user:{favoriteQuickAction:{id,favorite:next.has(id)}}})
1893
2004
  }
1894
- return{sections:()=>resolved().layout.sections,expanded:()=>resolved().layout.expanded,sectionOrder:()=>resolved().layout.order,toggleKey:()=>resolved().behavior.toggleKey,focusKey:()=>resolved().behavior.focusKey,searchKey:()=>resolved().behavior.searchKey,persistMcp:()=>resolved().behavior.persistMcp,limitsRefreshMinutes:()=>resolved().behavior.limitsRefreshMinutes,showSessionTitle:()=>resolved().behavior.showSessionTitle,showSessionDate:()=>resolved().behavior.showSessionDate,startInChatForScope:(scope)=>{revision()
2005
+ return{sections:()=>resolved().layout.sections,toolbarPins(){revision()
2006
+ return document.user.toolbarPins??[]
2007
+ },changeToolbarPin(change){requireHydration()
2008
+ update({user:{toolbarPin:change}})
2009
+ },expanded:()=>resolved().layout.expanded,sectionOrder:()=>resolved().layout.order,toggleKey:()=>resolved().behavior.toggleKey,focusKey:()=>resolved().behavior.focusKey,searchKey:()=>resolved().behavior.searchKey,persistMcp:()=>resolved().behavior.persistMcp,limitsRefreshMinutes:()=>resolved().behavior.limitsRefreshMinutes,showSessionTitle:()=>resolved().behavior.showSessionTitle,showSessionDate:()=>resolved().behavior.showSessionDate,startInChatForScope:(scope)=>{revision()
1895
2010
  return resolveTarget(targetForScope(scope),false).behavior.startInChat
1896
- },cornerFont:()=>resolved().behavior.cornerFont,lspIconStyle:()=>resolved().behavior.lspIconStyle,rowDensity:()=>resolved().behavior.rowDensity,selectedToggleKey:()=>selectedResolved().behavior.toggleKey,selectedFocusKey:()=>selectedResolved().behavior.focusKey,selectedSearchKey:()=>selectedResolved().behavior.searchKey,selectedPersistMcp:()=>selectedResolved().behavior.persistMcp,selectedLimitsRefreshMinutes:()=>selectedResolved().behavior.limitsRefreshMinutes,setLimitsRefreshMinutes(value){if(parseLimitsRefreshMinutes(value)===undefined)
2011
+ },cornerFont:()=>resolved().behavior.cornerFont,lspIconStyle:()=>resolved().behavior.lspIconStyle,rowDensity:()=>resolved().behavior.rowDensity,toolbarOverflow:()=>resolved().behavior.toolbarOverflow,selectedToolbarOverflow:()=>selectedResolved().behavior.toolbarOverflow,toggleToolbarOverflow(){load()
2012
+ update({target:selectedTarget(),behavior:{toolbarOverflow:selectedResolved().behavior.toolbarOverflow==="menu"?"wrap":"menu"}})
2013
+ },selectedToggleKey:()=>selectedResolved().behavior.toggleKey,selectedFocusKey:()=>selectedResolved().behavior.focusKey,selectedSearchKey:()=>selectedResolved().behavior.searchKey,selectedPersistMcp:()=>selectedResolved().behavior.persistMcp,selectedLimitsRefreshMinutes:()=>selectedResolved().behavior.limitsRefreshMinutes,setLimitsRefreshMinutes(value){if(parseLimitsRefreshMinutes(value)===undefined)
1897
2014
  throw new Error("Enter whole minutes (at least 1 minute, within the supported timer range)")
1898
2015
  load()
1899
2016
  update({target:selectedTarget(),behavior:{limitsRefreshMinutes:value}})
@@ -1911,23 +2028,24 @@ update({target:selectedTarget(),behavior:{quickActionOrder:order}})
1911
2028
  throw new Error("Enter a non-negative whole number (0 for All)")
1912
2029
  load()
1913
2030
  update({target:selectedTarget(),behavior:{sectionItemLimits:{[section]:value}}})
1914
- },selectedSections:()=>selectedLayoutResolved().layout.sections,selectedExpanded:()=>selectedLayoutResolved().layout.expanded,selectedSectionOrder:()=>selectedLayoutResolved().layout.order,layoutPresets,mcpPresets,workspaceProfiles,exportPortableSettings(){return serializePortableSettings(selectedLayoutResolved().layout,selectedResolved().desiredMcpStates)
2031
+ },selectedSections:()=>selectedLayoutResolved().layout.sections,selectedExpanded:()=>selectedLayoutResolved().layout.expanded,selectedSectionOrder:()=>selectedLayoutResolved().layout.order,layoutPresets,mcpPresets,workspaceProfiles,exportPortableSettings(){return serializePortableSettings(selectedLayoutResolved().layout,selectedResolved().desiredMcpStates,{toolbarOverflow:selectedResolved().behavior.toolbarOverflow
2032
+ })
1915
2033
  },previewPortableSettings(source){requireHydration()
1916
2034
  const parsed=parsePortableSettings(source)
1917
2035
  const target=selectedTarget()
1918
2036
  const current=selectedResolved()
1919
2037
  const scope=target.kind==="global"?document.global:document.worktrees[target.key]??{}
1920
- const imported={...scope,...parsed.settings.layout&&{layout:parsed.settings.layout},...parsed.settings.mcp&&{mcp:parsed.settings.mcp}}
2038
+ const imported={...scope,...parsed.settings.behavior&&{behavior:{...scope.behavior,...parsed.settings.behavior}},...parsed.settings.layout&&{layout:parsed.settings.layout},...parsed.settings.mcp&&{mcp:parsed.settings.mcp}}
1921
2039
  const next=resolvePreferences({builtIns,pluginOptions:configured,global:values(target.kind==="global"?imported:document.global),worktree:target.kind==="worktree"?values(imported):undefined
1922
2040
  })
1923
2041
  const layoutChanged=Boolean(parsed.settings.layout&&JSON.stringify(next.layout)!==JSON.stringify(selectedLayoutResolved().layout))
1924
2042
  const mcpChanged=Boolean(parsed.settings.mcp&&JSON.stringify(next.desiredMcpStates)!==JSON.stringify(current.desiredMcpStates))
1925
- return{...parsed,target:targetKey(target),expectedScope:scopeSnapshot(target),layoutChanged,mcpChanged
2043
+ return{...parsed,target:targetKey(target),expectedScope:scopeSnapshot(target),layoutChanged,mcpChanged,behaviorChanged:Boolean(parsed.settings.behavior&&next.behavior.toolbarOverflow!==current.behavior.toolbarOverflow)
1926
2044
  }},async applyPortableSettings(preview){await load()
1927
2045
  const target=selectedTarget()
1928
2046
  if(preview.target!==targetKey(target))
1929
2047
  throw new Error("Preference scope changed; reopen the import preview")
1930
- const change={target,expectedScope:preview.expectedScope,...preview.settings.layout&&{layout:preview.settings.layout,clearLayout:true},...preview.settings.mcp&&{mcp:{states:preview.settings.mcp},clearMcp:true}}
2048
+ const change={target,expectedScope:preview.expectedScope,...preview.settings.behavior&&{behavior:preview.settings.behavior},...preview.settings.layout&&{layout:preview.settings.layout,clearLayout:true},...preview.settings.mcp&&{mcp:{states:preview.settings.mcp},clearMcp:true}}
1931
2049
  updateRevision++
1932
2050
  await store.update(change)
1933
2051
  document=await store.load()
@@ -2173,15 +2291,16 @@ return{behavior,layout:{sections,expanded:{},...sectionOrder&&{order:sectionOrde
2173
2291
  function configuredDefaultsFromPluginOptions(options){return mergeConfiguredDefaults(legacyDefaults(pluginConfig(options)),parseConfiguredDefaults(options??{}))
2174
2292
  }
2175
2293
 
2176
- function createSkillController(api){const [skills,setSkills]=createSignal5({})
2294
+ function createSkillController(api,source){const [skills,setSkills]=createSignal5({})
2177
2295
  const refreshing=new Map
2178
2296
  const targets=new Map
2179
2297
  const requests=createRequestState(api.lifecycle.signal)
2180
2298
  const promptRequests=createRequestState(api.lifecycle.signal)
2181
2299
  let activeTarget
2300
+ let leases=new Set
2182
2301
  function target(){return currentLocation(api)
2183
2302
  }
2184
- function list(current=target()){return skills()[current.key]??[]
2303
+ function list(current=target()){return source?source.list(current):skills()[current.key]??[]
2185
2304
  }
2186
2305
  function error(current=target()){return requests.state(current.key).error?.message
2187
2306
  }
@@ -2192,8 +2311,8 @@ targets.set(current.key,current)
2192
2311
  const requestState=requests.start(current.key,"refresh skills",current.key in skills(),force)
2193
2312
  if(!requestState)
2194
2313
  return pending
2195
- const request=api.client.app.skills(current.routing,{throwOnError:true,signal:requestState.signal}).then((result)=>{const items=[...result.data??[]].sort((a,b)=>a.name.localeCompare(b.name))
2196
- if(requestState.isCurrent())
2314
+ const request=(source?source.refresh(current,force,requestState.signal).then((data)=>({data})):api.client.app.skills(current.routing,{throwOnError:true,signal:requestState.signal})).then((result)=>{const items=[...result.data??[]].sort((a,b)=>a.name.localeCompare(b.name))
2315
+ if(!source&&requestState.isCurrent())
2197
2316
  setSkills((value)=>({...value,[current.key]:items}))
2198
2317
  requestState.succeed()
2199
2318
  return items
@@ -2216,19 +2335,25 @@ if(activeTarget!==current.key){requests.abortAll()
2216
2335
  promptRequests.abortAll()
2217
2336
  refreshing.clear()
2218
2337
  activeTarget=current.key
2338
+ leases=new Set
2339
+ targets.clear()
2340
+ targets.set(current.key,current)
2219
2341
  }
2220
- return()=>{if(activeTarget!==current.key)
2342
+ const lease=Symbol(current.key)
2343
+ leases.add(lease)
2344
+ return()=>{if(activeTarget!==current.key||!leases.delete(lease)||leases.size>0)
2221
2345
  return
2222
2346
  activeTarget=undefined
2347
+ targets.delete(current.key)
2223
2348
  requests.abortAll()
2224
2349
  promptRequests.abortAll()
2225
2350
  refreshing.clear()
2226
- }},async use(current,name){if(activeTarget&&activeTarget!==current.key)
2351
+ }},async use(current,name,selected){if(activeTarget&&activeTarget!==current.key||target().key!==current.key)
2227
2352
  throw new DOMException("Sidebar context changed","AbortError")
2228
2353
  const request=promptRequests.start(current.key,"insert skill",false,true)
2229
2354
  if(!request)
2230
2355
  return false
2231
- try{const result=await api.client.tui.appendPrompt({...current.routing,text:`/${name} `},{throwOnError:true,signal:request.signal})
2356
+ try{const result=source&&selected?{data:await source.use(current,selected,request.signal)}:await api.client.tui.appendPrompt({...current.routing,text:`/${name} `},{throwOnError:true,signal:request.signal})
2232
2357
  if(!request.isCurrent())
2233
2358
  return false
2234
2359
  request.succeed()
@@ -2257,11 +2382,6 @@ return rank||left.bucket.localeCompare(right.bucket)||(left.bucket==="Favorites"
2257
2382
 
2258
2383
 
2259
2384
 
2260
-
2261
-
2262
-
2263
-
2264
-
2265
2385
  function SkillConfirmation(props){const icons=useIcons()
2266
2386
  const theme=()=>props.api.theme.current
2267
2387
  return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` Confirmation`),_el$4=_$createElement("box"),_el$5=_$createElement("text"),_el$6=_$createElement("text"),_el$8=_$createElement("text"),_el$9=_$createTextNode(`(`),_el$0=_$createTextNode(`)`),_el$1=_$createElement("box")
@@ -2326,7 +2446,7 @@ return _el$
2326
2446
 
2327
2447
 
2328
2448
  function SkillDetails(props){const icons=useIcons()
2329
- const dimensions=useTerminalDimensions2()
2449
+ const dimensions=useTerminalDimensions3()
2330
2450
  const theme=()=>props.api.theme.current
2331
2451
  return(()=>{var _el$=_$createElement("scrollbox"),_el$2=_$createElement("box"),_el$3=_$createElement("box"),_el$4=_$createElement("text"),_el$5=_$createTextNode(` Description`),_el$6=_$createElement("text"),_el$7=_$createElement("box"),_el$8=_$createElement("text"),_el$9=_$createTextNode(` Source`),_el$0=_$createElement("text")
2332
2452
  _$insertNode(_el$,_el$2)
@@ -2365,11 +2485,67 @@ return _p$
2365
2485
  return _el$
2366
2486
  })()
2367
2487
  }
2368
- function SkillDialog(props){const icons=useIcons()
2369
- const dialogs=useDialogs(props.api)
2370
- const [skipConfirmation,setSkipConfirmation]=createSignal6(false)
2371
- const [active,setActive]=createSignal6("accept")
2488
+
2489
+
2490
+
2491
+
2492
+
2493
+
2494
+
2495
+
2496
+
2497
+
2498
+ function SkillDialogHeader(props){const icons=useIcons()
2372
2499
  const theme=()=>props.api.theme.current
2500
+ return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` `),_el$4=_$createElement("box"),_el$5=_$createElement("text")
2501
+ _$insertNode(_el$,_el$2)
2502
+ _$insertNode(_el$,_el$4)
2503
+ _$setProp(_el$,"flexDirection","row")
2504
+ _$setProp(_el$,"justifyContent","space-between")
2505
+ _$setProp(_el$,"alignItems","center")
2506
+ _$insertNode(_el$2,_el$3)
2507
+ _$setProp(_el$2,"truncate",true)
2508
+ _$setProp(_el$2,"wrapMode","none")
2509
+ _$setProp(_el$2,"flexGrow",1)
2510
+ _$insert(_el$2,()=>icons.icon("skills"),_el$3)
2511
+ _$insert(_el$2,()=>props.name,null)
2512
+ _$insertNode(_el$4,_el$5)
2513
+ _$setProp(_el$4,"flexDirection","row")
2514
+ _$setProp(_el$4,"gap",1)
2515
+ _$setProp(_el$4,"alignItems","center")
2516
+ _$insert(_el$4,_$createComponent(Show2,{get when(){return props.onConfigure
2517
+ },get children(){return _$createComponent(IconControl,{get icon(){return terminalIcon("pin",icons.style())
2518
+ },get foregroundColor(){return _$memo(()=>props.active==="configure")()?theme().selectedListItemText:theme().textMuted
2519
+ },get backgroundColor(){return _$memo(()=>props.active==="configure")()?theme().primary:undefined
2520
+ },onMouseOver:()=>props.onActive("configure"),onMouseUp:()=>props.onConfigure?.()
2521
+ })
2522
+ }}),_el$5)
2523
+ _$insert(_el$4,_$createComponent(BookmarkControl,{get bookmarked(){return props.favorite
2524
+ },get backgroundColor(){return _$memo(()=>props.active==="favorite")()?theme().primary:undefined
2525
+ },get foregroundColor(){return _$memo(()=>!!props.favoriteDisabled)()?theme().textMuted:_$memo(()=>props.active==="favorite")()?theme().selectedListItemText:theme().warning
2526
+ },onMouseOver:()=>{if(!props.favoriteDisabled)
2527
+ props.onActive("favorite")
2528
+ },onMouseUp:()=>{if(!props.favoriteDisabled)
2529
+ props.onFavorite()
2530
+ }}),_el$5)
2531
+ _$setProp(_el$5,"onMouseDown",(event)=>event.stopPropagation())
2532
+ _$setProp(_el$5,"onMouseUp",(event)=>{event.stopPropagation()
2533
+ props.onCancel()
2534
+ })
2535
+ _$insert(_el$5,()=>icons.key("esc"))
2536
+ _$effect((_p$)=>{var _v$=TextAttributes6.BOLD,_v$2=theme().text,_v$3=theme().textMuted
2537
+ _v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"attributes",_v$,_p$.e))
2538
+ _v$2!==_p$.t&&(_p$.t=_$setProp(_el$2,"fg",_v$2,_p$.t))
2539
+ _v$3!==_p$.a&&(_p$.a=_$setProp(_el$5,"fg",_v$3,_p$.a))
2540
+ return _p$
2541
+ },{e:undefined,t:undefined,a:undefined
2542
+ })
2543
+ return _el$
2544
+ })()
2545
+ }
2546
+ function SkillDialog(props){const dialogs=useDialogs(props.api)
2547
+ const [skipConfirmation,setSkipConfirmation]=useDialogState("skill-skip",false)
2548
+ const [active,setActive]=useDialogState("skill-action","accept")
2373
2549
  let body
2374
2550
  function accept(){const isSkip=skipConfirmation()
2375
2551
  dialogs.close()
@@ -2378,6 +2554,8 @@ props.onAccept(isSkip)
2378
2554
  function cancel(){dialogs.back()
2379
2555
  }
2380
2556
  function move(offset){const actions=props.favoriteDisabled?["accept","cancel"]:["accept","cancel","favorite"]
2557
+ if(props.onConfigure)
2558
+ actions.push("configure")
2381
2559
  const index=actions.indexOf(active())
2382
2560
  setActive(actions[(index + offset + actions.length)%actions.length])
2383
2561
  }
@@ -2385,11 +2563,13 @@ function submit(){if(active()==="accept")
2385
2563
  accept()
2386
2564
  else if(active()==="cancel")
2387
2565
  cancel()
2566
+ else if(active()==="configure")
2567
+ props.onConfigure?.(dialogs)
2388
2568
  else if(!props.favoriteDisabled)
2389
2569
  props.onToggleFavorite()
2390
2570
  }
2391
2571
  function confirmationAction(){const action=active()
2392
- return action==="favorite"?undefined:action
2572
+ return action==="favorite"||action==="configure"?undefined:action
2393
2573
  }
2394
2574
  const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,commands:[{name:`${PLUGIN_ID}.skill-dialog.scroll-up`,run:()=>body?.scrollBy(-1)
2395
2575
  },{name:`${PLUGIN_ID}.skill-dialog.scroll-down`,run:()=>body?.scrollBy(1)
@@ -2406,43 +2586,17 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
2406
2586
  },{key:"return",cmd:`${PLUGIN_ID}.skill-dialog.submit`
2407
2587
  }]
2408
2588
  })
2409
- onCleanup3(unregister)
2589
+ onCleanup4(unregister)
2410
2590
  return _$createComponent(DialogSurface,{get api(){return props.api
2411
- },get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` `),_el$4=_$createElement("box"),_el$5=_$createElement("text")
2412
- _$insertNode(_el$,_el$2)
2413
- _$insertNode(_el$,_el$4)
2414
- _$setProp(_el$,"flexDirection","row")
2415
- _$setProp(_el$,"justifyContent","space-between")
2416
- _$setProp(_el$,"alignItems","center")
2417
- _$insertNode(_el$2,_el$3)
2418
- _$insert(_el$2,()=>icons.icon("skills"),_el$3)
2419
- _$insert(_el$2,()=>props.skill.name,null)
2420
- _$insertNode(_el$4,_el$5)
2421
- _$setProp(_el$4,"flexDirection","row")
2422
- _$setProp(_el$4,"gap",1)
2423
- _$setProp(_el$4,"alignItems","center")
2424
- _$insert(_el$4,_$createComponent(BookmarkControl,{get bookmarked(){return props.favorite
2425
- },get backgroundColor(){return _$memo(()=>active()==="favorite")()?theme().primary:undefined
2426
- },get foregroundColor(){return _$memo(()=>!!props.favoriteDisabled)()?theme().textMuted:_$memo(()=>active()==="favorite")()?theme().selectedListItemText:theme().warning
2427
- },onMouseOver:()=>{if(!props.favoriteDisabled)
2428
- setActive("favorite")
2429
- },onMouseUp:()=>{if(!props.favoriteDisabled)
2430
- props.onToggleFavorite()
2431
- }}),_el$5)
2432
- _$setProp(_el$5,"onMouseDown",(event)=>event.stopPropagation())
2433
- _$setProp(_el$5,"onMouseUp",(event)=>{event.stopPropagation()
2434
- cancel()
2435
- })
2436
- _$insert(_el$5,()=>icons.key("esc"))
2437
- _$effect((_p$)=>{var _v$=TextAttributes6.BOLD,_v$2=theme().text,_v$3=theme().textMuted
2438
- _v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"attributes",_v$,_p$.e))
2439
- _v$2!==_p$.t&&(_p$.t=_$setProp(_el$2,"fg",_v$2,_p$.t))
2440
- _v$3!==_p$.a&&(_p$.a=_$setProp(_el$5,"fg",_v$3,_p$.a))
2441
- return _p$
2442
- },{e:undefined,t:undefined,a:undefined
2443
- })
2444
- return _el$
2445
- })(),_$createComponent(SkillDetails,{get api(){return props.api
2591
+ },get children(){return [_$createComponent(SkillDialogHeader,{get api(){return props.api
2592
+ },get name(){return props.skill.name
2593
+ },get favorite(){return props.favorite
2594
+ },get favoriteDisabled(){return props.favoriteDisabled
2595
+ },get active(){return active()
2596
+ },onActive:setActive,get onFavorite(){return props.onToggleFavorite
2597
+ },get onConfigure(){return props.onConfigure?()=>props.onConfigure?.(dialogs):undefined
2598
+ },onCancel:cancel
2599
+ }),_$createComponent(SkillDetails,{get api(){return props.api
2446
2600
  },get skill(){return props.skill
2447
2601
  },ref:(node)=>body=node
2448
2602
  }),_$createComponent(SkillConfirmation,{get api(){return props.api
@@ -2452,10 +2606,57 @@ return _el$
2452
2606
  })]
2453
2607
  }})
2454
2608
  }
2609
+ function skillUnavailable(controller,skill){const list=controller.list()
2610
+ if(list.every((item)=>!(item.name===skill.name&&item.location===skill.location)))
2611
+ return "Skill is unavailable in this workspace"
2612
+ if(skill.id){if(list.every((item)=>item.id!==skill.id||item.location!==skill.location))
2613
+ return "Skill source changed"
2614
+ } else if(list.filter((item)=>item.name===skill.name).length!==1)
2615
+ return "Multiple sources share this skill name"
2616
+ return
2617
+ }
2618
+ function activateSkill(input){input={...input,skill:{...input.skill
2619
+ }}
2620
+ const target=input.controller.target()
2621
+ const route=JSON.stringify(input.api.route.current)
2622
+ const current=()=>target.key===input.controller.target().key&&route===JSON.stringify(input.api.route.current)
2623
+ const report=(error)=>{if(!isAbortError(error))
2624
+ input.api.ui.toast({variant:"error",title:"Skills",message:String(error),duration:5000
2625
+ })
2626
+ }
2627
+ function check(){if(!current())
2628
+ throw new DOMException("Skill target changed; choose it again","AbortError")
2629
+ const reason=skillUnavailable(input.controller,input.skill)
2630
+ if(reason)
2631
+ throw new Error(reason)
2632
+ }
2633
+ async function insert(skip=false){try{check()
2634
+ if(skip)
2635
+ input.access.skipSkillConfirmation(input.skill)
2636
+ input.beforeInsert?.()
2637
+ if(await input.controller.use(target,input.skill.name,input.skill))
2638
+ await input.access.recordSkillUse?.(input.skill)
2639
+ } catch(error){report(error)
2640
+ }}
2641
+ try{check()
2642
+ } catch(error){report(error)
2643
+ return
2644
+ }
2645
+ if(!input.access.shouldConfirmSkill(input.skill)){insert()
2646
+ return
2647
+ }
2648
+ input.dialogs.open(()=>_$createComponent(SkillDialog,{get api(){return input.api
2649
+ },get skill(){return input.skill
2650
+ },get favorite(){return input.access.isFavoriteSkill?.(input.skill)??false
2651
+ },get favoriteDisabled(){return input.access.ready?.()===false
2652
+ },onToggleFavorite:()=>input.access.toggleFavoriteSkill?.(input.skill),get onConfigure(){return input.onConfigure
2653
+ },onAccept:(skip)=>{insert(skip)
2654
+ }}))
2655
+ }
2455
2656
 
2456
2657
 
2457
2658
  function createSubagentHistory({now=Date.now}={}){const targets=new Map
2458
- const [revision,setRevision]=createSignal7(0)
2659
+ const [revision,setRevision]=createSignal6(0)
2459
2660
  function state(key){let value=targets.get(key)
2460
2661
  if(!value){value={known:new Set,active:new Map,recent:[]}
2461
2662
  targets.set(key,value)
@@ -2510,19 +2711,21 @@ return targets.get(key)?.recent??[]
2510
2711
  var POLL_INTERVAL_MS=5000
2511
2712
  function activeStatus(status){return status?.type==="busy"||status?.type==="retry"
2512
2713
  }
2513
- function createSubagentController(api,options={}){const now=options.now??Date.now
2714
+ function createSubagentController(api,options={}){const source=options.source
2715
+ const now=options.now??Date.now
2514
2716
  const history=createSubagentHistory({now})
2515
- const [children,setChildren]=createSignal8({})
2516
- const [statuses,setStatuses]=createSignal8({})
2717
+ const [children,setChildren]=createSignal7({})
2718
+ const [statuses,setStatuses]=createSignal7({})
2517
2719
  const refreshing=new Map
2518
2720
  const journals=new Set
2519
- const [unavailable,setUnavailable]=createSignal8({})
2721
+ const [unavailable,setUnavailable]=createSignal7({})
2520
2722
  const targets=new Map
2521
2723
  const remoteFailures=new Map
2522
2724
  const remoteRetryAt=new Map
2523
2725
  const requests=createRequestState(api.lifecycle.signal)
2524
2726
  let activeTarget
2525
2727
  let pollTimer
2728
+ const snapshots=()=>source?Object.fromEntries([...targets].map(([key,current])=>[key,source.list(current.parentID)])):children()
2526
2729
  function target(parentID){const parent=api.state.session.get(parentID)
2527
2730
  const directory=parent?.directory??api.state.path.directory
2528
2731
  const workspace=parent?.workspaceID
@@ -2541,16 +2744,18 @@ history.remove(key,sessionID)
2541
2744
  }
2542
2745
  for(const journal of journals)
2543
2746
  journal.sessions.push(mutation)
2747
+ if(!source)
2544
2748
  setChildren((current)=>Object.fromEntries(Object.entries(current).map(([key,items])=>[key,applySession(items,targets.get(key).parentID,mutation)])))
2545
2749
  }
2546
2750
  function recordStatus(input){const mutation={...input,at:now(),observed:new Set}
2547
2751
  for(const journal of journals)
2548
2752
  journal.statuses.push(mutation)
2549
- batch(()=>{for(const [key,items] of Object.entries(children())){if(items.every((item)=>item.id!==mutation.sessionID))
2753
+ batch(()=>{for(const [key,items] of Object.entries(snapshots())){if(items.every((item)=>item.id!==mutation.sessionID))
2550
2754
  continue
2551
2755
  history.observeStatus(key,mutation.sessionID,mutation.status,mutation.at)
2552
2756
  mutation.observed.add(key)
2553
2757
  }
2758
+ if(!source)
2554
2759
  setStatuses((current)=>Object.fromEntries(Object.entries(current).map(([key,value])=>[key,applyStatus(value,mutation)])))
2555
2760
  })
2556
2761
  }
@@ -2559,7 +2764,7 @@ return
2559
2764
  const mutation={sessionID:input.sessionID,error:input.error,at:now(),observed:new Set}
2560
2765
  for(const journal of journals)
2561
2766
  journal.errors.push(mutation)
2562
- for(const [key,items] of Object.entries(children())){if(items.every((item)=>item.id!==mutation.sessionID))
2767
+ for(const [key,items] of Object.entries(snapshots())){if(items.every((item)=>item.id!==mutation.sessionID))
2563
2768
  continue
2564
2769
  history.observeError(key,mutation.sessionID,mutation.error,mutation.at)
2565
2770
  mutation.observed.add(key)
@@ -2576,12 +2781,13 @@ if(!requestState){journals.delete(journal)
2576
2781
  return pending
2577
2782
  }
2578
2783
  const signal=AbortSignal.any([requestState.signal,AbortSignal.timeout(5000)])
2579
- const request=Promise.all([api.client.session.children({sessionID:current.parentID,...current.routing},{throwOnError:true,signal}),api.client.session.status(current.routing,{throwOnError:true,signal})]).then(async ([childResult,statusResult])=>{let nextChildren=childResult.data??[]
2784
+ const request=(source?source.refresh(current.parentID,signal).then(()=>[{data:source.list(current.parentID)},{data:Object.fromEntries(source.list(current.parentID).map((item)=>[item.id,source.status(item.id)]))
2785
+ }]):Promise.all([api.client.session.children({sessionID:current.parentID,...current.routing},{throwOnError:true,signal}),api.client.session.status(current.routing,{throwOnError:true,signal})])).then(async ([childResult,statusResult])=>{let nextChildren=childResult.data??[]
2580
2786
  for(const mutation of journal.sessions)
2581
2787
  nextChildren=applySession(nextChildren,current.parentID,mutation)
2582
2788
  let nextStatuses={...statusResult.data}
2583
2789
  const missing={}
2584
- const remoteStatuses=await Promise.all(nextChildren.map((session)=>{const key=JSON.stringify([current.key,session.id])
2790
+ const remoteStatuses=source?[]:await Promise.all(nextChildren.map((session)=>{const key=JSON.stringify([current.key,session.id])
2585
2791
  return(remoteRetryAt.get(key)??0)<=now()?fetchDevTeamStatus(session,requestState.signal):{sessionID:session.id,failed:true,cooldown:true,status:undefined}}))
2586
2792
  if(!requestState.isCurrent())
2587
2793
  return
@@ -2618,8 +2824,9 @@ history.observeStatus(current.key,session.id,status)
2618
2824
  for(const mutation of journal.errors){if(mutation.sessionID===session.id&&!mutation.observed.has(current.key))
2619
2825
  history.observeError(current.key,session.id,mutation.error,mutation.at)
2620
2826
  }}
2621
- setChildren((value)=>({...value,[current.key]:nextChildren}))
2827
+ if(!source){setChildren((value)=>({...value,[current.key]:nextChildren}))
2622
2828
  setStatuses((value)=>({...value,[current.key]:nextStatuses}))
2829
+ }
2623
2830
  setUnavailable((value)=>({...value,[current.key]:missing}))
2624
2831
  })
2625
2832
  }
@@ -2637,13 +2844,13 @@ return request
2637
2844
  function refresh(parentID,force=false){return refreshTarget(target(parentID),force)
2638
2845
  }
2639
2846
  function list(parentID){const current=target(parentID)
2640
- const currentStatuses=statuses()[current.key]??{}
2641
- return(children()[current.key]??[]).map((session)=>({session,status:currentStatuses[session.id]??(unavailable()[current.key]?.[session.id]?undefined:api.state.session.status(session.id))
2847
+ const currentStatuses=source?Object.fromEntries(source.list(parentID).map((item)=>[item.id,source.status(item.id)])):statuses()[current.key]??{}
2848
+ return(snapshots()[current.key]??[]).map((session)=>({session,status:currentStatuses[session.id]??(unavailable()[current.key]?.[session.id]?undefined:api.state.session.status(session.id))
2642
2849
  })).filter((item)=>activeStatus(item.status)).map((item)=>({...item,run:history.active(current.key,item.session.id),unavailable:unavailable()[current.key]?.[item.session.id]
2643
2850
  }))
2644
2851
  }
2645
2852
  function recent(parentID){const current=target(parentID)
2646
- const sessions=new Map((children()[current.key]??[]).map((session)=>[session.id,session]))
2853
+ const sessions=new Map((snapshots()[current.key]??[]).map((session)=>[session.id,session]))
2647
2854
  return history.recent(current.key).flatMap((run)=>{const session=sessions.get(run.sessionID)
2648
2855
  return session?[{session,status:{type:"idle"},run,unavailable:false}]:[]
2649
2856
  })
@@ -2673,6 +2880,7 @@ return
2673
2880
  refreshTarget(current).catch(()=>{})
2674
2881
  pollTimer=setTimeout(poll,POLL_INTERVAL_MS)
2675
2882
  }
2883
+ if(!source)
2676
2884
  pollTimer=setTimeout(poll,POLL_INTERVAL_MS)
2677
2885
  }
2678
2886
  return()=>{if(activeTarget!==current.key)
@@ -2735,17 +2943,17 @@ else if(seconds>=60)
2735
2943
  value=`${Math.floor(seconds / 60)}m ${String(seconds % 60).padStart(2, "0")}s`
2736
2944
  return value
2737
2945
  }
2738
- function createSubagentClock(key){const [now,setNow]=createSignal9(Date.now())
2946
+ function createSubagentClock(key){const [now,setNow]=createSignal8(Date.now())
2739
2947
  createEffect5(()=>{if(key()===undefined)
2740
2948
  return
2741
2949
  setNow(Date.now())
2742
2950
  const timer=setInterval(()=>setNow(Date.now()),1000)
2743
- onCleanup4(()=>clearInterval(timer))
2951
+ onCleanup5(()=>clearInterval(timer))
2744
2952
  })
2745
2953
  return now
2746
2954
  }
2747
2955
 
2748
- function createTodoController(api){const [sessions,setSessions]=createSignal10({})
2956
+ function createTodoController(api){const [sessions,setSessions]=createSignal9({})
2749
2957
  const refreshing=new Map
2750
2958
  const revisions=new Map
2751
2959
  const requests=createRequestState(api.lifecycle.signal)
@@ -2799,107 +3007,7 @@ activeTarget=undefined
2799
3007
  requests.abortAll()
2800
3008
  refreshing.clear()
2801
3009
  }}}}
2802
- function normalizeTodoState(value){if(!value||typeof value!=="object")
2803
- return{todos:[],guidance:false}
2804
- const state=value
2805
- const statuses=new Set(["pending","in_progress","completed","cancelled"])
2806
- const priorities=new Set(["high","medium","low"])
2807
- 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}})):[]
2808
- return{todos,guidance:state.guidance===true}}
2809
-
2810
- 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
2811
- }
2812
- var todos={type:"array",items:item,maxItems:100}
2813
- var sessionID={type:"string",minLength:1}
2814
- var output={type:"object",properties:{todos,guidance:{type:"boolean"}},required:["todos","guidance"],additionalProperties:false
2815
- }
2816
- var NavigatorTodoRpc={id:"opencode-navigator.todo",methods:{list:{input:{type:"object",properties:{sessionID},required:["sessionID"],additionalProperties:false},output
2817
- },replace:{input:{type:"object",properties:{sessionID,todos},required:["sessionID","todos"],additionalProperties:false
2818
- },output
2819
- },guidance:{input:{type:"object",properties:{sessionID,enabled:{type:"boolean"}},required:["sessionID","enabled"],additionalProperties:false
2820
- },output
2821
- }},events:{updated:{schema:{type:"object",properties:{sessionID,todos,guidance:{type:"boolean"}},required:["sessionID","todos","guidance"],additionalProperties:false
2822
- }}}};
2823
- function isMissingServer(error){return typeof error==="object"&&error!==null&&"type" in error&&error.type==="rpc.unavailable"
2824
- }
2825
- function createNavigatorTodoController(context,api){const rpc=context.client.rpc(NavigatorTodoRpc)
2826
- const [sessions,setSessions]=createSignal11({})
2827
- const [saving,setSaving]=createSignal11({})
2828
- const [errors,setErrors]=createSignal11({})
2829
- const [missing,setMissing]=createSignal11({})
2830
- const requests=createRequestState(api.lifecycle.signal)
2831
- const refreshing=new Map
2832
- const revisions=new Map
2833
- let activeTarget
2834
- function target(sessionID){const session=api.state.session.get(sessionID)
2835
- const directory=session?.directory??api.state.path.directory
2836
- const workspace=session?.workspaceID
2837
- return{key:JSON.stringify([sessionID,directory,workspace??null]),sessionID,routing:{directory}}}
2838
- function set(key,value){setSessions((current)=>({...current,[key]:normalizeTodoState(value)}))
2839
- }
2840
- function refresh(sessionID,force=false){const current=target(sessionID)
2841
- const pending=refreshing.get(current.key)
2842
- if(pending&&!force)
2843
- return pending
2844
- const revision=revisions.get(current.key)??0
2845
- const requestState=requests.start(current.key,"refresh Navigator todos",current.key in sessions(),force)
2846
- if(!requestState)
2847
- return pending
2848
- const request=rpc.list({sessionID},{location:current.routing,signal:requestState.signal}).then((value)=>{const state=normalizeTodoState(value)
2849
- if(requestState.isCurrent()){setMissing((values)=>({...values,[current.key]:false}))
2850
- if((revisions.get(current.key)??0)===revision)
2851
- set(current.key,state)
2852
- }
2853
- requestState.succeed()
2854
- return state
2855
- }).catch((error)=>{if(requestState.isCurrent()&&!requestState.signal.aborted)
2856
- setMissing((values)=>({...values,[current.key]:isMissingServer(error)}))
2857
- requestState.fail(error)
2858
- throw error
2859
- }).finally(()=>{requestState.finish()
2860
- if(refreshing.get(current.key)===request)
2861
- refreshing.delete(current.key)
2862
- })
2863
- refreshing.set(current.key,request)
2864
- return request
2865
- }
2866
- const unsubscribe=rpc.events.on("updated",(event)=>{const{sessionID}=event.data
2867
- if(typeof sessionID!=="string")
2868
- return
2869
- const current=target(sessionID)
2870
- if(event.location.directory!==current.routing.directory)
2871
- return
2872
- revisions.set(current.key,(revisions.get(current.key)??0) + 1)
2873
- set(current.key,normalizeTodoState(event.data))
2874
- })
2875
- api.lifecycle.onDispose(unsubscribe)
2876
- return{target,list(sessionID){return sessions()[target(sessionID).key]?.todos??[]
2877
- },refresh,state(sessionID){return requests.state(target(sessionID).key)
2878
- },missing(sessionID){return missing()[target(sessionID).key]??false
2879
- },retry(sessionID){return refresh(sessionID,true)
2880
- },guidance(sessionID){const key=target(sessionID).key
2881
- return{enabled:sessions()[key]?.guidance??false,saving:saving()[key]??false,error:errors()[key],available:key in sessions()
2882
- }},async setGuidance(sessionID,enabled){const current=target(sessionID)
2883
- if(!(current.key in sessions())||saving()[current.key])
2884
- return
2885
- setSaving((value)=>({...value,[current.key]:true}))
2886
- setErrors((value)=>({...value,[current.key]:undefined}))
2887
- try{const state=await rpc.guidance({sessionID,enabled},{location:current.routing})
2888
- revisions.set(current.key,(revisions.get(current.key)??0) + 1)
2889
- set(current.key,normalizeTodoState(state))
2890
- } catch(error){setErrors((value)=>({...value,[current.key]:error instanceof Error?error.message:String(error)}))
2891
- } finally{setSaving((value)=>({...value,[current.key]:false}))
2892
- }},activate(sessionID){const key=target(sessionID).key
2893
- if(activeTarget!==key){requests.abortAll()
2894
- refreshing.clear()
2895
- activeTarget=key
2896
- }
2897
- return()=>{if(activeTarget!==key)
2898
- return
2899
- activeTarget=undefined
2900
- requests.abortAll()
2901
- refreshing.clear()
2902
- }}}}
3010
+
2903
3011
  function buildTodoView(todos,mode){const active=[...todos.filter((item)=>item.status==="in_progress"),...todos.filter((item)=>item.status==="pending")]
2904
3012
  const completed=todos.filter((item)=>item.status==="completed")
2905
3013
  const cancelled=todos.filter((item)=>item.status==="cancelled")
@@ -2912,38 +3020,46 @@ return{groups,rows:groups.flatMap((group)=>group.items.map((item)=>({item,group:
2912
3020
 
2913
3021
 
2914
3022
 
2915
-
2916
-
2917
-
2918
-
2919
- function KeyboardHelpDialog(props){const icons=useIcons()
2920
- const theme=()=>props.api.theme.current
2921
- const hints=()=>[`${icons.key("up")}/k and ${icons.key("down")}/j move \xB7 ${icons.key("enter")} activates`,`${icons.key("enter")} on a filter starts typing \xB7 ${icons.key("esc")} returns`,`Todo: ${icons.key("enter")} on All / Active / Finished changes the view`,`MCP: ${icons.key("enter")} toggles a group`,"Show all / Show less expands or limits the filtered list",`Skills: ${icons.icon("info")} opens source \xB7 ${icons.icon("recent")} marks recent skills`,"Navigator Settings: Ctrl+,","Navigator shortcuts: c checks for updates \xB7 u updates Navigator after confirmation",`Search Everything: shortcut in Settings ${icons.icon("right")} Behavior`,`Search: type \xB7 ${icons.key("up/down")} results \xB7 ${icons.key("tab/shift+tab")} tabs \xB7 ${icons.key("enter")} run`,`${icons.key("esc")} leaves the sidebar \xB7 ${icons.key("?")} opens this help`]
2922
- return _$createComponent(DialogSurface,{get api(){return props.api
2923
- },get children(){return [(()=>{var _el$=_$createElement("text"),_el$2=_$createTextNode(` Navigator keyboard help`)
2924
- _$insertNode(_el$,_el$2)
2925
- _$insert(_el$,()=>icons.icon("help"),_el$2)
2926
- _$effect((_p$)=>{var _v$=TextAttributes7.BOLD,_v$2=theme().text
2927
- _v$!==_p$.e&&(_p$.e=_$setProp(_el$,"attributes",_v$,_p$.e))
2928
- _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"fg",_v$2,_p$.t))
2929
- return _p$
2930
- },{e:undefined,t:undefined
2931
- })
3023
+ var HelpView=lazy2(async ()=>{const path=import.meta.url.includes("/dist/tui.js")?"./sidebar-shortcuts.js":"../../../sidebar-shortcuts"
3024
+ const module=await import(path)
3025
+ return{default:module.KeyboardHelpDialog
3026
+ }})
3027
+ function KeyboardHelpDialog(props){return(()=>{var _el$=_$createElement("box")
3028
+ _$insert(_el$,_$createComponent(Suspense2,{get children(){return _$createComponent(HelpView,props)
3029
+ }}))
2932
3030
  return _el$
2933
- })(),_$createComponent(Index,{get each(){return hints()
2934
- },children:(hint)=>(()=>{var _el$3=_$createElement("text")
2935
- _$setProp(_el$3,"wrapMode","word")
2936
- _$insert(_el$3,hint)
2937
- _$effect((_$p)=>_$setProp(_el$3,"fg",theme().textMuted,_$p))
2938
- return _el$3
2939
3031
  })()
2940
- })]
2941
- }})
2942
3032
  }
2943
- function openKeyboardHelp(api,iconStyle=()=>"nerd",multilineCorners=()=>true){createDialogStack(api,iconStyle,()=>true,multilineCorners).open(()=>_$createComponent(KeyboardHelpDialog,{api
3033
+ function openKeyboardHelp(api,iconStyle=()=>"nerd",multilineCorners=()=>true,shortcuts=[]){createDialogStack(api,iconStyle,()=>true,multilineCorners).open(()=>_$createComponent(KeyboardHelpDialog,{api,shortcuts
2944
3034
  }))
2945
3035
  }
2946
3036
 
3037
+
3038
+
3039
+
3040
+
3041
+
3042
+
3043
+
3044
+
3045
+
3046
+
3047
+
3048
+ var defaults={todo:true,lsp:true}
3049
+ var capabilities=new WeakMap
3050
+ function setHostCapabilities(api,value){capabilities.set(api,value)
3051
+ }
3052
+ function hostCapabilities(api){return capabilities.get(api)??defaults
3053
+ }
3054
+ function hostCapabilityUnavailable(api,section){return section==="todo"||section==="lsp"?hostCapabilities(api).unavailable?.[section]:undefined
3055
+ }
3056
+ function supportsSidebarSection(api,section){const current=hostCapabilities(api)
3057
+ return section!=="todo"&&section!=="lsp"?true:current[section]
3058
+ }
3059
+ function supportsTitleVisibility(api){return hostCapabilities(api).titleVisibility!==false
3060
+ }
3061
+ function supportsPermissionMode(api){return hostCapabilities(api).permissionMode!==false
3062
+ }
2947
3063
  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"]]
2948
3064
  var QUICK_ACTIONS=QUICK_ACTION_IDS.map((command,index)=>({command,icon:QUICK_ACTION_METADATA[index][0],label:QUICK_ACTION_METADATA[index][1]
2949
3065
  }))
@@ -2954,10 +3070,10 @@ return action.label
2954
3070
  const command=api.keymap.getCommands?.({visibility:"registered"}).find((candidate)=>candidate.name===action.command)
2955
3071
  return typeof command?.title==="string"?command.title:action.label
2956
3072
  }
2957
- function createQuickActionRevision(api){const [revision,setRevision]=createSignal12(0)
3073
+ function createQuickActionRevision(api){const [revision,setRevision]=createSignal11(0)
2958
3074
  const unsubscribe=api.keymap.on?.("state",()=>setRevision((value)=>value + 1))
2959
3075
  if(unsubscribe)
2960
- onCleanup5(unsubscribe)
3076
+ onCleanup7(unsubscribe)
2961
3077
  return revision
2962
3078
  }
2963
3079
  function orderQuickActionIds(order,favorites){return [...order.filter((id)=>favorites.has(id)),...order.filter((id)=>!favorites.has(id))]
@@ -2970,12 +3086,35 @@ if(!getCommands)
2970
3086
  return
2971
3087
  const command=getCommands({visibility:"registered"}).find((candidate)=>candidate.name===action.command)
2972
3088
  if(!command)
2973
- return "Unavailable in this OpenCode version"
3089
+ return hostCapabilities(api).commandsReachableOnly?"Unavailable in the current session":"Unavailable in this OpenCode version"
2974
3090
  const enabled=command.enabled
2975
3091
  if(enabled===false||typeof enabled==="function"&&!enabled())
2976
3092
  return "Unavailable in the current session"
2977
3093
  return
2978
3094
  }
3095
+ var sources=new WeakMap
3096
+ function setQuickActionStateSource(api,source){sources.set(api,source)
3097
+ }
3098
+ function currentPermissionMode(api){const title=api.keymap.getCommands?.({visibility:"registered"}).find((command)=>command.name==="permission.mode")?.title
3099
+ if(typeof title!=="string")
3100
+ return
3101
+ if(title.startsWith("Disable auto-approve permissions"))
3102
+ return true
3103
+ return title.startsWith("Enable auto-approve permissions")?false:undefined
3104
+ }
3105
+ function quickActionStates(api,id){if(id==="permission.mode"&&currentPermissionMode(api)!==undefined)
3106
+ return [{id:"on",label:"Auto-approve on"},{id:"off",label:"Auto-approve off"}]
3107
+ if(id==="session.compact"&&sources.has(api))
3108
+ return [{id:"idle",label:"Idle"},{id:"compacting",label:"Compacting"}]
3109
+ return []
3110
+ }
3111
+ function quickActionState(api,id){if(id==="permission.mode"){const mode=currentPermissionMode(api)
3112
+ if(mode===undefined)
3113
+ return
3114
+ return mode?"on":"off"
3115
+ }
3116
+ return sources.get(api)?.(id)
3117
+ }
2979
3118
  var SEARCH_GROUPS=["Skills","Subagents","MCP","Actions"]
2980
3119
  var SEARCH_SECTIONS={Skills:"skills",Subagents:"subagents",MCP:"mcp",Actions:"quick_actions"
2981
3120
  }
@@ -3039,8 +3178,6 @@ return scored.map(({item})=>item)
3039
3178
 
3040
3179
 
3041
3180
 
3042
-
3043
-
3044
3181
  function mixColor(from,to,amount){return RGBA3.fromValues(from.r + (to.r-from.r)*amount,from.g + (to.g-from.g)*amount,from.b + (to.b-from.b)*amount)
3045
3182
  }
3046
3183
  function createSearchDialogController(props){const context=searchContext(props.api)
@@ -3052,7 +3189,7 @@ const [selectedID,setSelectedID]=useDialogState("selection",undefined)
3052
3189
  const [views]=useDialogState("tab-views",new Map)
3053
3190
  const tabViews=views()
3054
3191
  const [scrollTop,setScrollTop]=useDialogState("scroll",0)
3055
- const [refreshing,setRefreshing]=createSignal13(false)
3192
+ const [refreshing,setRefreshing]=createSignal12(false)
3056
3193
  const theme=()=>props.api.theme.current
3057
3194
  const icons=useIcons()
3058
3195
  const commandRevision=createQuickActionRevision(props.api)
@@ -3061,18 +3198,31 @@ const resultColors=createMemo(()=>{const background=parseColor2(theme().backgrou
3061
3198
  const contrast=background.r*0.299 + background.g*0.587 + background.b*0.114>0.5?0:1
3062
3199
  return{title:mixColor(parseColor2(theme().text),RGBA3.fromValues(contrast,contrast,contrast),0.45),description:mixColor(parseColor2(theme().textMuted),background,0.4)
3063
3200
  }})
3064
- const dimensions=useTerminalDimensions3()
3201
+ const dimensions=useTerminalDimensions5()
3202
+ const renderer=useRenderer2()
3065
3203
  let input
3066
3204
  let body
3067
3205
  let pendingScroll=scrollTop()
3068
3206
  let isDisposed=false
3069
3207
  let refreshGeneration=0
3070
- const sameContext=()=>searchContext(props.api).key===context.key
3071
- const candidates=createMemo(()=>{commandRevision()
3072
- return buildSearchCandidates({skills:props.skills.list(skillTarget),subagents:context.sessionID?buildSubagentView(props.subagents.list(context.sessionID),props.subagents.recent(context.sessionID)):[],mcp:props.mcp.list(mcpTarget),actionOrder:props.preferences.quickActionOrder?.()??QUICK_ACTION_IDS,favoriteQuickActions:props.preferences.favoriteQuickActions?.()??new Set,favoriteSkills:props.preferences.favoriteSkills(),skillGroups:props.preferences.skillGroups?.()??{},recentSkills:props.preferences.recentSkills(),favoriteMcp:props.preferences.favoriteMcpServers(),mcpGroups:props.preferences.mcpServerGroups?.()??{},hasSession:Boolean(context.sessionID),mcpBusy:props.mcp.mutating(mcpTarget)||props.mcp.bulkState(mcpTarget).status==="running",actionDisabledReason:(action)=>quickActionDisabledReason(props.api,action),actionLabel:(action)=>quickActionLabel(props.api,action)
3073
- })
3074
- })
3075
- const matches=createMemo(()=>searchResults(candidates(),query()))
3208
+ const onFrame=()=>{if(!body||body.isDestroyed)
3209
+ return
3210
+ const position=pendingScroll
3211
+ pendingScroll=undefined
3212
+ if(typeof position==="number")
3213
+ body.scrollTo(position)
3214
+ else if(typeof position==="string")
3215
+ body.scrollChildIntoView(`${prefix}.${position}`)
3216
+ setScrollTop(body.scrollTop)
3217
+ }
3218
+ renderer.on("frame",onFrame)
3219
+ onCleanup8(()=>renderer.off("frame",onFrame))
3220
+ const sameContext=()=>searchContext(props.api).key===context.key
3221
+ const candidates=createMemo(()=>{commandRevision()
3222
+ return buildSearchCandidates({skills:props.skills.list(skillTarget),subagents:context.sessionID?buildSubagentView(props.subagents.list(context.sessionID),props.subagents.recent(context.sessionID)):[],mcp:props.mcp.list(mcpTarget),actionOrder:props.preferences.quickActionOrder?.()??QUICK_ACTION_IDS,favoriteQuickActions:props.preferences.favoriteQuickActions?.()??new Set,favoriteSkills:props.preferences.favoriteSkills(),skillGroups:props.preferences.skillGroups?.()??{},recentSkills:props.preferences.recentSkills(),favoriteMcp:props.preferences.favoriteMcpServers(),mcpGroups:props.preferences.mcpServerGroups?.()??{},hasSession:Boolean(context.sessionID),mcpBusy:props.mcp.mutating(mcpTarget)||props.mcp.bulkState(mcpTarget).status==="running",actionDisabledReason:(action)=>quickActionDisabledReason(props.api,action),actionLabel:(action)=>quickActionLabel(props.api,action)
3223
+ })
3224
+ })
3225
+ const matches=createMemo(()=>searchResults(candidates(),query()))
3076
3226
  const results=createMemo(()=>matches().filter((item)=>item.group===activeTab()))
3077
3227
  const queryScope=createMemo(()=>({query:query(),tab:activeTab()
3078
3228
  }))
@@ -3126,11 +3276,6 @@ return
3126
3276
  props.api.ui.toast({title:"Search Everything",variant:"error",message:cause instanceof Error?cause.message:"Action failed",duration:4000
3127
3277
  })
3128
3278
  }
3129
- async function insertSkill(skill){if(!sameContext())
3130
- return
3131
- if(await props.skills.use(skillTarget,skill.name))
3132
- await props.preferences.recordSkillUse(skill)
3133
- }
3134
3279
  function activate(id=active()?.id){if(isDisposed||!sameContext())
3135
3280
  return
3136
3281
  const item=results().find((candidate)=>candidate.id===id)
@@ -3139,26 +3284,15 @@ return
3139
3284
  setSelectedID(item.id)
3140
3285
  if(body)
3141
3286
  setScrollTop(body.scrollTop)
3142
- if(item.group==="Skills"&&props.preferences.shouldConfirmSkill(item.skill)){dialogs.open(()=>_$createComponent(SkillDialog,{get api(){return props.api
3143
- },get skill(){return item.skill
3144
- },get favorite(){return props.preferences.isFavoriteSkill?.(item.skill)??false
3145
- },get favoriteDisabled(){return _$memo(()=>!!props.preferences.ready)()?!props.preferences.ready():false
3146
- },onToggleFavorite:()=>props.preferences.toggleFavoriteSkill?.(item.skill),onAccept:(skip)=>{if(!sameContext())
3147
- return
3148
- if(skip)
3149
- props.preferences.skipSkillConfirmation(item.skill)
3150
- insertSkill(item.skill).catch(report)
3151
- }}))
3287
+ if(item.group==="Skills"){activateSkill({api:props.api,controller:props.skills,access:props.preferences,dialogs,skill:item.skill,beforeInsert:dialogs.close
3288
+ })
3152
3289
  return
3153
3290
  }
3154
3291
  if(item.group==="MCP"){props.mcp.toggle(item.server).catch(report)
3155
3292
  return
3156
3293
  }
3157
3294
  dialogs.close()
3158
- switch(item.group){case "Skills":{insertSkill(item.skill).catch(report)
3159
- break
3160
- }
3161
- case "Subagents":{props.subagents.open(item.sessionID)
3295
+ switch(item.group){case "Subagents":{props.subagents.open(item.sessionID)
3162
3296
  break
3163
3297
  }
3164
3298
  case "Actions":{const target=props.returnTarget?.parent&&!props.returnTarget.isDestroyed?props.returnTarget:null
@@ -3188,9 +3322,10 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
3188
3322
  },{key:"ctrl+r",cmd:`${prefix}.retry`
3189
3323
  }]
3190
3324
  })
3191
- onCleanup6(()=>{isDisposed=true
3325
+ onCleanup8(()=>{isDisposed=true
3192
3326
  unregister()
3193
3327
  })
3328
+ onCleanup8(props.skills.activate?.(skillTarget)??(()=>{}))
3194
3329
  onMount(()=>{input?.focus()
3195
3330
  refresh().catch(report)
3196
3331
  })
@@ -3203,17 +3338,7 @@ return{active,activeTab,activate,allErrors,byID,dialogs,errors,icons,loading,mat
3203
3338
  pendingScroll=0
3204
3339
  setQueryValue(value)
3205
3340
  setSelectedID(undefined)
3206
- },setSelectedID,renderBefore(){const position=pendingScroll
3207
- pendingScroll=undefined
3208
- if(!body||position===undefined)
3209
- return
3210
- if(typeof position==="number")
3211
- body.scrollTo(position)
3212
- else
3213
- body.scrollChildIntoView(`${prefix}.${position}`)
3214
- },renderAfter(){if(body)
3215
- setScrollTop(body.scrollTop)
3216
- },resultHeight:()=>Math.min(Math.max(3,Math.min(16,Math.floor(dimensions().height*0.5)-9)),Math.max(1,results().length*3 + errors().length*2)),theme
3341
+ },setSelectedID,resultHeight:()=>Math.min(Math.max(3,Math.min(16,Math.floor(dimensions().height*0.5)-9)),Math.max(1,results().length*3 + errors().length*2)),theme
3217
3342
  }}
3218
3343
 
3219
3344
 
@@ -3367,7 +3492,7 @@ _$effect((_$p)=>_$setProp(_el$2,"fg",model.theme().error,_$p))
3367
3492
  return _el$2
3368
3493
  })()
3369
3494
  }),null)
3370
- _$insert(_el$,_$createComponent(Show2,{get when(){return model.results().length
3495
+ _$insert(_el$,_$createComponent(Show3,{get when(){return model.results().length
3371
3496
  },get fallback(){return(()=>{var _el$8=_$createElement("text"),_el$9=_$createTextNode(` `)
3372
3497
  _$insertNode(_el$8,_el$9)
3373
3498
  _$insert(_el$8,()=>model.icons.icon(model.loading()?"pending":"search"),_el$9)
@@ -3375,20 +3500,18 @@ _$insert(_el$8,()=>model.loading()?"Loading sources\u2026":"No matching results"
3375
3500
  _$effect((_$p)=>_$setProp(_el$8,"fg",model.theme().textMuted,_$p))
3376
3501
  return _el$8
3377
3502
  })()
3378
- },get children(){return _$createComponent(Show2,{keyed:true,get when(){return model.queryScope()
3503
+ },get children(){return _$createComponent(Show3,{keyed:true,get when(){return model.queryScope()
3379
3504
  },children:(_scope)=>_$createComponent(For3,{get each(){return model.results().map((item)=>item.id)
3380
3505
  },children:(id)=>_$createComponent(SearchResultRow,{model,id
3381
3506
  })
3382
3507
  })
3383
3508
  })
3384
3509
  }}),null)
3385
- _$effect((_p$)=>{var _v$=`${model.prefix}.results`,{renderBefore:_v$2,renderAfter:_v$3}=model,_v$4=model.resultHeight()
3510
+ _$effect((_p$)=>{var _v$=`${model.prefix}.results`,_v$2=model.resultHeight()
3386
3511
  _v$!==_p$.e&&(_p$.e=_$setProp(_el$,"id",_v$,_p$.e))
3387
- _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"renderBefore",_v$2,_p$.t))
3388
- _v$3!==_p$.a&&(_p$.a=_$setProp(_el$,"renderAfter",_v$3,_p$.a))
3389
- _v$4!==_p$.o&&(_p$.o=_$setProp(_el$,"height",_v$4,_p$.o))
3512
+ _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"height",_v$2,_p$.t))
3390
3513
  return _p$
3391
- },{e:undefined,t:undefined,a:undefined,o:undefined
3514
+ },{e:undefined,t:undefined
3392
3515
  })
3393
3516
  return _el$
3394
3517
  })()
@@ -3435,9 +3558,9 @@ createEffect7(()=>{const key=props.preferences.searchKey()
3435
3558
  const remove=props.api.keymap.registerLayer({mode:"base",bindings:[{key,cmd:SEARCH_COMMAND
3436
3559
  }]
3437
3560
  })
3438
- onCleanup7(remove)
3561
+ onCleanup9(remove)
3439
3562
  })
3440
- onCleanup7(()=>{isDisposed=true
3563
+ onCleanup9(()=>{isDisposed=true
3441
3564
  unregister()
3442
3565
  for(const timer of timers)
3443
3566
  clearTimeout(timer)
@@ -3474,21 +3597,6 @@ return value&&valid()&&!blocked()?controller.applyPreset(name,value,target):unde
3474
3597
 
3475
3598
 
3476
3599
 
3477
- var defaults={todo:true,lsp:true}
3478
- var capabilities=new WeakMap
3479
- function setHostCapabilities(api,value){capabilities.set(api,value)
3480
- }
3481
- function hostCapabilities(api){return capabilities.get(api)??defaults
3482
- }
3483
- function hostCapabilityUnavailable(api,section){return section==="todo"||section==="lsp"?hostCapabilities(api).unavailable?.[section]:undefined
3484
- }
3485
- function supportsSidebarSection(api,section){const current=hostCapabilities(api)
3486
- return section!=="todo"&&section!=="lsp"?true:current[section]
3487
- }
3488
- function supportsTitleVisibility(api){return hostCapabilities(api).titleVisibility!==false
3489
- }
3490
- function supportsPermissionMode(api){return hostCapabilities(api).permissionMode!==false
3491
- }
3492
3600
  var ONBOARDING_STEPS=[{title:"A control center that stays compact",summary:"Navigator brings session state, search, and controls into OpenCode's existing sidebar.",icon:"help",features:[{icon:"sections",title:"Progressive disclosure",description:"Expand only the context you need right now."},{icon:"scope",title:"Current context",description:"Follow the active session, workspace, and worktree."},{icon:"actions",title:"Mouse and keyboard",description:"Use the same controls with either input method."}]
3493
3601
  },{title:"Stay oriented while agents work",summary:"Keep current work visible without turning the sidebar into another dashboard.",icon:"todo",features:[{icon:"todo",title:"Todo filters",description:"Separate active, finished, and cancelled work."},{icon:"subagents",title:"Live subagents",description:"See running, retrying, recent, and failed child sessions; open them directly."
3494
3602
  },{icon:"info",title:"Provider limits",description:"Link a matching Codex account for model quotas and confirmed banked resets."
@@ -3668,8 +3776,8 @@ return _el$
3668
3776
  }
3669
3777
  function FirstRunWizard(props){const icons=useIcons()
3670
3778
  const dialogs=useDialogs(props.api)
3671
- const [active,setActive]=createSignal14(0)
3672
- const [step,setStep]=createSignal14(0)
3779
+ const [active,setActive]=createSignal13(0)
3780
+ const [step,setStep]=createSignal13(0)
3673
3781
  const theme=()=>props.api.theme.current
3674
3782
  const sections=SECTION_DEFINITIONS.filter((section)=>supportsSidebarSection(props.api,section.name))
3675
3783
  const finishIndex=sections.length
@@ -3710,7 +3818,7 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
3710
3818
  },{key:"return",cmd:`${PLUGIN_ID}.wizard.select`
3711
3819
  }]
3712
3820
  })
3713
- onCleanup8(unregister)
3821
+ onCleanup10(unregister)
3714
3822
  return _$createComponent(DialogSurface,{get api(){return props.api
3715
3823
  },get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` Navigator setup`),_el$4=_$createElement("text"),_el$5=_$createTextNode(`Step `),_el$6=_$createTextNode(`/`),_el$7=_$createTextNode(` \xB7 `)
3716
3824
  _$insertNode(_el$,_el$2)
@@ -3737,7 +3845,7 @@ return _p$
3737
3845
  },{e:undefined,t:undefined,a:undefined
3738
3846
  })
3739
3847
  return _el$
3740
- })(),_$createComponent(Show3,{get when(){return configuring()
3848
+ })(),_$createComponent(Show4,{get when(){return configuring()
3741
3849
  },get fallback(){return _$createComponent(OnboardingStep,{get api(){return props.api
3742
3850
  },get preferences(){return props.preferences
3743
3851
  },get step(){return ONBOARDING_STEPS[step()]
@@ -3794,7 +3902,7 @@ _$insertNode(_el$,_el$6)
3794
3902
  _$setProp(_el$,"flexDirection","row")
3795
3903
  _$setProp(_el$,"justifyContent","space-between")
3796
3904
  _$setProp(_el$2,"flexGrow",1)
3797
- _$insert(_el$2,_$createComponent(Show4,{get when(){return props.onRefresh
3905
+ _$insert(_el$2,_$createComponent(Show5,{get when(){return props.onRefresh
3798
3906
  },get children(){var _el$3=_$createElement("text"),_el$4=_$createTextNode(` Refresh (`),_el$5=_$createTextNode(`)`)
3799
3907
  _$insertNode(_el$3,_el$4)
3800
3908
  _$insertNode(_el$3,_el$5)
@@ -3855,9 +3963,9 @@ return _el$
3855
3963
  function PresetPreviewFrame(props){const icons=useIcons()
3856
3964
  const dialogs=useDialogs(props.api)
3857
3965
  const theme=()=>props.api.theme.current
3858
- const dimensions=useTerminalDimensions4()
3966
+ const dimensions=useTerminalDimensions6()
3859
3967
  const scroll=useDialogScroll()
3860
- const [active,setActive]=createSignal15("apply")
3968
+ const [active,setActive]=createSignal14("apply")
3861
3969
  let body
3862
3970
  const prefix=`${PLUGIN_ID}.preset-preview`
3863
3971
  function activate(action){if(!props.valid()){dialogs.close()
@@ -3886,7 +3994,7 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
3886
3994
  },{key:"ctrl+r",cmd:`${prefix}.refresh`
3887
3995
  }]
3888
3996
  })
3889
- onCleanup9(unregister)
3997
+ onCleanup11(unregister)
3890
3998
  createEffect8(()=>{if(!props.valid())
3891
3999
  dialogs.close()
3892
4000
  })
@@ -3926,15 +4034,9 @@ _$setProp(_el$5,"contentOptions",{minHeight:0
3926
4034
  })
3927
4035
  _$setProp(_el$6,"gap",1)
3928
4036
  _$insert(_el$6,()=>props.children)
3929
- _$effect((_p$)=>{var{restore:_v$3,save:_v$4}=scroll,_v$5=Math.min(Math.max(2,Math.floor(dimensions().height*0.75)-14),Math.max(1,props.rowCount*3-1))
3930
- _v$3!==_p$.e&&(_p$.e=_$setProp(_el$5,"renderBefore",_v$3,_p$.e))
3931
- _v$4!==_p$.t&&(_p$.t=_$setProp(_el$5,"renderAfter",_v$4,_p$.t))
3932
- _v$5!==_p$.a&&(_p$.a=_$setProp(_el$5,"height",_v$5,_p$.a))
3933
- return _p$
3934
- },{e:undefined,t:undefined,a:undefined
3935
- })
4037
+ _$effect((_$p)=>_$setProp(_el$5,"height",Math.min(Math.max(2,Math.floor(dimensions().height*0.75)-14),Math.max(1,props.rowCount*3-1)),_$p))
3936
4038
  return _el$5
3937
- })(),_$createComponent(Show5,{get when(){return props.blocked||props.notice
4039
+ })(),_$createComponent(Show6,{get when(){return props.blocked||props.notice
3938
4040
  },get children(){var _el$7=_$createElement("box"),_el$8=_$createElement("text"),_el$9=_$createElement("text")
3939
4041
  _$insertNode(_el$7,_el$8)
3940
4042
  _$insertNode(_el$7,_el$9)
@@ -3946,9 +4048,9 @@ _$setProp(_el$9,"flexGrow",1)
3946
4048
  _$setProp(_el$9,"wrapMode","word")
3947
4049
  _$setProp(_el$9,"height",2)
3948
4050
  _$insert(_el$9,()=>props.blocked||props.notice)
3949
- _$effect((_p$)=>{var _v$6=props.blocked?theme().warning:theme().accent,_v$7=props.blocked?theme().warning:theme().textMuted
3950
- _v$6!==_p$.e&&(_p$.e=_$setProp(_el$8,"fg",_v$6,_p$.e))
3951
- _v$7!==_p$.t&&(_p$.t=_$setProp(_el$9,"fg",_v$7,_p$.t))
4051
+ _$effect((_p$)=>{var _v$3=props.blocked?theme().warning:theme().accent,_v$4=props.blocked?theme().warning:theme().textMuted
4052
+ _v$3!==_p$.e&&(_p$.e=_$setProp(_el$8,"fg",_v$3,_p$.e))
4053
+ _v$4!==_p$.t&&(_p$.t=_$setProp(_el$9,"fg",_v$4,_p$.t))
3952
4054
  return _p$
3953
4055
  },{e:undefined,t:undefined
3954
4056
  })
@@ -4146,78 +4248,159 @@ dialogs.open(()=>_$createComponent(SelectionMenu,{api,title:"MCP presets",get op
4146
4248
 
4147
4249
 
4148
4250
 
4251
+ var Content=lazy3(async ()=>{const path=import.meta.url.includes("/dist/")?"./sidebar-settings.js":"./settings-dialog-content"
4252
+ const module=await import(path)
4253
+ return{default:module.SettingsDialog
4254
+ }})
4255
+ function SettingsDialog(props){return(()=>{var _el$=_$createElement("box")
4256
+ _$insert(_el$,_$createComponent(Suspense3,{get children(){return _$createComponent(Content,props)
4257
+ }}))
4258
+ return _el$
4259
+ })()
4260
+ }
4261
+ function openSettings(api,preferences,activeValue,mcp,skills){createDialogStack(api,preferences.lspIconStyle,()=>true,preferences.cornerFont).open(()=>_$createComponent(SettingsDialog,{api,preferences,mcp,skills,activeValue
4262
+ }),"xlarge")
4263
+ }
4149
4264
 
4150
4265
 
4266
+ async function load(input){const path=import.meta.url.includes("/dist/")?"./toolbar-settings.js":"./open-toolbar"
4267
+ try{return await import(path)
4268
+ } catch(error){input.api.ui.toast({variant:"error",title:"Toolbar",message:String(error)})
4269
+ return
4270
+ }}
4271
+ async function openToolbarManager(input){const route=JSON.stringify(input.api.route.current)
4272
+ const target=input.skills?.target().key
4273
+ const wasOpen=input.api.ui.dialog.open
4274
+ const module=await load(input)
4275
+ if(route===JSON.stringify(input.api.route.current)&&target===input.skills?.target().key&&(!wasOpen||input.api.ui.dialog.open)&&!input.api.lifecycle?.signal?.aborted)
4276
+ module?.openToolbarManager(input)
4277
+ }
4278
+ async function openToolbarPin(input){const route=JSON.stringify(input.api.route.current)
4279
+ const target=input.skills?.target().key
4280
+ const wasOpen=input.api.ui.dialog.open
4281
+ const module=await load(input)
4282
+ if(route===JSON.stringify(input.api.route.current)&&target===input.skills?.target().key&&(!wasOpen||input.api.ui.dialog.open)&&!input.api.lifecycle?.signal?.aborted)
4283
+ module?.openToolbarPin(input)
4284
+ }
4285
+ function SettingsBinding(props){const unregister=props.api.keymap.registerLayer({mode:"base",commands:[{name:`${PLUGIN_ID}.settings`,title:"Navigator settings",category:"Navigator",namespace:"palette",enabled:()=>["home","session"].includes(props.api.route.current.name),run:()=>openSettings(props.api,props.preferences,undefined,props.mcp,props.skills)
4286
+ },{name:`${PLUGIN_ID}.toolbar`,title:"Manage pinned toolbar",category:"Navigator",namespace:"palette",enabled:()=>["home","session"].includes(props.api.route.current.name),run:()=>{openToolbarManager(props)
4287
+ }}],bindings:[{key:{name:",",ctrl:true
4288
+ },cmd:`${PLUGIN_ID}.settings`
4289
+ }]
4290
+ })
4291
+ onCleanup13(unregister)
4292
+ return _$createElement("box")
4293
+ }
4151
4294
 
4152
4295
 
4296
+ function PermissionModeBinding(props){let applying=false
4297
+ let observed
4298
+ createEffect11(()=>{if(!props.preferences.ready())
4299
+ return
4300
+ const preferred=props.preferences.autoApprovePermissions()
4301
+ const current=currentPermissionMode(props.api)
4302
+ observed=current
4303
+ if(preferred===undefined||current===undefined||current===preferred)
4304
+ return
4305
+ applying=true
4306
+ try{props.api.keymap.dispatchCommand("permission.mode")
4307
+ observed=currentPermissionMode(props.api)
4308
+ } finally{applying=false
4309
+ }})
4310
+ const unsubscribe=props.api.keymap.on?.("state",()=>{if(applying||!props.preferences.ready())
4311
+ return
4312
+ const current=currentPermissionMode(props.api)
4313
+ if(current===undefined||current===observed)
4314
+ return
4315
+ observed=current
4316
+ props.preferences.setAutoApprovePermissions(current)
4317
+ })
4318
+ if(unsubscribe)
4319
+ onCleanup14(unsubscribe)
4320
+ return _$createElement("box")
4321
+ }
4153
4322
 
4154
4323
 
4155
4324
 
4325
+ function SettingsFooterButton(props){const icons=useIcons()
4326
+ const [hovered,setHovered]=createSignal15(false)
4327
+ const theme=()=>props.api.theme.current
4328
+ return _$createComponent(IconControl,{id:`${PLUGIN_ID}.settings.footer`,get icon(){return icons.icon("settings")
4329
+ },get foregroundColor(){return _$memo(()=>!!hovered())()?theme().text:theme().textMuted
4330
+ },get backgroundColor(){return _$memo(()=>!!hovered())()?theme().backgroundElement:theme().backgroundPanel
4331
+ },onMouseOver:()=>setHovered(true),onMouseOut:()=>setHovered(false),onMouseUp:()=>openSettings(props.api,props.preferences,undefined,props.mcp,props.skills)
4332
+ })
4333
+ }
4156
4334
 
4157
4335
 
4158
4336
 
4159
- function behaviorSettingsOptions(api,preferences,icons){const permission=preferences.autoApprovePermissions()
4160
- const permissionDescription=permission?"on for new sessions":"off for new sessions"
4161
- return [...supportsPermissionMode(api)?[{title:`${icons.icon(permission === true ? "checked" : "unchecked")} Default auto-approve permissions`,value:"auto_approve_permissions",description:permission===undefined?"follow OpenCode startup mode":permissionDescription
4162
- }]:[],{title:`${icons.icon(preferences.selectedStartInChat() ? "checked" : "unchecked")} Start new sessions in chat`,value:"start_in_chat",description:preferences.selectedStartInChat()?"skip Home \xB7 on":"show Home \xB7 off"
4163
- },{title:`${icons.icon(preferences.selectedPersistMcp() ? "checked" : "unchecked")} Remember MCP states`,value:"persist_mcp",description:preferences.selectedPersistMcp()?"on":"off"
4164
- },{title:`${icons.icon("settings")} Icon style`,value:"lsp_icon_style",description:preferences.selectedLspIconStyle()==="nerd"?"Nerd Font":"Text fallback"
4165
- },{title:`${icons.icon(preferences.selectedCornerFont() ? "checked" : "unchecked")} Multiline corner font`,value:"corner_font",description:preferences.selectedCornerFont()?"Installed":"Not installed \xB7 rectangular highlights"
4166
- },{title:`${icons.icon("sections")} Row density`,value:"row_density",description:preferences.selectedRowDensity()==="compact"?"Compact":"Comfortable"
4167
- },{title:`${icons.icon("sections")} Sidebar shortcut`,value:"toggle_key",description:preferences.selectedToggleKey()
4168
- },{title:`${icons.icon("selected")} Focus shortcut`,value:"focus_key",description:preferences.selectedFocusKey()
4169
- },{title:`${icons.icon("search")} Search Everything shortcut`,value:"search_key",description:preferences.selectedSearchKey?.()??DEFAULT_SEARCH_KEY
4170
- },{title:`${icons.icon("retry")} Limits refresh interval`,value:"limits_refresh",description:`${preferences.selectedLimitsRefreshMinutes()} min \xB7 minimum 1 min`
4171
- }]
4172
- }
4173
- function titleVisibilityOptions(api,preferences,icons){if(!supportsTitleVisibility(api))
4174
- return []
4175
- const title=preferences.selectedShowSessionTitle()
4176
- const date=preferences.selectedShowSessionDate()
4177
- return [{title:`${icons.icon(title ? "checked" : "unchecked")} Session title`,value:"session_title",description:title?"visible":"hidden"
4178
- },{title:`${icons.icon(date ? "checked" : "unchecked")} Creation date`,value:"session_date",description:date?"visible":"hidden"
4337
+ var ACTIONS=[{key:"h",label:"Toggle sidebar",icon:"sections",group:"navigate",command:"session.sidebar.toggle",section:undefined
4338
+ },{key:"t",label:"Todo",icon:"todo",group:"navigate",command:`${PLUGIN_ID}.focus.todo`,section:"todo"},{key:"a",label:"Subagents",icon:"subagents",group:"navigate",command:`${PLUGIN_ID}.focus.subagents`,section:"subagents"
4339
+ },{key:"s",label:"Skills",icon:"skills",group:"navigate",command:`${PLUGIN_ID}.focus.skills`,section:"skills"
4340
+ },{key:"q",label:"Quick actions",icon:"actions",group:"navigate",command:`${PLUGIN_ID}.focus.quick_actions`,section:"quick_actions"
4341
+ },{key:"l",label:"LSP",icon:"lsp",group:"navigate",command:`${PLUGIN_ID}.focus.lsp`,section:"lsp"},{key:"m",label:"MCP",icon:"mcp",group:"navigate",command:`${PLUGIN_ID}.focus.mcp`,section:"mcp"},{key:"c",label:"Check update",icon:"search",group:"updates",command:`${PLUGIN_ID}.check-update`,section:undefined
4342
+ },{key:"u",label:"Update Navigator",icon:"update",group:"updates",command:`${PLUGIN_ID}.update-navigator`,section:undefined
4179
4343
  }]
4344
+ function sidebarShortcutActions(api){return ACTIONS.filter(({section})=>!section||supportsSidebarSection(api,section))
4180
4345
  }
4181
- function createSettingsGroups(api,preferences,icons){const supportedSections=()=>SIDEBAR_SECTIONS.filter((name)=>supportsSidebarSection(api,name))
4182
- const groups=createMemo7(()=>[{id:"scope",tab:"Scope",title:"Preference scope",options:[{title:`${icons.icon(preferences.preferenceScope() === "global" ? "radioOn" : "radioOff")} Global`,value:"scope:global",description:"applies to every worktree"
4183
- },{title:`${icons.icon(preferences.preferenceScope() === "worktree" ? "radioOn" : "radioOff")} Current worktree`,value:"scope:worktree",description:preferences.canUseWorktreeScope()?preferences.preferenceScopeLabel():"unavailable outside a worktree"
4184
- }]
4185
- },{id:"presets",tab:"Presets",title:"Layout presets",options:[...Object.keys(preferences.layoutPresets()).sort((left,right)=>left.localeCompare(right)).map((name)=>({title:`${icons.icon("presets")} ${name}`,value:`preset:custom:${encodeURIComponent(name)}`,description:preferences.workspaceProfiles?.()[name]?`profile \xB7 ${preferences.workspaceProfiles()[name]}`:"enter to apply or edit"
4186
- })),{title:`${icons.icon("add")} Save as\u2026`,value:"save_preset",description:"create a preset from the current layout"
4187
- }]
4188
- },{id:"sections",tab:"Sections",title:"Sections & order",options:[...titleVisibilityOptions(api,preferences,icons),...preferences.selectedSectionOrder().filter((name)=>supportsSidebarSection(api,name)).map((name,index)=>{const section=SECTION_DEFINITIONS.find((candidate)=>candidate.name===name)
4189
- return{title:`${icons.icon(preferences.selectedSections()[section.name] ? "checked" : "unchecked")} ${index + 1}. ${icons.section(section.name)} ${section.label}`,value:section.name,description:preferences.selectedSections()[section.name]?"visible":"hidden"
4190
- }})]
4191
- },{id:"behavior",tab:"Behavior",title:"Behavior",options:behaviorSettingsOptions(api,preferences,icons)
4192
- },{id:"defaults",tab:"Defaults",title:"Defaults & help",options:[{title:`${icons.icon("save")} Save current layout as default`,value:"save_layout",description:`${supportedSections().filter((name) => preferences.selectedSections()[name]).length} visible \xB7 ${supportedSections().filter((name) => preferences.selectedExpanded()[name]).length} expanded`
4193
- },{title:`${icons.icon("export")} Copy portable settings`,value:"export_settings",description:"versioned layout and MCP JSON"
4194
- },{title:`${icons.icon("add")} Import portable settings\u2026`,value:"import_settings",description:"preview pasted JSON before applying"
4195
- },{title:`${icons.icon("retry")} Reload settings from file`,value:"reload_settings",description:"sync saved changes from other OpenCode sessions"
4196
- },{title:`${icons.icon("reset")} Restore configured layout`,value:"reset_sections",description:"visibility and expansion"
4197
- },{title:`${icons.icon("reset")} Restore configured behavior`,value:"reset_settings",description:"startup, MCP memory, icons, shortcuts, limits, actions"
4198
- },{title:`${icons.icon("reset")} Clear remembered MCP states`,value:"reset_mcp",description:`scope: ${preferences.preferenceScopeLabel()}`
4199
- },{title:`${icons.section("skills")} Manage trusted skills`,value:"trusted_skills",description:`${preferences.skippedSkillCount()} trusted`
4200
- },{title:`${icons.icon("help")} Open quick setup guide`,value:"wizard",description:"tips and section settings"
4201
- }]
4202
- }])
4203
- const orderedGroups=createMemo7(()=>["sections","scope","presets","behavior","defaults"].map((id)=>groups().find((group)=>group.id===id)))
4204
- return orderedGroups
4346
+ var ENTRY_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.enter`
4347
+ var CANCEL_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.cancel`
4348
+ var MODE=`${PLUGIN_ID}.sidebar-shortcuts`
4349
+ var DEFAULT_TIMEOUT_MS=5000
4350
+ function createSidebarShortcutMode(api,options={}){const actions=sidebarShortcutActions(api)
4351
+ const [active,setActive]=createSignal16(false)
4352
+ const timeoutMs=options.timeoutMs??DEFAULT_TIMEOUT_MS
4353
+ let shortcutKey=""
4354
+ let unregisterBinding
4355
+ let unregisterMode
4356
+ let leaveMode
4357
+ let timeout
4358
+ let disposed=false
4359
+ function cancel(){if(timeout)
4360
+ clearTimeout(timeout)
4361
+ timeout=undefined
4362
+ unregisterMode?.()
4363
+ unregisterMode=undefined
4364
+ leaveMode?.()
4365
+ leaveMode=undefined
4366
+ setActive(false)
4205
4367
  }
4206
- function registerSettingsKeymap(input){return input.api.keymap.registerLayer({mode:"modal",priority:1000,commands:[{name:`${PLUGIN_ID}.settings.previous`,run:()=>input.move(-1)},{name:`${PLUGIN_ID}.settings.next`,run:()=>input.move(1)},{name:`${PLUGIN_ID}.settings.select`,run:()=>input.select()},{name:`${PLUGIN_ID}.settings.groups`,run:()=>{if(input.activeGroup()!=="sections")
4368
+ function run(command){cancel()
4369
+ if(api.route.current.name!=="session"||api.ui?.dialog?.open)
4207
4370
  return
4208
- if(input.options()[input.active()]?.value==="mcp")
4209
- input.openMcpGroups()
4210
- if(input.options()[input.active()]?.value==="skills")
4211
- input.openSkillGroups()
4212
- }},{name:`${PLUGIN_ID}.settings.quick-actions`,run:()=>{if(input.activeGroup()==="sections"&&input.options()[input.active()]?.value==="quick_actions")
4213
- input.openQuickActions()
4214
- }},{name:`${PLUGIN_ID}.settings.item-limit`,run:()=>{const section=input.options()[input.active()]?.value
4215
- if(input.activeGroup()==="sections"&&SIDEBAR_SECTIONS.includes(section))
4216
- input.openLimitPrompt(section)
4217
- }},{name:`${PLUGIN_ID}.settings.previous-tab`,run:()=>input.switchGroup(-1)},{name:`${PLUGIN_ID}.settings.next-tab`,run:()=>input.switchGroup(1)},{name:`${PLUGIN_ID}.settings.move-up`,run:()=>input.reorder(input.options()[input.active()]?.value,-1)},{name:`${PLUGIN_ID}.settings.move-down`,run:()=>input.reorder(input.options()[input.active()]?.value,1)}],bindings:[{key:"up",cmd:`${PLUGIN_ID}.settings.previous`},{key:"down",cmd:`${PLUGIN_ID}.settings.next`},{key:"tab",cmd:`${PLUGIN_ID}.settings.next-tab`},{key:"shift+tab",cmd:`${PLUGIN_ID}.settings.previous-tab`},{key:"space",cmd:`${PLUGIN_ID}.settings.select`},{key:"return",cmd:`${PLUGIN_ID}.settings.select`},{key:"l",cmd:`${PLUGIN_ID}.settings.item-limit`},{key:"a",cmd:`${PLUGIN_ID}.settings.quick-actions`},{key:"g",cmd:`${PLUGIN_ID}.settings.groups`},{key:"left",cmd:`${PLUGIN_ID}.settings.move-up`},{key:"right",cmd:`${PLUGIN_ID}.settings.move-down`},{key:"shift+up",cmd:`${PLUGIN_ID}.settings.move-up`},{key:"shift+down",cmd:`${PLUGIN_ID}.settings.move-down`}]
4371
+ return api.keymap.dispatchCommand(command)
4372
+ }
4373
+ function enter(){if(disposed||api.route.current.name!=="session"||api.ui?.dialog?.open)
4374
+ return false
4375
+ cancel()
4376
+ unregisterMode=api.keymap.registerLayer({mode:MODE,priority:2000,commands:[{name:ENTRY_COMMAND,run:enter},{name:CANCEL_COMMAND,run:cancel},...actions.map(({key,command})=>({name:`${MODE}.${key}`,run:()=>run(command)
4377
+ }))],bindings:[{key:"escape",cmd:CANCEL_COMMAND},{key:shortcutKey,cmd:ENTRY_COMMAND},...actions.map(({key})=>({key,cmd:`${MODE}.${key}`}))]
4218
4378
  })
4379
+ leaveMode=api.mode.push(MODE)
4380
+ timeout=setTimeout(cancel,timeoutMs)
4381
+ setActive(true)
4382
+ return true
4219
4383
  }
4384
+ const unregisterCommands=api.keymap.registerLayer({mode:"base",commands:[{name:TOGGLE_COMMAND,title:"Toggle sidebar",category:"Navigator",namespace:"palette",enabled:()=>api.route.current.name==="session"&&!api.ui?.dialog?.open,run:()=>api.keymap.dispatchCommand("session.sidebar.toggle")
4385
+ },{name:`${LEGACY_PLUGIN_ID}.toggle`,run:()=>api.keymap.dispatchCommand("session.sidebar.toggle")
4386
+ },{name:ENTRY_COMMAND,enabled:()=>api.route.current.name==="session"&&!api.ui?.dialog?.open,run:enter
4387
+ }]
4388
+ })
4389
+ return{active,actions,bind(key){cancel()
4390
+ unregisterBinding?.()
4391
+ shortcutKey=key
4392
+ unregisterBinding=api.keymap.registerLayer({mode:"base",bindings:[{key,cmd:ENTRY_COMMAND}]
4393
+ })
4394
+ },enter,cancel,dispose(){disposed=true
4395
+ cancel()
4396
+ unregisterBinding?.()
4397
+ unregisterBinding=undefined
4398
+ unregisterCommands()
4399
+ }}}
4220
4400
 
4401
+ var SidebarShortcutHint=lazy4(()=>{const path=import.meta.url.includes("/dist/tui.js")?"./sidebar-shortcuts.js":"../../../sidebar-shortcuts"
4402
+ return import(path)
4403
+ });
4221
4404
 
4222
4405
 
4223
4406
 
@@ -4228,579 +4411,98 @@ input.openLimitPrompt(section)
4228
4411
 
4229
4412
 
4230
4413
 
4231
- function openLimitsRefreshPrompt(api,preferences,dialogs){const scope=preferences.preferenceScopeLabel()
4232
- dialogs.prompt({title:"Limits refresh interval",description:()=>(()=>{var _el$=_$createElement("text")
4233
- _$insertNode(_el$,_$createTextNode(`Automatic refresh in minutes (minimum 1; default 5). Manual Refresh stays immediate.`))
4234
- _$effect((_$p)=>_$setProp(_el$,"fg",api.theme.current.textMuted,_$p))
4235
- return _el$
4236
- })(),value:String(preferences.selectedLimitsRefreshMinutes()),onConfirm(value){if(preferences.preferenceScopeLabel()!==scope)
4237
- throw new Error("Preference scope changed; reopen this setting")
4238
- if(!/^\d+$/.test(value.trim()))
4239
- throw new Error("Enter whole minutes (at least 1 minute)")
4240
- preferences.setLimitsRefreshMinutes(Number(value))
4241
- dialogs.back()
4242
- }})
4243
- }
4244
- function createSettingsSelection(input){const dialogClosed=()=>("open" in input.api.ui.dialog)&&!input.api.ui.dialog.open
4245
- function openLimitPrompt(section){const index=input.options().findIndex((option)=>option.value===section)
4246
- if(index!==-1)
4247
- input.setActive(index)
4248
- input.dialogs.prompt({title:`${SECTION_DEFINITIONS.find((item) => item.name === section).label} item limit`,description:()=>(()=>{var _el$=_$createElement("text")
4249
- _$insertNode(_el$,_$createTextNode(`Visible items before Show all. Enter 0 for All.`))
4250
- _$effect((_$p)=>_$setProp(_el$,"fg",input.api.theme.current.textMuted,_$p))
4251
- return _el$
4252
- })(),value:String(input.preferences.selectedSectionItemLimit(section)),onConfirm(value){if(!/^\d+$/.test(value.trim()))
4253
- throw new Error("Enter a non-negative whole number (0 for All)")
4254
- input.preferences.setSectionItemLimit(section,Number(value))
4255
- input.dialogs.back()
4256
- }})
4414
+
4415
+
4416
+
4417
+
4418
+
4419
+
4420
+
4421
+
4422
+
4423
+
4424
+
4425
+
4426
+
4427
+
4428
+
4429
+
4430
+ import {realpathSync} from "fs"
4431
+ function routeKey(api){const route=api.route.current
4432
+ return `${route.name}:${"params" in route ? route.params?.sessionID ?? "" : ""}`
4257
4433
  }
4258
- function openShortcut(value){const bindings={toggle_key:{title:"Sidebar shortcut",get:input.preferences.selectedToggleKey,set:input.preferences.setToggleKey
4259
- },focus_key:{title:"Focus shortcut",get:input.preferences.selectedFocusKey,set:input.preferences.setFocusKey
4260
- },search_key:{title:"Search Everything shortcut",get:input.preferences.selectedSearchKey,set:input.preferences.setSearchKey
4434
+ function sameLocation(left,right){function canonical(path){try{return realpathSync(path)
4435
+ } catch{return path
4261
4436
  }}
4262
- const binding=bindings[value]
4263
- input.dialogs.prompt({title:binding.title,description:()=>(()=>{var _el$3=_$createElement("text")
4264
- _$insertNode(_el$3,_$createTextNode(`Use OpenCode key syntax, for example alt+s.`))
4265
- _$effect((_$p)=>_$setProp(_el$3,"fg",input.api.theme.current.textMuted,_$p))
4266
- return _el$3
4267
- })(),value:binding.get(),onConfirm(key){binding.set(key)
4268
- input.dialogs.back()
4269
- }})
4437
+ return canonical(left.routing.directory)===canonical(right.routing.directory)&&left.routing.workspace===right.routing.workspace
4270
4438
  }
4271
- function saveLayout(){input.preferences.saveLayoutAsDefault().then(()=>input.api.ui.toast({variant:"success",title:"Navigator settings",message:"Current layout saved as default",duration:3000
4272
- })).catch((error)=>input.api.ui.toast({variant:"error",title:"Navigator settings",message:error instanceof Error?error.message:"Failed to save the default layout",duration:5000
4273
- }))
4439
+ function createStartupSessionController(api,preferences){let initialized=false
4440
+ let pending=false
4441
+ let retry
4442
+ let disposed=false
4443
+ function enabled(){const location=currentLocation(api)
4444
+ return preferences.ready()&&!pending&&!api.ui.dialog.open&&preferences.startInChatForScope(location.routing.directory)
4274
4445
  }
4275
- function exportSettings(){const copied=input.api.renderer.copyToClipboardOSC52(input.preferences.exportPortableSettings())
4276
- input.api.ui.toast({variant:copied?"success":"warning",title:"Portable settings",message:copied?"Layout and MCP settings copied as JSON":"Terminal clipboard is unavailable",duration:4000
4446
+ async function start(){if(!enabled())
4447
+ return
4448
+ const location=currentLocation(api)
4449
+ const originalRoute=routeKey(api)
4450
+ pending=true
4451
+ try{const result=await api.client.session.create({directory:location.routing.directory,...location.routing.workspace&&{workspace:location.routing.workspace}},{signal:api.lifecycle.signal})
4452
+ if(result.error||!result.data)
4453
+ throw result.error??new Error("Session creation returned no session")
4454
+ if(!api.lifecycle.signal?.aborted&&routeKey(api)===originalRoute&&sameLocation(currentLocation(api),location)&&preferences.startInChatForScope(location.routing.directory)){api.route.navigate("session",{sessionID:result.data.id})
4455
+ }} catch(error){if(!api.lifecycle.signal?.aborted)
4456
+ api.ui.toast({variant:"error",title:"New session",message:error instanceof Error?error.message:"Could not create a session",duration:5000
4277
4457
  })
4278
- }
4279
- function importSettings(){const path=import.meta.url.includes("/dist/tui.js")?"./settings-import.js":"../ui/settings-import-dialog"
4280
- import(path).then((module)=>{if(!dialogClosed())
4281
- module.openSettingsImport(input)
4282
- }).catch((error)=>input.api.ui.toast({variant:"error",title:"Portable settings",message:String(error)
4283
- }))
4284
- }
4285
- function select(value=input.options()[input.active()]?.value){if(!value)
4458
+ } finally{pending=false
4459
+ }}
4460
+ async function initialize(){if(initialized)
4461
+ return
4462
+ initialized=true
4463
+ if(api.route.current.name!=="home")
4464
+ return
4465
+ const location=currentLocation(api)
4466
+ await preferences.load()
4467
+ if(api.route.current.name!=="home"||!sameLocation(currentLocation(api),location))
4468
+ return
4469
+ function tryStart(){if(disposed||api.route.current.name!=="home"||!sameLocation(currentLocation(api),location))
4470
+ return
4471
+ if(api.ui.dialog.open){retry=setTimeout(tryStart,200)
4286
4472
  return
4287
- const index=input.options().findIndex((option)=>option.value===value)
4288
- if(index!==-1)
4289
- input.setActive(index)
4290
- if(value==="scope:global"||value==="scope:worktree")
4291
- input.preferences.setPreferenceScope(value==="scope:global"?"global":"worktree")
4292
- else if(value.startsWith("preset:custom:"))
4293
- input.openPreset(decodeURIComponent(value.slice("preset:custom:".length)))
4294
- else
4295
- switch(value){case "save_preset":{input.promptPreset()
4296
- break
4297
- }
4298
- case "save_layout":{saveLayout()
4299
- break
4300
4473
  }
4301
- case "export_settings":{exportSettings()
4302
- break
4474
+ start()
4303
4475
  }
4304
- case "import_settings":{importSettings()
4305
- break
4476
+ queueMicrotask(tryStart)
4306
4477
  }
4307
- case "reload_settings":{input.preferences.reloadFromFile().then(()=>input.api.ui.toast({variant:"success",title:"Navigator settings",message:"Saved settings reloaded",duration:3000
4308
- })).catch((error)=>input.api.ui.toast({variant:"error",title:"Navigator settings",message:error instanceof Error?error.message:"Could not reload saved settings",duration:5000
4309
- }))
4310
- break
4478
+ return{enabled,initialize,start,handleNewSession(){if(!enabled())
4479
+ return false
4480
+ start()
4481
+ return true
4482
+ },dispose(){disposed=true
4483
+ clearTimeout(retry)
4484
+ }}}
4485
+
4486
+
4487
+ function StartupSessionBinding(props){if(props.api.keymap.on){const unregister=props.api.keymap.on("dispatch",(event)=>{if(event.phase!=="binding-execute"||event.command!=="session.new")
4488
+ return
4489
+ queueMicrotask(()=>void props.controller.start())
4490
+ })
4491
+ onCleanup15(unregister)
4492
+ } else
4493
+ createEffect12(()=>{if(!props.controller.enabled())
4494
+ return
4495
+ const unregister=props.api.keymap.registerLayer({mode:"global",priority:2001,commands:[{name:"session.new",title:"New session",category:"Session",namespace:"palette",enabled:props.controller.enabled,run:()=>void props.controller.start()
4496
+ }]
4497
+ })
4498
+ onCleanup15(unregister)
4499
+ })
4500
+ onMount4(()=>void props.controller.initialize())
4501
+ onCleanup15(props.controller.dispose)
4502
+ return _$createElement("box")
4311
4503
  }
4312
- case "reset_sections":{input.preferences.resetSections()
4313
- break
4314
- }
4315
- case "session_title":{input.preferences.toggleSessionTitleVisibility()
4316
- break
4317
- }
4318
- case "session_date":{input.preferences.toggleSessionDateVisibility()
4319
- break
4320
- }
4321
- case "persist_mcp":{input.preferences.toggleMcpPersistence()
4322
- break
4323
- }
4324
- case "limits_refresh":{openLimitsRefreshPrompt(input.api,input.preferences,input.dialogs)
4325
- break
4326
- }
4327
- case "start_in_chat":{input.preferences.toggleStartInChat()
4328
- break
4329
- }
4330
- case "auto_approve_permissions":{input.preferences.setAutoApprovePermissions(input.preferences.autoApprovePermissions()!==true)
4331
- break
4332
- }
4333
- case "lsp_icon_style":{input.preferences.toggleLspIconStyle()
4334
- break
4335
- }
4336
- case "corner_font":{input.preferences.toggleCornerFont()
4337
- break
4338
- }
4339
- case "row_density":{input.preferences.toggleRowDensity()
4340
- break
4341
- }
4342
- case "toggle_key":{openShortcut("toggle_key")
4343
- break
4344
- }
4345
- case "focus_key":{openShortcut("focus_key")
4346
- break
4347
- }
4348
- case "search_key":{openShortcut("search_key")
4349
- break
4350
- }
4351
- case "reset_settings":{input.preferences.resetPluginSettings()
4352
- break
4353
- }
4354
- case "reset_mcp":{input.preferences.resetMcpStates()
4355
- break
4356
- }
4357
- case "trusted_skills":{const path=import.meta.url.includes("/dist/tui.js")?"./trusted-skills.js":"../ui/trusted-skills-dialog"
4358
- import(path).then((module)=>{if(dialogClosed())
4359
- return
4360
- const{TrustedSkillsDialog
4361
- }=module
4362
- input.dialogs.open(()=>_$createComponent(TrustedSkillsDialog,{get api(){return input.api
4363
- },get preferences(){return input.preferences
4364
- }}))
4365
- }).catch((error)=>input.api.ui.toast({variant:"error",title:"Trusted skills",message:String(error)
4366
- }))
4367
- break
4368
- }
4369
- case "wizard":{input.dialogs.open(()=>_$createComponent(FirstRunWizard,{get api(){return input.api
4370
- },get preferences(){return input.preferences
4371
- }}))
4372
- break
4373
- }
4374
- default:{input.preferences.toggleSelectedSection(value)
4375
- }}}
4376
- function openQuickActions(){input.setActive(input.options().findIndex((option)=>option.value==="quick_actions"))
4377
- const path=import.meta.url.includes("/dist/tui.js")?"./quick-actions-settings.js":"../ui/quick-actions-dialog"
4378
- import(path).then((module)=>{if(dialogClosed())
4379
- return
4380
- const{QuickActionsDialog
4381
- }=module
4382
- input.dialogs.open(()=>_$createComponent(QuickActionsDialog,{get api(){return input.api
4383
- },get preferences(){return input.preferences
4384
- }}))
4385
- }).catch((error)=>{input.api.ui.toast({variant:"error",title:"Quick actions",message:String(error),duration:4000
4386
- })
4387
- })
4388
- }
4389
- function openMcpGroups(){if(!input.mcp)
4390
- return
4391
- input.setActive(input.options().findIndex((option)=>option.value==="mcp"))
4392
- const path=import.meta.url.includes("/dist/tui.js")?"./mcp-groups.js":"../ui/mcp-groups-dialog"
4393
- import(path).then((module)=>{if(dialogClosed())
4394
- return
4395
- const{McpGroupsDialog
4396
- }=module
4397
- input.dialogs.open(()=>_$createComponent(McpGroupsDialog,{get api(){return input.api
4398
- },get preferences(){return input.preferences
4399
- },get mcp(){return input.mcp
4400
- }}))
4401
- }).catch((error)=>{input.api.ui.toast({variant:"error",title:"MCP groups",message:String(error),duration:4000
4402
- })
4403
- })
4404
- }
4405
- function openSkillGroups(){if(!input.skills)
4406
- return
4407
- input.setActive(input.options().findIndex((option)=>option.value==="skills"))
4408
- const path=import.meta.url.includes("/dist/tui.js")?"./skill-groups.js":"../ui/skill-groups-dialog"
4409
- import(path).then((module)=>{if(dialogClosed())
4410
- return
4411
- const{SkillGroupsDialog
4412
- }=module
4413
- input.dialogs.open(()=>_$createComponent(SkillGroupsDialog,{get api(){return input.api
4414
- },get preferences(){return input.preferences
4415
- },get skills(){return input.skills
4416
- }}))
4417
- }).catch((error)=>{input.api.ui.toast({variant:"error",title:"Skill groups",message:String(error),duration:4000
4418
- })
4419
- })
4420
- }
4421
- return{openLimitPrompt,openMcpGroups,openSkillGroups,openQuickActions,select
4422
- }}
4423
- function createSettingsDialogController(props){let body
4424
- const theme=()=>props.api.theme.current
4425
- const icons=useIcons()
4426
- const dialogs=useDialogs(props.api)
4427
- const scroll=useDialogScroll()
4428
- const dimensions=useTerminalDimensions6()
4429
- const bodyHeight=createMemo8(()=>Math.max(4,Math.floor(dimensions().height*0.75)-10))
4430
- const orderedGroups=createSettingsGroups(props.api,props.preferences,icons)
4431
- const initialGroup=orderedGroups().find((group)=>group.options.some((option)=>option.value===props.activeValue))
4432
- const [activeGroup,setActiveGroup]=useDialogState("tab",initialGroup?.id??orderedGroups()[0].id)
4433
- const options=createMemo8(()=>orderedGroups().find((group)=>group.id===activeGroup())?.options??[])
4434
- const optionId=(value)=>`${PLUGIN_ID}.settings.${value}`
4435
- const initialActive=options().findIndex((option)=>option.value===props.activeValue)
4436
- const [active,setActive]=useDialogState("selection",Math.max(0,initialActive))
4437
- createEffect11(()=>{if(active()>=options().length)
4438
- setActive(Math.max(0,options().length-1))
4439
- })
4440
- const contentHeight=createMemo8(()=>Math.min(bodyHeight(),Math.max(1,options().length*2-1)))
4441
- const footerHint=createMemo8(()=>{const common=`${icons.key("tab")} switch \xB7 ${icons.key("up/down")} navigate`
4442
- if(activeGroup()==="sections")
4443
- return `${common} \xB7 ${icons.key("enter")} toggle \xB7 l item limit${options()[active()]?.value === "quick_actions" ? " \xB7 a actions" : ""}${["mcp", "skills"].includes(options()[active()]?.value ?? "") ? " \xB7 g groups" : ""} \xB7 ${icons.key("left/right")} or ${icons.key("shift+up/down")} reorder`
4444
- if(activeGroup()==="presets")
4445
- return `${common} \xB7 ${icons.key("enter")} manage`
4446
- if(activeGroup()==="behavior")
4447
- return `${common} \xB7 ${icons.key("enter")} change`
4448
- if(activeGroup()==="defaults")
4449
- return `${common} \xB7 ${icons.key("enter")} run`
4450
- return `${common} \xB7 ${icons.key("enter")} select`
4451
- })
4452
- onMount4(()=>{queueMicrotask(()=>{const option=options()[active()]
4453
- if(option)
4454
- body?.scrollChildIntoView(optionId(option.value))
4455
- })
4456
- })
4457
- function move(offset){const next=(active() + offset + options().length)%options().length
4458
- setActive(next)
4459
- const option=options()[next]
4460
- if(option)
4461
- body?.scrollChildIntoView(optionId(option.value))
4462
- }
4463
- function switchGroup(offset){const index=orderedGroups().findIndex((group)=>group.id===activeGroup())
4464
- const group=orderedGroups()[(index + offset + orderedGroups().length)%orderedGroups().length]
4465
- setActiveGroup(group.id)
4466
- setActive(0)
4467
- queueMicrotask(()=>{const option=options()[0]
4468
- if(option)
4469
- body?.scrollChildIntoView(optionId(option.value))
4470
- })
4471
- }
4472
- function reorder(value,direction){if(!value||!SIDEBAR_SECTIONS.includes(value))
4473
- return
4474
- props.preferences.moveSelectedSection(value,direction)
4475
- queueMicrotask(()=>{const next=options().findIndex((candidate)=>candidate.value===value)
4476
- if(next===-1)
4477
- return
4478
- setActive(next)
4479
- body?.scrollChildIntoView(optionId(value))
4480
- })
4481
- }
4482
- function runPresetAction(action,name){const path=import.meta.url.includes("/dist/tui.js")?"./layout-preset-actions.js":"./layout-preset-actions"
4483
- import(path).then((module)=>{if("open" in props.api.ui.dialog&&!props.api.ui.dialog.open)
4484
- return
4485
- const factory=module.createLayoutPresetActions
4486
- const actions=factory({api:props.api,preferences:props.preferences,mcp:props.mcp,dialogs
4487
- })
4488
- if(action==="open"&&name)
4489
- actions.open(name)
4490
- else
4491
- actions.prompt()
4492
- }).catch((error)=>props.api.ui.toast({variant:"error",title:"Layout presets",message:String(error)
4493
- }))
4494
- }
4495
- const selection=createSettingsSelection({api:props.api,preferences:props.preferences,mcp:props.mcp,skills:props.skills,dialogs,options,active,setActive,openPreset:(name)=>runPresetAction("open",name),promptPreset:()=>runPresetAction("prompt")
4496
- })
4497
- const unregister=registerSettingsKeymap({api:props.api,active,activeGroup,options,move,switchGroup,reorder,select:selection.select,openQuickActions:selection.openQuickActions,openMcpGroups:selection.openMcpGroups,openSkillGroups:selection.openSkillGroups,openLimitPrompt:selection.openLimitPrompt
4498
- })
4499
- onCleanup11(unregister)
4500
- return{active,activeGroup,contentHeight,dialogs,footerHint,icons,openLimitPrompt:selection.openLimitPrompt,openQuickActions:selection.openQuickActions,openMcpGroups:selection.openMcpGroups,openSkillGroups:selection.openSkillGroups,options,optionId,orderedGroups,reorder,select:selection.select,setActive,setActiveGroup,setBody(node){body=node
4501
- scroll.ref(node)
4502
- },restoreScroll:scroll.restore,saveScroll:scroll.save,theme
4503
- }}
4504
-
4505
-
4506
-
4507
-
4508
-
4509
-
4510
-
4511
-
4512
-
4513
-
4514
- function SettingsOptionRow(props){const model=props.controller
4515
- const index=()=>model.options().findIndex((candidate)=>candidate.value===props.option.value)
4516
- const selected=()=>model.active()===index()
4517
- const section=()=>props.option.value
4518
- return _$createComponent(SelectionBox,{get id(){return model.optionId(props.option.value)
4519
- },flexDirection:"row",gap:2,paddingLeft:1,paddingRight:1,get backgroundColor(){return _$memo(()=>!!selected())()?model.theme().backgroundElement:undefined
4520
- },onMouseOver:()=>model.setActive(index()),onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
4521
- model.select(props.option.value)
4522
- },get children(){return [(()=>{var _el$=_$createElement("text")
4523
- _$setProp(_el$,"flexShrink",0)
4524
- _$insert(_el$,()=>props.option.title)
4525
- _$effect((_p$)=>{var _v$=selected()?TextAttributes15.BOLD:undefined,_v$2=model.theme().text
4526
- _v$!==_p$.e&&(_p$.e=_$setProp(_el$,"attributes",_v$,_p$.e))
4527
- _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"fg",_v$2,_p$.t))
4528
- return _p$
4529
- },{e:undefined,t:undefined
4530
- })
4531
- return _el$
4532
- })(),(()=>{var _el$2=_$createElement("text")
4533
- _$setProp(_el$2,"flexGrow",1)
4534
- _$insert(_el$2,()=>props.option.description)
4535
- _$effect((_$p)=>_$setProp(_el$2,"fg",model.theme().borderSubtle,_$p))
4536
- return _el$2
4537
- })(),_$createComponent(Show6,{get when(){return SIDEBAR_SECTIONS.includes(section())
4538
- },get children(){var _el$3=_$createElement("box"),_el$8=_$createElement("text"),_el$9=_$createTextNode(` Items: `),_el$0=_$createElement("text"),_el$1=_$createElement("text")
4539
- _$insertNode(_el$3,_el$8)
4540
- _$insertNode(_el$3,_el$0)
4541
- _$insertNode(_el$3,_el$1)
4542
- _$setProp(_el$3,"flexDirection","row")
4543
- _$setProp(_el$3,"flexShrink",0)
4544
- _$setProp(_el$3,"gap",1)
4545
- _$insert(_el$3,_$createComponent(Show6,{get when(){return props.option.value==="quick_actions"
4546
- },get children(){var _el$4=_$createElement("text"),_el$5=_$createTextNode(` Actions`)
4547
- _$insertNode(_el$4,_el$5)
4548
- _$setProp(_el$4,"onMouseDown",(event)=>event.stopPropagation())
4549
- _$setProp(_el$4,"onMouseUp",(event)=>{event.stopPropagation()
4550
- model.openQuickActions()
4551
- })
4552
- _$insert(_el$4,()=>model.icons.icon("actions"),_el$5)
4553
- _$effect((_$p)=>_$setProp(_el$4,"fg",model.theme().accent,_$p))
4554
- return _el$4
4555
- }}),_el$8)
4556
- _$insert(_el$3,_$createComponent(Show6,{get when(){return props.option.value==="mcp"||props.option.value==="skills"
4557
- },get children(){var _el$6=_$createElement("text"),_el$7=_$createTextNode(` Groups`)
4558
- _$insertNode(_el$6,_el$7)
4559
- _$setProp(_el$6,"onMouseDown",(event)=>event.stopPropagation())
4560
- _$setProp(_el$6,"onMouseUp",(event)=>{event.stopPropagation()
4561
- if(props.option.value==="skills")
4562
- model.openSkillGroups()
4563
- else
4564
- model.openMcpGroups()
4565
- })
4566
- _$insert(_el$6,()=>model.icons.icon("sections"),_el$7)
4567
- _$effect((_$p)=>_$setProp(_el$6,"fg",model.theme().accent,_$p))
4568
- return _el$6
4569
- }}),_el$8)
4570
- _$insertNode(_el$8,_el$9)
4571
- _$setProp(_el$8,"onMouseDown",(event)=>event.stopPropagation())
4572
- _$setProp(_el$8,"onMouseUp",(event)=>{event.stopPropagation()
4573
- model.openLimitPrompt(section())
4574
- })
4575
- _$insert(_el$8,()=>model.icons.icon("todo"),_el$9)
4576
- _$insert(_el$8,()=>props.preferences.selectedSectionItemLimit?.(section())||"All",null)
4577
- _$setProp(_el$0,"onMouseDown",(event)=>{event.stopPropagation()
4578
- model.reorder(props.option.value,-1)
4579
- })
4580
- _$insert(_el$0,()=>model.icons.icon("up"))
4581
- _$setProp(_el$1,"onMouseDown",(event)=>{event.stopPropagation()
4582
- model.reorder(props.option.value,1)
4583
- })
4584
- _$insert(_el$1,()=>model.icons.icon("down"))
4585
- _$effect((_p$)=>{var _v$3=model.theme().accent,_v$4=model.theme().accent,_v$5=model.theme().accent
4586
- _v$3!==_p$.e&&(_p$.e=_$setProp(_el$8,"fg",_v$3,_p$.e))
4587
- _v$4!==_p$.t&&(_p$.t=_$setProp(_el$0,"fg",_v$4,_p$.t))
4588
- _v$5!==_p$.a&&(_p$.a=_$setProp(_el$1,"fg",_v$5,_p$.a))
4589
- return _p$
4590
- },{e:undefined,t:undefined,a:undefined
4591
- })
4592
- return _el$3
4593
- }})]
4594
- }})
4595
- }
4596
- function SettingsDialog(props){const model=createSettingsDialogController(props)
4597
- return _$createComponent(DialogSurface,{get api(){return props.api
4598
- },get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` Navigator settings`),_el$4=_$createElement("text")
4599
- _$insertNode(_el$,_el$2)
4600
- _$insertNode(_el$,_el$4)
4601
- _$setProp(_el$,"flexDirection","row")
4602
- _$setProp(_el$,"justifyContent","space-between")
4603
- _$insertNode(_el$2,_el$3)
4604
- _$insert(_el$2,()=>model.icons.icon("settings"),_el$3)
4605
- _$setProp(_el$4,"onMouseDown",(event)=>event.stopPropagation())
4606
- _$setProp(_el$4,"onMouseUp",(event)=>{event.stopPropagation()
4607
- model.dialogs.back()
4608
- })
4609
- _$insert(_el$4,()=>model.icons.key("esc"))
4610
- _$effect((_p$)=>{var _v$=TextAttributes16.BOLD,_v$2=model.theme().text,_v$3=model.theme().textMuted
4611
- _v$!==_p$.e&&(_p$.e=_$setProp(_el$2,"attributes",_v$,_p$.e))
4612
- _v$2!==_p$.t&&(_p$.t=_$setProp(_el$2,"fg",_v$2,_p$.t))
4613
- _v$3!==_p$.a&&(_p$.a=_$setProp(_el$4,"fg",_v$3,_p$.a))
4614
- return _p$
4615
- },{e:undefined,t:undefined,a:undefined
4616
- })
4617
- return _el$
4618
- })(),(()=>{var _el$5=_$createElement("text")
4619
- _$insertNode(_el$5,_$createTextNode(`Adjust sections and behavior. Changes apply immediately.`))
4620
- _$effect((_$p)=>_$setProp(_el$5,"fg",model.theme().textMuted,_$p))
4621
- return _el$5
4622
- })(),(()=>{var _el$7=_$createElement("box")
4623
- _$setProp(_el$7,"flexDirection","row")
4624
- _$setProp(_el$7,"gap",1)
4625
- _$insert(_el$7,_$createComponent(For10,{get each(){return model.orderedGroups()
4626
- },children:(group)=>_$createComponent(Tab,{get api(){return props.api
4627
- },get selected(){return model.activeGroup()===group.id
4628
- },paddingLeft:1,paddingRight:1,onMouseDown:()=>{model.setActiveGroup(group.id)
4629
- model.setActive(0)
4630
- },get children(){return [_$memo(()=>model.icons.tab(group.id))," ",_$memo(()=>group.tab)]
4631
- }})
4632
- }))
4633
- return _el$7
4634
- })(),(()=>{var _el$8=_$createElement("scrollbox"),_el$9=_$createElement("box")
4635
- _$insertNode(_el$8,_el$9)
4636
- var _ref$=model.setBody
4637
- typeof _ref$==="function"?_$use(_ref$,_el$8):model.setBody=_el$8
4638
- _$setProp(_el$8,"id",`${PLUGIN_ID}.settings.body`)
4639
- _$setProp(_el$8,"scrollX",false)
4640
- _$setProp(_el$8,"verticalScrollbarOptions",{visible:true
4641
- })
4642
- _$setProp(_el$8,"horizontalScrollbarOptions",{visible:false
4643
- })
4644
- _$setProp(_el$9,"gap",1)
4645
- _$insert(_el$9,_$createComponent(For10,{get each(){return model.options()
4646
- },children:(option)=>_$createComponent(SettingsOptionRow,{get preferences(){return props.preferences
4647
- },controller:model,option
4648
- })
4649
- }))
4650
- _$effect((_p$)=>{var{restoreScroll:_v$4,saveScroll:_v$5}=model,_v$6=model.contentHeight()
4651
- _v$4!==_p$.e&&(_p$.e=_$setProp(_el$8,"renderBefore",_v$4,_p$.e))
4652
- _v$5!==_p$.t&&(_p$.t=_$setProp(_el$8,"renderAfter",_v$5,_p$.t))
4653
- _v$6!==_p$.a&&(_p$.a=_$setProp(_el$8,"height",_v$6,_p$.a))
4654
- return _p$
4655
- },{e:undefined,t:undefined,a:undefined
4656
- })
4657
- return _el$8
4658
- })(),(()=>{var _el$0=_$createElement("text")
4659
- _$insert(_el$0,()=>model.footerHint())
4660
- _$effect((_$p)=>_$setProp(_el$0,"fg",model.theme().textMuted,_$p))
4661
- return _el$0
4662
- })()]
4663
- }})
4664
- }
4665
- function openSettings(api,preferences,activeValue,mcp,skills){createDialogStack(api,preferences.lspIconStyle,()=>true,preferences.cornerFont).open(()=>_$createComponent(SettingsDialog,{api,preferences,mcp,skills,activeValue
4666
- }),"xlarge")
4667
- }
4668
-
4669
-
4670
- function SettingsBinding(props){const unregister=props.api.keymap.registerLayer({mode:"base",commands:[{name:`${PLUGIN_ID}.settings`,title:"Navigator settings",category:"Navigator",namespace:"palette",enabled:()=>["home","session"].includes(props.api.route.current.name),run:()=>openSettings(props.api,props.preferences,undefined,props.mcp,props.skills)
4671
- }],bindings:[{key:{name:",",ctrl:true
4672
- },cmd:`${PLUGIN_ID}.settings`
4673
- }]
4674
- })
4675
- onCleanup12(unregister)
4676
- return _$createElement("box")
4677
- }
4678
-
4679
-
4680
- function currentPermissionMode(api){const title=api.keymap.getCommands?.({visibility:"registered"
4681
- }).find((command)=>command.name==="permission.mode")?.title
4682
- if(typeof title!=="string")
4683
- return
4684
- if(title.startsWith("Disable auto-approve permissions"))
4685
- return true
4686
- return title.startsWith("Enable auto-approve permissions")?false:undefined
4687
- }
4688
- function PermissionModeBinding(props){let applying=false
4689
- let observed
4690
- createEffect12(()=>{if(!props.preferences.ready())
4691
- return
4692
- const preferred=props.preferences.autoApprovePermissions()
4693
- const current=currentPermissionMode(props.api)
4694
- observed=current
4695
- if(preferred===undefined||current===undefined||current===preferred)
4696
- return
4697
- applying=true
4698
- try{props.api.keymap.dispatchCommand("permission.mode")
4699
- observed=currentPermissionMode(props.api)
4700
- } finally{applying=false
4701
- }})
4702
- const unsubscribe=props.api.keymap.on?.("state",()=>{if(applying||!props.preferences.ready())
4703
- return
4704
- const current=currentPermissionMode(props.api)
4705
- if(current===undefined||current===observed)
4706
- return
4707
- observed=current
4708
- props.preferences.setAutoApprovePermissions(current)
4709
- })
4710
- if(unsubscribe)
4711
- onCleanup13(unsubscribe)
4712
- return _$createElement("box")
4713
- }
4714
-
4715
-
4716
-
4717
- function SettingsFooterButton(props){const icons=useIcons()
4718
- const [hovered,setHovered]=createSignal16(false)
4719
- const theme=()=>props.api.theme.current
4720
- return _$createComponent(IconControl,{id:`${PLUGIN_ID}.settings.footer`,get icon(){return icons.icon("settings")
4721
- },get foregroundColor(){return _$memo(()=>!!hovered())()?theme().text:theme().textMuted
4722
- },get backgroundColor(){return _$memo(()=>!!hovered())()?theme().backgroundElement:theme().backgroundPanel
4723
- },onMouseOver:()=>setHovered(true),onMouseOut:()=>setHovered(false),onMouseUp:()=>openSettings(props.api,props.preferences,undefined,props.mcp,props.skills)
4724
- })
4725
- }
4726
-
4727
-
4728
- import {realpathSync} from "fs"
4729
- function routeKey(api){const route=api.route.current
4730
- return `${route.name}:${"params" in route ? route.params?.sessionID ?? "" : ""}`
4731
- }
4732
- function sameLocation(left,right){function canonical(path){try{return realpathSync(path)
4733
- } catch{return path
4734
- }}
4735
- return canonical(left.routing.directory)===canonical(right.routing.directory)&&left.routing.workspace===right.routing.workspace
4736
- }
4737
- function createStartupSessionController(api,preferences){let initialized=false
4738
- let pending=false
4739
- let retry
4740
- let disposed=false
4741
- function enabled(){const location=currentLocation(api)
4742
- return preferences.ready()&&!pending&&!api.ui.dialog.open&&preferences.startInChatForScope(location.routing.directory)
4743
- }
4744
- async function start(){if(!enabled())
4745
- return
4746
- const location=currentLocation(api)
4747
- const originalRoute=routeKey(api)
4748
- pending=true
4749
- try{const result=await api.client.session.create({directory:location.routing.directory,...location.routing.workspace&&{workspace:location.routing.workspace}},{signal:api.lifecycle.signal})
4750
- if(result.error||!result.data)
4751
- throw result.error??new Error("Session creation returned no session")
4752
- if(!api.lifecycle.signal?.aborted&&routeKey(api)===originalRoute&&sameLocation(currentLocation(api),location)&&preferences.startInChatForScope(location.routing.directory)){api.route.navigate("session",{sessionID:result.data.id})
4753
- }} catch(error){if(!api.lifecycle.signal?.aborted)
4754
- api.ui.toast({variant:"error",title:"New session",message:error instanceof Error?error.message:"Could not create a session",duration:5000
4755
- })
4756
- } finally{pending=false
4757
- }}
4758
- async function initialize(){if(initialized)
4759
- return
4760
- initialized=true
4761
- if(api.route.current.name!=="home")
4762
- return
4763
- const location=currentLocation(api)
4764
- await preferences.load()
4765
- if(api.route.current.name!=="home"||!sameLocation(currentLocation(api),location))
4766
- return
4767
- function tryStart(){if(disposed||api.route.current.name!=="home"||!sameLocation(currentLocation(api),location))
4768
- return
4769
- if(api.ui.dialog.open){retry=setTimeout(tryStart,200)
4770
- return
4771
- }
4772
- start()
4773
- }
4774
- queueMicrotask(tryStart)
4775
- }
4776
- return{enabled,initialize,start,handleNewSession(){if(!enabled())
4777
- return false
4778
- start()
4779
- return true
4780
- },dispose(){disposed=true
4781
- clearTimeout(retry)
4782
- }}}
4783
-
4784
-
4785
- function StartupSessionBinding(props){if(props.api.keymap.on){const unregister=props.api.keymap.on("dispatch",(event)=>{if(event.phase!=="binding-execute"||event.command!=="session.new")
4786
- return
4787
- queueMicrotask(()=>void props.controller.start())
4788
- })
4789
- onCleanup14(unregister)
4790
- } else
4791
- createEffect13(()=>{if(!props.controller.enabled())
4792
- return
4793
- const unregister=props.api.keymap.registerLayer({mode:"global",priority:2001,commands:[{name:"session.new",title:"New session",category:"Session",namespace:"palette",enabled:props.controller.enabled,run:()=>void props.controller.start()
4794
- }]
4795
- })
4796
- onCleanup14(unregister)
4797
- })
4798
- onMount5(()=>void props.controller.initialize())
4799
- onCleanup14(props.controller.dispose)
4800
- return _$createElement("box")
4801
- }
4802
- function versionParts(value){const match=/^v?(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/.exec(value)
4803
- return match?{numbers:match.slice(1,4).map(Number),prerelease:match[4]||undefined}:undefined
4504
+ function versionParts(value){const match=/^v?(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/.exec(value)
4505
+ return match?{numbers:match.slice(1,4).map(Number),prerelease:match[4]||undefined}:undefined
4804
4506
  }
4805
4507
  function isNewerVersion(latest,current){const next=versionParts(latest)
4806
4508
  const installed=versionParts(current)
@@ -4842,7 +4544,7 @@ return Bun.file(new URL("../../../../CHANGELOG.md",import.meta.url)).text()
4842
4544
 
4843
4545
 
4844
4546
 
4845
- function UpgradeNotesDialog(props){const dimensions=useTerminalDimensions7()
4547
+ function UpgradeNotesDialog(props){const dimensions=useTerminalDimensions9()
4846
4548
  const dialogs=useDialogs(props.api)
4847
4549
  const icons=useIcons()
4848
4550
  const theme=()=>props.api.theme.current
@@ -4912,7 +4614,7 @@ return _el$8
4912
4614
  }
4913
4615
  function UpgradeNotesBinding(props){let pending
4914
4616
  let disposed=false
4915
- onMount6(async ()=>{const previous=await props.preferences.claimNavigatorUpgrade(props.version)
4617
+ onMount5(async ()=>{const previous=await props.preferences.claimNavigatorUpgrade(props.version)
4916
4618
  if(!previous||disposed)
4917
4619
  return
4918
4620
  try{let show=function(){if(disposed||props.api.lifecycle.signal?.aborted)
@@ -4930,7 +4632,7 @@ if(entries.length===0||disposed)
4930
4632
  return
4931
4633
  show()
4932
4634
  } catch{}})
4933
- onCleanup15(()=>{disposed=true
4635
+ onCleanup16(()=>{disposed=true
4934
4636
  clearTimeout(pending)
4935
4637
  })
4936
4638
  return _$createElement("box")
@@ -5326,7 +5028,7 @@ const colors=()=>sidebarInteractiveColors(api.theme.current,{focused:focused(),h
5326
5028
  const ref=(renderable)=>{unregister?.()
5327
5029
  unregister=interaction?.register({...descriptor,renderable})
5328
5030
  }
5329
- onCleanup16(()=>unregister?.())
5031
+ onCleanup17(()=>unregister?.())
5330
5032
  return{ref,disabled,focused,backgroundColor:()=>colors().backgroundColor,foregroundColor:()=>colors().foregroundColor,onMouseOver:()=>setHovered(true),onMouseOut:()=>setHovered(false),select(event){interaction?.mouseSelect(descriptor.id,event)
5331
5033
  },activate(event){if(interaction)
5332
5034
  return interaction.mouseActivate(descriptor.id,event)
@@ -5362,7 +5064,7 @@ _$setProp(_el$2,"flexShrink",0)
5362
5064
  _$insert(_el$2,()=>lspIcon(props.id,props.iconStyle??icons.style()))
5363
5065
  _$effect((_$p)=>_$setProp(_el$2,"fg",item.foregroundColor(),_$p))
5364
5066
  return _el$2
5365
- })(),_$createComponent(Show7,{get when(){return showName()
5067
+ })(),_$createComponent(Show10,{get when(){return showName()
5366
5068
  },get children(){var _el$3=_$createElement("text")
5367
5069
  _$setProp(_el$3,"flexShrink",0)
5368
5070
  _$setProp(_el$3,"wrapMode","none")
@@ -5383,7 +5085,7 @@ return _el$3
5383
5085
  function createListVisibility(options){const [expanded,setExpanded]=createSignal21(false)
5384
5086
  let previousKey
5385
5087
  let previousLimit
5386
- const canToggle=createMemo10(()=>options.limit()>0&&options.items().length>options.limit())
5088
+ const canToggle=createMemo8(()=>options.limit()>0&&options.items().length>options.limit())
5387
5089
  createComputed(()=>{const key=options.resetKey()
5388
5090
  const limit=options.limit()
5389
5091
  const isToggle=canToggle()
@@ -5392,7 +5094,7 @@ untrack3(()=>setExpanded(false))
5392
5094
  previousKey=key
5393
5095
  previousLimit=limit
5394
5096
  })
5395
- const visible=createMemo10(()=>!canToggle()||expanded()?options.items():options.items().slice(0,options.limit()))
5097
+ const visible=createMemo8(()=>!canToggle()||expanded()?options.items():options.items().slice(0,options.limit()))
5396
5098
  return{visible,expanded,canToggle,hiddenCount:()=>options.items().length-visible().length,showAll:()=>setExpanded(canToggle()),showLess:()=>setExpanded(false)
5397
5099
  }}
5398
5100
 
@@ -5417,7 +5119,7 @@ else
5417
5119
  props.visibility.showAll()
5418
5120
  queueMicrotask(()=>props.interaction?.select(id))
5419
5121
  }})
5420
- return _$createComponent(Show8,{get when(){return props.visibility.canToggle()
5122
+ return _$createComponent(Show11,{get when(){return props.visibility.canToggle()
5421
5123
  },get children(){return _$createComponent(SelectionBox,{ref(r$){var _ref$=item.ref
5422
5124
  typeof _ref$==="function"?_ref$(r$):item.ref=r$
5423
5125
  },id,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
@@ -5470,7 +5172,7 @@ return result + ellipsis
5470
5172
  function SectionHeaderControl(props){const [width,setWidth]=createSignal22()
5471
5173
  const control=useSidebarItem(props.api,props.interaction,{id:props.action.id,position:()=>props.position,disabled:props.action.disabled,activate:props.action.onActivate
5472
5174
  },()=>props.api.theme.current.accent,"control")
5473
- createEffect14(on(()=>[props.action.label(),props.resetWidth],()=>setWidth(undefined)))
5175
+ createEffect13(on(()=>[props.action.label(),props.resetWidth],()=>setWidth(undefined)))
5474
5176
  const label=()=>width()===undefined||props.iconOnly?props.action.label():truncateEnd(props.action.label(),width()-2)
5475
5177
  return _$createComponent(SelectionBox,{ref:(node)=>control.ref(node),get id(){return props.action.id
5476
5178
  },get iconOnly(){return props.iconOnly
@@ -5534,7 +5236,7 @@ _$setProp(_el$7,"flexGrow",1)
5534
5236
  _$setProp(_el$7,"minWidth",0)
5535
5237
  _$setProp(_el$7,"justifyContent","flex-end")
5536
5238
  _$insert(_el$7,()=>props.headerControls,null)
5537
- _$insert(_el$7,_$createComponent(Show9,{get when(){return props.headerAction
5239
+ _$insert(_el$7,_$createComponent(Show12,{get when(){return props.headerAction
5538
5240
  },children:(action)=>_$createComponent(SectionHeaderControl,{get api(){return props.api
5539
5241
  },get interaction(){return props.interaction
5540
5242
  },get action(){return action()
@@ -5542,7 +5244,7 @@ _$insert(_el$7,_$createComponent(Show9,{get when(){return props.headerAction
5542
5244
  },get position(){return{section:props.navigationSection??0,row:0,column:1
5543
5245
  }}})
5544
5246
  }),null)
5545
- _$insert(_el$7,_$createComponent(Show9,{get when(){return props.summary
5247
+ _$insert(_el$7,_$createComponent(Show12,{get when(){return props.summary
5546
5248
  },get children(){var _el$8=_$createElement("text")
5547
5249
  _$setProp(_el$8,"wrapMode","none")
5548
5250
  _$setProp(_el$8,"truncate",true)
@@ -5559,25 +5261,25 @@ return _el$8
5559
5261
  return _el$7
5560
5262
  })()]
5561
5263
  }}),null)
5562
- _$insert(_el$,_$createComponent(Show9,{get when(){return props.open
5264
+ _$insert(_el$,_$createComponent(Show12,{get when(){return props.open
5563
5265
  },get children(){return props.children
5564
5266
  }}),null)
5565
5267
  return _el$
5566
5268
  })()
5567
5269
  }
5568
5270
  var SectionWithHeaderAction=Section;
5569
- function LspSection(props){const list=createMemo11(()=>[...props.api.state.lsp()].sort((a,b)=>Number(b.status==="error")-Number(a.status==="error")||a.id.localeCompare(b.id)||a.root.localeCompare(b.root)))
5271
+ function LspSection(props){const list=createMemo9(()=>[...props.api.state.lsp()].sort((a,b)=>Number(b.status==="error")-Number(a.status==="error")||a.id.localeCompare(b.id)||a.root.localeCompare(b.root)))
5570
5272
  const visibility=createListVisibility({items:list,limit:()=>props.preferences.sectionItemLimit?.("lsp")??0,resetKey:()=>currentLocation(props.api).key
5571
5273
  })
5572
- const connected=createMemo11(()=>list().filter((item)=>item.status==="connected").length)
5573
- const disabled=createMemo11(()=>props.api.state.config.lsp===false)
5274
+ const connected=createMemo9(()=>list().filter((item)=>item.status==="connected").length)
5275
+ const disabled=createMemo9(()=>props.api.state.config.lsp===false)
5574
5276
  const navigationSection=()=>props.navigationSection??5
5575
5277
  return _$createComponent(Section,{get api(){return props.api
5576
5278
  },get interaction(){return props.interaction
5577
5279
  },sectionId:`${PLUGIN_ID}.section.lsp`,get navigationSection(){return navigationSection()
5578
5280
  },title:"LSP",section:"lsp",get summary(){return `${connected()}/${list().length}`
5579
5281
  },get open(){return props.preferences.expanded().lsp
5580
- },onToggle:()=>props.preferences.toggleSectionExpanded("lsp"),get children(){return [_$createComponent(Show10,{get when(){return list().length>0
5282
+ },onToggle:()=>props.preferences.toggleSectionExpanded("lsp"),get children(){return [_$createComponent(Show13,{get when(){return list().length>0
5581
5283
  },get fallback(){return(()=>{var _el$2=_$createElement("text")
5582
5284
  _$insert(_el$2,()=>disabled()?"LSP is disabled":"Activates as files are read")
5583
5285
  _$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.textMuted,_$p))
@@ -5609,25 +5311,25 @@ return _el$
5609
5311
 
5610
5312
 
5611
5313
 
5612
- function createMcpSectionModel(props,query){const target=createMemo12(()=>props.controller.target())
5613
- const favorites=createMemo12(()=>props.preferences.favoriteMcpServers?.()??new Set)
5614
- const groups=createMemo12(()=>props.preferences.mcpServerGroups?.()??{})
5615
- const grouped=createMemo12(()=>Object.keys(groups()).length>0)
5616
- const list=createMemo12(()=>buildMcpGroupedView(props.controller.list(target()),favorites(),groups()))
5314
+ function createMcpSectionModel(props,query){const target=createMemo10(()=>props.controller.target())
5315
+ const favorites=createMemo10(()=>props.preferences.favoriteMcpServers?.()??new Set)
5316
+ const groups=createMemo10(()=>props.preferences.mcpServerGroups?.()??{})
5317
+ const grouped=createMemo10(()=>Object.keys(groups()).length>0)
5318
+ const list=createMemo10(()=>buildMcpGroupedView(props.controller.list(target()),favorites(),groups()))
5617
5319
  const groupItems=(bucket)=>list().filter((item)=>item.bucket===bucket)
5618
- const filtered=createMemo12(()=>list().filter((item)=>matchesFilter(query(),`${item.name} ${item.assignedGroup ?? ""}`)))
5320
+ const filtered=createMemo10(()=>list().filter((item)=>matchesFilter(query(),`${item.name} ${item.assignedGroup ?? ""}`)))
5619
5321
  const visibility=createListVisibility({items:filtered,limit:()=>props.preferences.sectionItemLimit?.("mcp")??0,resetKey:()=>JSON.stringify([target().key,query()])
5620
5322
  })
5621
- const active=createMemo12(()=>list().filter((item)=>item.status==="connected").length)
5622
- const state=createMemo12(()=>props.controller.state(target()))
5623
- const bulk=createMemo12(()=>props.controller.bulkState?.(target())??{action:"connect",status:"idle",completed:0,total:0,failed:[]
5323
+ const active=createMemo10(()=>list().filter((item)=>item.status==="connected").length)
5324
+ const state=createMemo10(()=>props.controller.state(target()))
5325
+ const bulk=createMemo10(()=>props.controller.bulkState?.(target())??{action:"connect",status:"idle",completed:0,total:0,failed:[]
5624
5326
  })
5625
- const bulkRunning=createMemo12(()=>bulk().status==="running")
5626
- const mutationRunning=createMemo12(()=>props.controller.mutating?.(target()))
5627
- const connectable=createMemo12(()=>list().filter((item)=>mcpToggleAction2(item.status)==="connect").length)
5628
- const disconnectable=createMemo12(()=>list().filter((item)=>mcpToggleAction2(item.status)==="disconnect").length)
5629
- const errors=createMemo12(()=>list().filter((item)=>item.status==="failed"||item.status==="needs_auth"||item.status==="needs_client_registration").length)
5630
- const presetName=createMemo12(()=>{const presets=props.preferences.mcpPresets?.()??{}
5327
+ const bulkRunning=createMemo10(()=>bulk().status==="running")
5328
+ const mutationRunning=createMemo10(()=>props.controller.mutating?.(target()))
5329
+ const connectable=createMemo10(()=>list().filter((item)=>mcpToggleAction2(item.status)==="connect").length)
5330
+ const disconnectable=createMemo10(()=>list().filter((item)=>mcpToggleAction2(item.status)==="disconnect").length)
5331
+ const errors=createMemo10(()=>list().filter((item)=>item.status==="failed"||item.status==="needs_auth"||item.status==="needs_client_registration").length)
5332
+ const presetName=createMemo10(()=>{const presets=props.preferences.mcpPresets?.()??{}
5631
5333
  const selected=props.controller.selectedPreset?.(target())
5632
5334
  return selected&&Object.hasOwn(presets,selected)?selected:matchingMcpPreset(list(),presets)
5633
5335
  })
@@ -5702,7 +5404,7 @@ _$insert(_el$,_$createComponent(McpBulkAction,{get api(){return props.api
5702
5404
  }),null)
5703
5405
  _$effect((_$p)=>_$setProp(_el$,"paddingBottom",model.bulkRunning()||model.bulk().status==="error"?1:0,_$p))
5704
5406
  return _el$
5705
- })(),_$createComponent(Show11,{get when(){return model.bulkRunning()
5407
+ })(),_$createComponent(Show14,{get when(){return model.bulkRunning()
5706
5408
  },get children(){var _el$2=_$createElement("text"),_el$3=_$createTextNode(` `),_el$4=_$createTextNode(`/`),_el$5=_$createTextNode(`\u2026`)
5707
5409
  _$insertNode(_el$2,_el$3)
5708
5410
  _$insertNode(_el$2,_el$4)
@@ -5712,7 +5414,7 @@ _$insert(_el$2,()=>model.bulk().completed,_el$4)
5712
5414
  _$insert(_el$2,()=>model.bulk().total,_el$5)
5713
5415
  _$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.textMuted,_$p))
5714
5416
  return _el$2
5715
- }}),_$createComponent(Show11,{get when(){return model.bulk().status==="error"
5417
+ }}),_$createComponent(Show14,{get when(){return model.bulk().status==="error"
5716
5418
  },get children(){return _$createComponent(McpBulkAction,{get api(){return props.api
5717
5419
  },get interaction(){return props.interaction
5718
5420
  },id:`${PLUGIN_ID}.mcp.retry-all`,get position(){return{section:props.navigationSection,row:3,column:0
@@ -5792,7 +5494,7 @@ return _el$4
5792
5494
  function RequestErrorRow(props){const icons=useIcons()
5793
5495
  const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>props.position,disabled:()=>!props.state.error?.retryable||props.state.status==="loading"||props.state.status==="refreshing",activate:props.onRetry
5794
5496
  })
5795
- return _$createComponent(Show12,{get when(){return props.state.error
5497
+ return _$createComponent(Show15,{get when(){return props.state.error
5796
5498
  },children:(error)=>_$createComponent(SelectionBox,{ref:(node)=>item.ref(node),get id(){return props.id
5797
5499
  },flexDirection:"row",gap:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
5798
5500
  },get onMouseOver(){return item.onMouseOver
@@ -5807,7 +5509,7 @@ _$insert(_el$,()=>icons.icon("error"),_el$2)
5807
5509
  _$insert(_el$,()=>error().message,null)
5808
5510
  _$effect((_$p)=>_$setProp(_el$,"fg",item.focused()?item.foregroundColor():props.api.theme.current.error,_$p))
5809
5511
  return _el$
5810
- })(),_$createComponent(Show12,{get when(){return error().retryable
5512
+ })(),_$createComponent(Show15,{get when(){return error().retryable
5811
5513
  },get children(){var _el$3=_$createElement("text"),_el$4=_$createTextNode(` Retry`)
5812
5514
  _$insertNode(_el$3,_el$4)
5813
5515
  _$setProp(_el$3,"flexShrink",0)
@@ -5822,7 +5524,7 @@ function SectionRequestBody(props){const icons=useIcons()
5822
5524
  const pending=()=>props.state.status==="loading"
5823
5525
  return(()=>{var _el$5=_$createElement("box")
5824
5526
  _$insert(_el$5,_$createComponent(RequestErrorRow,props),null)
5825
- _$insert(_el$5,_$createComponent(Show12,{get when(){return _$memo(()=>!!pending())()&&!props.hasItems
5527
+ _$insert(_el$5,_$createComponent(Show15,{get when(){return _$memo(()=>!!pending())()&&!props.hasItems
5826
5528
  },get children(){var _el$6=_$createElement("text"),_el$7=_$createTextNode(` `)
5827
5529
  _$insertNode(_el$6,_el$7)
5828
5530
  _$insert(_el$6,()=>icons.icon("pending"),_el$7)
@@ -5830,10 +5532,10 @@ _$insert(_el$6,()=>props.loading,null)
5830
5532
  _$effect((_$p)=>_$setProp(_el$6,"fg",props.api.theme.current.textMuted,_$p))
5831
5533
  return _el$6
5832
5534
  }}),null)
5833
- _$insert(_el$5,_$createComponent(Show12,{get when(){return props.hasItems
5535
+ _$insert(_el$5,_$createComponent(Show15,{get when(){return props.hasItems
5834
5536
  },get children(){return props.children
5835
5537
  }}),null)
5836
- _$insert(_el$5,_$createComponent(Show12,{get when(){return _$memo(()=>!!((props.state.status==="ready"||props.state.status==="refreshing")&&!props.hasItems))()&&!props.state.error
5538
+ _$insert(_el$5,_$createComponent(Show15,{get when(){return _$memo(()=>!!((props.state.status==="ready"||props.state.status==="refreshing")&&!props.hasItems))()&&!props.state.error
5837
5539
  },get children(){var _el$8=_$createElement("text"),_el$9=_$createTextNode(` `)
5838
5540
  _$insertNode(_el$8,_el$9)
5839
5541
  _$insert(_el$8,()=>icons.icon("info"),_el$9)
@@ -5988,7 +5690,7 @@ props.interaction.leaveFilter(input)
5988
5690
  else
5989
5691
  input?.blur()
5990
5692
  }
5991
- onCleanup17(()=>unregisterInput?.())
5693
+ onCleanup18(()=>unregisterInput?.())
5992
5694
  return _$createComponent(SelectionBox,{ref:(node)=>item.ref(node),get id(){return props.id
5993
5695
  },flexDirection:"row",gap:1,marginTop:1,marginBottom:1,paddingLeft:1,paddingRight:1,get backgroundColor(){return _$memo(()=>!!highlighted())()?theme().primary:item.backgroundColor()
5994
5696
  },get onMouseOver(){return item.onMouseOver
@@ -6026,7 +5728,7 @@ return _p$
6026
5728
  },{e:undefined,t:undefined,a:undefined,o:undefined,i:undefined,n:undefined,s:undefined,h:undefined
6027
5729
  })
6028
5730
  return _el$2
6029
- })(),_$createComponent(Show13,{get when(){return props.query
5731
+ })(),_$createComponent(Show16,{get when(){return props.query
6030
5732
  },get children(){var _el$3=_$createElement("text")
6031
5733
  _$setProp(_el$3,"flexShrink",0)
6032
5734
  _$setProp(_el$3,"onMouseDown",()=>props.onInput(""))
@@ -6055,7 +5757,7 @@ _$insert(_el$,_$createComponent(SectionFilter,{get api(){return props.api
6055
5757
  }},get query(){return props.query
6056
5758
  },placeholder:"Filter MCP...",get onInput(){return props.onQuery
6057
5759
  }}),null)
6058
- _$insert(_el$,_$createComponent(Show14,{get when(){return model.filtered().length>0
5760
+ _$insert(_el$,_$createComponent(Show17,{get when(){return model.filtered().length>0
6059
5761
  },get fallback(){return(()=>{var _el$2=_$createElement("text")
6060
5762
  _$insertNode(_el$2,_$createTextNode(`No matching MCP servers`))
6061
5763
  _$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.textMuted,_$p))
@@ -6066,7 +5768,7 @@ return _el$2
6066
5768
  },get grouped(){return model.grouped
6067
5769
  },get density(){return props.preferences.rowDensity?.()??"compact"
6068
5770
  },get children(){return _$createComponent(For13,{get each(){return model.visibility.visible()
6069
- },children:(item,index)=>[_$createComponent(Show14,{get when(){return _$memo(()=>!!model.grouped())()&&(index()===0||model.visibility.visible()[index()-1]?.bucket!==item.bucket)
5771
+ },children:(item,index)=>[_$createComponent(Show17,{get when(){return _$memo(()=>!!model.grouped())()&&(index()===0||model.visibility.visible()[index()-1]?.bucket!==item.bucket)
6070
5772
  },get children(){return _$createComponent(McpGroupHeader,{get api(){return props.api
6071
5773
  },get interaction(){return props.interaction
6072
5774
  },get bucket(){return item.bucket
@@ -6100,7 +5802,7 @@ function McpSection(props){const icons=useIcons()
6100
5802
  const [query,setQuery]=createSignal26("")
6101
5803
  const model=createMcpSectionModel(props,query)
6102
5804
  const navigationSection=()=>props.navigationSection??6
6103
- const summary=createMemo13(()=>`${model.active()}/${model.list().length}${model.errors() ? ` \xB7 ${model.errors()} ${icons.icon("error")}` : ""}`)
5805
+ const summary=createMemo11(()=>`${model.active()}/${model.list().length}${model.errors() ? ` \xB7 ${model.errors()} ${icons.icon("error")}` : ""}`)
6104
5806
  return _$createComponent(SectionWithHeaderAction,{get api(){return props.api
6105
5807
  },get interaction(){return props.interaction
6106
5808
  },sectionId:`${PLUGIN_ID}.section.mcp`,get navigationSection(){return navigationSection()
@@ -6198,17 +5900,52 @@ return _$createComponent(SectionWithHeaderAction,{get api(){return props.api
6198
5900
 
6199
5901
 
6200
5902
 
5903
+
5904
+
5905
+
5906
+ var ToolbarContext=createContext4()
5907
+ var useToolbar=()=>useContext4(ToolbarContext)
5908
+ function ToolbarProvider(props){const value={pinned:(pin)=>Boolean(props.preferences.toolbarPins?.().some((item)=>toolbarPinKey(item)===toolbarPinKey(pin))),configure:(pin,dialogs)=>{if(pin.kind==="skill"&&!pin.location){props.api.ui.toast({variant:"warning",title:"Toolbar",message:"This Skill has no host-provided source location"
5909
+ })
5910
+ return
5911
+ }
5912
+ openToolbarPin({api:props.api,preferences:props.preferences,skills:props.skills,pin,dialogs
5913
+ })
5914
+ }}
5915
+ return _$createComponent(ToolbarContext.Provider,{value,get children(){return props.children
5916
+ }})
5917
+ }
5918
+
5919
+ function SidebarPinControl(props){const toolbar=useToolbar()
5920
+ const{api,interaction
5921
+ }=useSidebarList()
5922
+ const icons=useIcons()
5923
+ const item=useSidebarItem(api,interaction,{id:`${props.id}.pin`,position:()=>({...props.position,column:2
5924
+ }),activate:()=>toolbar?.configure(props.pin)
5925
+ },()=>toolbar?.pinned(props.pin)?api.theme.current.accent:api.theme.current.textMuted,"control")
5926
+ return _$createComponent(IconControl,{get id(){return `${props.id}.pin`
5927
+ },ref(r$){var _ref$=item.ref
5928
+ typeof _ref$==="function"?_ref$(r$):item.ref=r$
5929
+ },get icon(){return terminalIcon("pin",icons.style())
5930
+ },get backgroundColor(){return item.backgroundColor()
5931
+ },get foregroundColor(){return item.foregroundColor()
5932
+ },get onMouseOver(){return item.onMouseOver
5933
+ },get onMouseOut(){return item.onMouseOut
5934
+ },onMouseUp:(event)=>item.activate(event)
5935
+ })
5936
+ }
6201
5937
  function QuickActionRow(props){const{api,interaction
6202
5938
  }=useSidebarList()
6203
5939
  const icons=useIcons()
5940
+ const toolbar=useToolbar()
6204
5941
  const theme=()=>api.theme.current
6205
- const [width,setWidth]=createSignal30(0)
6206
- const shortcut=createMemo14(()=>{const bindings=api.keymap.getCommandBindings({visibility:"registered",commands:[props.action.command]
5942
+ const [width,setWidth]=createSignal31(0)
5943
+ const shortcut=createMemo12(()=>{const bindings=api.keymap.getCommandBindings({visibility:"registered",commands:[props.action.command]
6207
5944
  })
6208
5945
  return api.keys.formatBindings(bindings.get(props.action.command))
6209
5946
  })
6210
- const visibleShortcut=createMemo14(()=>{const value=shortcut()
6211
- return value&&width()>=Bun.stringWidth(props.action.label) + Bun.stringWidth(value) + 8?value:undefined
5947
+ const visibleShortcut=createMemo12(()=>{const value=shortcut()
5948
+ return value&&width()>=Bun.stringWidth(props.action.label) + Bun.stringWidth(value) + (toolbar?11:8)?value:undefined
6212
5949
  })
6213
5950
  function run(){if(props.action.command==="session.new"&&props.onNewSession?.())
6214
5951
  return
@@ -6246,7 +5983,7 @@ _$insert(_el$2,()=>props.action.label)
6246
5983
  _$effect((_$p)=>_$setProp(_el$2,"fg",row.foregroundColor(),_$p))
6247
5984
  return _el$2
6248
5985
  })()
6249
- },get metadata(){return _$createComponent(Show21,{get when(){return visibleShortcut()
5986
+ },get metadata(){return _$createComponent(Show24,{get when(){return visibleShortcut()
6250
5987
  },children:(value)=>(()=>{var _el$3=_$createElement("text")
6251
5988
  _$setProp(_el$3,"flexShrink",0)
6252
5989
  _$setProp(_el$3,"wrapMode","none")
@@ -6255,7 +5992,12 @@ _$effect((_$p)=>_$setProp(_el$3,"fg",row.focused()?row.foregroundColor():theme()
6255
5992
  return _el$3
6256
5993
  })()
6257
5994
  })
6258
- },get details(){return _$createComponent(Show21,{get when(){return props.disabled
5995
+ },get trailing(){return _$createComponent(Show24,{when:toolbar,get children(){return _$createComponent(SidebarPinControl,{get id(){return id()
5996
+ },get position(){return props.position
5997
+ },get pin(){return{kind:"action",id:props.action.command,icon:"bolt"
5998
+ }}})
5999
+ }})
6000
+ },get details(){return _$createComponent(Show24,{get when(){return props.disabled
6259
6001
  },children:(reason)=>(()=>{var _el$4=_$createElement("text")
6260
6002
  _$setProp(_el$4,"wrapMode","word")
6261
6003
  _$insert(_el$4,reason)
@@ -6266,7 +6008,7 @@ return _el$4
6266
6008
  }})
6267
6009
  }
6268
6010
  function QuickActionsSection(props){const commandRevision=createQuickActionRevision(props.api)
6269
- const actions=createMemo15(()=>{commandRevision()
6011
+ const actions=createMemo13(()=>{commandRevision()
6270
6012
  return orderQuickActionIds(props.preferences.quickActionOrder?.()??QUICK_ACTIONS.map((action)=>action.command),props.preferences.favoriteQuickActions?.()??new Set).flatMap((id)=>{const action=QUICK_ACTIONS.find((candidate)=>candidate.command===id)
6271
6013
  return action&&props.preferences.quickActionVisible?.(id)!==false?[{...action,label:quickActionLabel(props.api,action),disabled:quickActionDisabledReason(props.api,action)
6272
6014
  }]:[]
@@ -6283,7 +6025,7 @@ return _$createComponent(Section,{get api(){return props.api
6283
6025
  },onToggle:()=>props.preferences.toggleSectionExpanded("quick_actions"),get children(){return [_$createComponent(SidebarRowList,{get api(){return props.api
6284
6026
  },get interaction(){return props.interaction
6285
6027
  },get density(){return props.preferences.rowDensity?.()??"compact"
6286
- },get children(){return [_$createComponent(Show22,{get when(){return actions().length===0
6028
+ },get children(){return [_$createComponent(Show25,{get when(){return actions().length===0
6287
6029
  },get children(){var _el$=_$createElement("text")
6288
6030
  _$insertNode(_el$,_$createTextNode(`No quick actions selected`))
6289
6031
  _$effect((_$p)=>_$setProp(_el$,"fg",props.api.theme.current.textMuted,_$p))
@@ -6314,104 +6056,74 @@ function SectionBoundary(props){const dividerColor=()=>{const{backgroundPanel,bo
6314
6056
  return subtleLineColor(backgroundPanel,borderSubtle)
6315
6057
  }
6316
6058
  return(()=>{var _el$=_$createElement("box")
6317
- _$spread(_el$,_$mergeProps(()=>props.divided?{border:["bottom"],borderColor:dividerColor(),paddingBottom:1
6318
- }:{}),true)
6319
- _$insert(_el$,()=>props.children)
6320
- return _el$
6321
- })()
6322
- }
6323
-
6324
-
6325
- function SectionTab(props){const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>props.position,disabled:()=>props.disabled===true,activate:props.onActivate
6326
- })
6327
- const focused=()=>item.focused()
6328
- return _$createComponent(Tab,{get api(){return props.api
6329
- },get selected(){return props.selected
6330
- },get focused(){return _$memo(()=>!!!props.disabled)()&&focused()
6331
- },get count(){return props.count
6332
- },ref:(node)=>item.ref(node),get id(){return props.id
6333
- },height:1,minWidth:0,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
6334
- },get foregroundColor(){return item.foregroundColor()
6335
- },get onMouseOver(){return _$memo(()=>!!props.disabled)()?undefined:item.onMouseOver
6336
- },get onMouseOut(){return _$memo(()=>!!props.disabled)()?undefined:item.onMouseOut
6337
- },onMouseDown:(event)=>{if(!props.disabled)
6338
- item.select(event)
6339
- },onMouseUp:(event)=>{event.stopPropagation()
6340
- if(!props.disabled)
6341
- item.activate(event)
6342
- },get children(){return props.label
6343
- }})
6344
- }
6345
-
6346
-
6347
- var ENTRY_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.enter`
6348
- var CANCEL_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.cancel`
6349
- var MODE=`${PLUGIN_ID}.sidebar-shortcuts`
6350
- var DEFAULT_TIMEOUT_MS=5000
6351
- var ACTIONS=[{key:"h",hint:"toggle",command:"session.sidebar.toggle",section:undefined},{key:"t",hint:"todo",command:`${PLUGIN_ID}.focus.todo`,section:"todo"},{key:"a",hint:"agents",command:`${PLUGIN_ID}.focus.subagents`,section:"subagents"},{key:"s",hint:"skills",command:`${PLUGIN_ID}.focus.skills`,section:"skills"},{key:"q",hint:"actions",command:`${PLUGIN_ID}.focus.quick_actions`,section:"quick_actions"},{key:"l",hint:"LSP",command:`${PLUGIN_ID}.focus.lsp`,section:"lsp"},{key:"m",hint:"MCP",command:`${PLUGIN_ID}.focus.mcp`,section:"mcp"},{key:"c",hint:"check update",command:`${PLUGIN_ID}.check-update`,section:undefined},{key:"u",hint:"update",command:`${PLUGIN_ID}.update-navigator`,section:undefined}]
6352
- function createSidebarShortcutMode(api,options={}){const actions=ACTIONS.filter(({section})=>!section||supportsSidebarSection(api,section))
6353
- const hints=actions.map(({key,hint})=>`${key} ${hint}`).join(" | ")
6354
- const timeoutMs=options.timeoutMs??DEFAULT_TIMEOUT_MS
6355
- let shortcutKey=""
6356
- let unregisterBinding
6357
- let unregisterMode
6358
- let leaveMode
6359
- let timeout
6360
- let disposed=false
6361
- function cancel(){if(timeout)
6362
- clearTimeout(timeout)
6363
- timeout=undefined
6364
- unregisterMode?.()
6365
- unregisterMode=undefined
6366
- leaveMode?.()
6367
- leaveMode=undefined
6368
- }
6369
- function run(command){cancel()
6370
- return api.keymap.dispatchCommand(command)
6371
- }
6372
- function enter(){if(disposed||api.route.current.name!=="session"||api.ui?.dialog?.open)
6373
- return false
6374
- cancel()
6375
- unregisterMode=api.keymap.registerLayer({mode:MODE,priority:2000,commands:[{name:ENTRY_COMMAND,run:enter},{name:CANCEL_COMMAND,run:cancel},...actions.map(({key,command})=>({name:`${MODE}.${key}`,run:()=>run(command)
6376
- }))],bindings:[{key:"escape",cmd:CANCEL_COMMAND},{key:shortcutKey,cmd:ENTRY_COMMAND},...actions.map(({key})=>({key,cmd:`${MODE}.${key}`}))]
6377
- })
6378
- leaveMode=api.mode.push(MODE)
6379
- timeout=setTimeout(cancel,timeoutMs)
6380
- api.ui?.toast?.({variant:"info",title:"Navigator shortcuts",message:`${hints} | Esc cancel`,duration:timeoutMs
6059
+ _$spread(_el$,_$mergeProps(()=>props.divided?{border:["bottom"],borderColor:dividerColor(),paddingBottom:1
6060
+ }:{}),true)
6061
+ _$insert(_el$,()=>props.children)
6062
+ return _el$
6063
+ })()
6064
+ }
6065
+
6066
+
6067
+ function SectionTab(props){const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>props.position,disabled:()=>props.disabled===true,activate:props.onActivate
6381
6068
  })
6382
- return true
6069
+ const focused=()=>item.focused()
6070
+ return _$createComponent(Tab,{get api(){return props.api
6071
+ },get selected(){return props.selected
6072
+ },get focused(){return _$memo(()=>!!!props.disabled)()&&focused()
6073
+ },get count(){return props.count
6074
+ },ref:(node)=>item.ref(node),get id(){return props.id
6075
+ },height:1,minWidth:0,paddingLeft:1,paddingRight:1,get backgroundColor(){return item.backgroundColor()
6076
+ },get foregroundColor(){return item.foregroundColor()
6077
+ },get onMouseOver(){return _$memo(()=>!!props.disabled)()?undefined:item.onMouseOver
6078
+ },get onMouseOut(){return _$memo(()=>!!props.disabled)()?undefined:item.onMouseOut
6079
+ },onMouseDown:(event)=>{if(!props.disabled)
6080
+ item.select(event)
6081
+ },onMouseUp:(event)=>{event.stopPropagation()
6082
+ if(!props.disabled)
6083
+ item.activate(event)
6084
+ },get children(){return props.label
6085
+ }})
6383
6086
  }
6384
- const unregisterCommands=api.keymap.registerLayer({mode:"base",commands:[{name:TOGGLE_COMMAND,title:"Toggle sidebar",category:"Navigator",namespace:"palette",enabled:()=>api.route.current.name==="session"&&!api.ui?.dialog?.open,run:()=>api.keymap.dispatchCommand("session.sidebar.toggle")
6385
- },{name:`${LEGACY_PLUGIN_ID}.toggle`,run:()=>api.keymap.dispatchCommand("session.sidebar.toggle")
6386
- },{name:ENTRY_COMMAND,enabled:()=>api.route.current.name==="session"&&!api.ui?.dialog?.open,run:enter
6387
- }]
6087
+
6088
+
6089
+
6090
+
6091
+
6092
+
6093
+ function SidebarToggleBinding(props){const shortcuts=createSidebarShortcutMode(props.api)
6094
+ createEffect15(()=>{const key=props.preferences.toggleKey()
6095
+ untrack6(()=>shortcuts.bind(key))
6388
6096
  })
6389
- return{active:()=>leaveMode!==undefined,bind(key){cancel()
6390
- unregisterBinding?.()
6391
- shortcutKey=key
6392
- unregisterBinding=api.keymap.registerLayer({mode:"base",bindings:[{key,cmd:ENTRY_COMMAND}]
6097
+ createEffect15(()=>{if(shortcuts.active()&&(props.api.route.current.name!=="session"||props.api.ui.dialog.open||props.api.mode.current()==="modal"))
6098
+ untrack6(shortcuts.cancel)
6393
6099
  })
6394
- },enter,cancel,dispose(){disposed=true
6395
- cancel()
6396
- unregisterBinding?.()
6397
- unregisterBinding=undefined
6398
- unregisterCommands()
6399
- }}}
6400
- function SidebarToggleBinding(props){const shortcuts=createSidebarShortcutMode(props.api)
6401
- createEffect16(()=>shortcuts.bind(props.preferences.toggleKey()))
6402
- onCleanup18(shortcuts.dispose)
6403
- return _$createElement("box")
6100
+ onCleanup19(shortcuts.dispose)
6101
+ return(()=>{var _el$=_$createElement("box")
6102
+ _$setProp(_el$,"position","absolute")
6103
+ _$setProp(_el$,"top",0)
6104
+ _$setProp(_el$,"left",0)
6105
+ _$setProp(_el$,"width","100%")
6106
+ _$setProp(_el$,"height","100%")
6107
+ _$insert(_el$,_$createComponent(Show26,{get when(){return shortcuts.active()
6108
+ },get children(){return _$createComponent(Suspense4,{get children(){return _$createComponent(SidebarShortcutHint,{get api(){return props.api
6109
+ },get actions(){return shortcuts.actions
6110
+ }})
6111
+ }})
6112
+ }}))
6113
+ _$effect((_$p)=>_$setProp(_el$,"visible",shortcuts.active(),_$p))
6114
+ return _el$
6115
+ })()
6404
6116
  }
6405
6117
  function SidebarFocusBinding(props){const commands=props.interaction.baseCommands()
6406
6118
  const unregisterCommands=props.api.keymap.registerLayer({commands:[...commands,...commands.map(({name,run,enabled
6407
6119
  })=>({name:name.replace(PLUGIN_ID,()=>LEGACY_PLUGIN_ID),run,enabled
6408
6120
  }))]
6409
6121
  })
6410
- onCleanup18(unregisterCommands)
6411
- createEffect16(()=>{const unregister=props.api.keymap.registerLayer({bindings:[{key:props.preferences.focusKey(),cmd:FOCUS_COMMAND
6122
+ onCleanup19(unregisterCommands)
6123
+ createEffect15(()=>{const unregister=props.api.keymap.registerLayer({bindings:[{key:props.preferences.focusKey(),cmd:FOCUS_COMMAND
6412
6124
  }]
6413
6125
  })
6414
- onCleanup18(unregister)
6126
+ onCleanup19(unregister)
6415
6127
  })
6416
6128
  return _$createElement("box")
6417
6129
  }
@@ -6431,6 +6143,154 @@ return _$createElement("box")
6431
6143
 
6432
6144
 
6433
6145
 
6146
+ function toolbarLayout(keys,width,mode){const columns=Math.max(1,Math.floor((Math.max(3,width) + 1) / 4))
6147
+ const shown=mode==="wrap"||keys.length<=columns?keys.length:Math.max(0,columns-1)
6148
+ const visible=keys.slice(0,shown)
6149
+ const overflow=keys.slice(shown)
6150
+ const controls=[...visible,...overflow.length>0?["toolbar:more"]:[]]
6151
+ return{columns,overflow,rows:Array.from({length:Math.ceil(controls.length / columns)},(_,row)=>controls.slice(row*columns,(row + 1)*columns))
6152
+ }}
6153
+
6154
+ function createToolbarModel(props){const icons=useIcons()
6155
+ const revision=createQuickActionRevision(props.api)
6156
+ const pins=()=>props.preferences.toolbarPins?.()??[]
6157
+ const needsSkills=createMemo14(()=>pins().some((pin)=>pin.kind==="skill"))
6158
+ const target=createMemo14(()=>props.skills.target())
6159
+ createEffect16(()=>{if(!needsSkills())
6160
+ return
6161
+ const current=target()
6162
+ const release=untrack7(()=>props.skills.activate(current))
6163
+ onCleanup20(release)
6164
+ untrack7(()=>{props.skills.refresh(current).catch(()=>{})
6165
+ })
6166
+ })
6167
+ function view(pin){revision()
6168
+ if(pin.kind==="action"){const action=QUICK_ACTIONS.find((item)=>item.command===pin.id)
6169
+ const state=quickActionState(props.api,pin.id)
6170
+ const stateLabel=quickActionStates(props.api,pin.id).find((item)=>item.id===state)?.label
6171
+ return{label:quickActionLabel(props.api,action),stateLabel,icon:state?pin.stateIcons?.[state]??pin.icon:pin.icon,reason:quickActionDisabledReason(props.api,action)
6172
+ }}
6173
+ const skill=props.skills.list(target()).find((item)=>item.location===pin.location&&item.name===pin.name)
6174
+ const request=props.skills.state(target())
6175
+ const unavailable=request.status==="loading"?"Loading Skills":"Skill is unavailable in this workspace"
6176
+ return{label:pin.name,icon:pin.icon,stateLabel:undefined,reason:request.error?.message??(skill?skillUnavailable(props.skills,skill):unavailable)
6177
+ }}
6178
+ function run(key){const pin=pins().find((item)=>toolbarPinKey(item)===key)
6179
+ if(!pin)
6180
+ return
6181
+ const item=view(pin)
6182
+ if(item.reason){props.api.ui.toast({variant:"warning",title:item.label,message:item.reason})
6183
+ return
6184
+ }
6185
+ if(pin.kind==="action"){if(pin.id==="session.new"&&props.onNewSession?.())
6186
+ return
6187
+ const result=props.interaction.dispatchFromReturnTarget(pin.id)
6188
+ if(!result.ok)
6189
+ props.api.ui.toast({variant:"warning",title:item.label,message:`Command is ${result.reason}`})
6190
+ return
6191
+ }
6192
+ const skill=props.skills.list(target()).find((candidate)=>candidate.location===pin.location&&candidate.name===pin.name)
6193
+ if(!skill)
6194
+ return
6195
+ const route=JSON.stringify(props.api.route.current)
6196
+ const dialogs=createDialogStack(props.api,icons.style,()=>route===JSON.stringify(props.api.route.current),icons.multilineCorners)
6197
+ activateSkill({api:props.api,controller:props.skills,access:props.preferences,skill,dialogs})
6198
+ }
6199
+ return{pins,view,run}}
6200
+
6201
+
6202
+
6203
+ function ToolbarButton(props){const icons=useIcons()
6204
+ const [hovered,setHovered]=createSignal32(false)
6205
+ const item=useSidebarItem(props.api,props.interaction,{id:props.id,position:()=>({section:0,row:props.row + 1,column:props.column
6206
+ }),activate:props.onRun
6207
+ },()=>props.reason?props.api.theme.current.textMuted:props.api.theme.current.accent,"control")
6208
+ createEffect17(()=>props.onDetails(props.id,item.focused()||hovered()))
6209
+ onCleanup21(()=>props.onDetails(props.id,false))
6210
+ return _$createComponent(IconControl,{get id(){return props.id
6211
+ },ref(r$){var _ref$=item.ref
6212
+ typeof _ref$==="function"?_ref$(r$):item.ref=r$
6213
+ },get icon(){return terminalIcon(props.icon,icons.style())
6214
+ },get backgroundColor(){return item.backgroundColor()
6215
+ },get foregroundColor(){return _$memo(()=>!!props.reason)()?props.api.theme.current.textMuted:item.foregroundColor()
6216
+ },onMouseOver:()=>{item.onMouseOver()
6217
+ setHovered(true)
6218
+ },onMouseOut:()=>{item.onMouseOut()
6219
+ setHovered(false)
6220
+ },onMouseUp:(event)=>item.activate(event)
6221
+ })
6222
+ }
6223
+ function SidebarToolbar(props){const model=createToolbarModel(props)
6224
+ const icons=useIcons()
6225
+ const [width,setWidth]=createSignal33(3)
6226
+ const [detail,setDetail]=createSignal33()
6227
+ const keys=createMemo15(()=>model.pins().map((pin)=>toolbarPinKey(pin)))
6228
+ const layout=createMemo15(()=>toolbarLayout(keys(),width(),props.preferences.toolbarOverflow?.()??"menu"))
6229
+ const rows=createMemo15(()=>layout().rows.map((_,index)=>index))
6230
+ const byKey=createMemo15(()=>new Map(model.pins().map((pin)=>[toolbarPinKey(pin),pin])))
6231
+ const view=(key)=>{const pin=byKey().get(key)
6232
+ return pin&&model.view(pin)
6233
+ }
6234
+ const details=createMemo15(()=>{if(detail()==="toolbar:more")
6235
+ return "More pinned actions and Skills"
6236
+ const item=view(detail()??"")
6237
+ return item?[item.label,item.stateLabel,item.reason].filter(Boolean).join(" \xB7 "):undefined
6238
+ })
6239
+ function showMore(){const route=JSON.stringify(props.api.route.current)
6240
+ const dialogs=createDialogStack(props.api,icons.style,()=>route===JSON.stringify(props.api.route.current),icons.multilineCorners)
6241
+ dialogs.open(()=>_$createComponent(SelectionMenu,{get api(){return props.api
6242
+ },title:"More pinned buttons",height:16,get options(){return layout().overflow.flatMap((key)=>{const item=view(key)
6243
+ return item?[{title:item.label,value:key,description:item.reason??item.stateLabel??"Run pinned item"
6244
+ }]:[]
6245
+ })
6246
+ },onSelect:(option)=>{if(view(option.value)?.reason){model.run(option.value)
6247
+ return
6248
+ }
6249
+ dialogs.close()
6250
+ model.run(option.value)
6251
+ }}))
6252
+ }
6253
+ return _$createComponent(Show27,{get when(){return keys().length>0
6254
+ },get children(){var _el$=_$createElement("box")
6255
+ _$setProp(_el$,"id","opencode-navigator.toolbar")
6256
+ _$setProp(_el$,"onSizeChange",function(){setWidth(this.width)
6257
+ })
6258
+ _$insert(_el$,_$createComponent(For17,{get each(){return rows()
6259
+ },children:(row)=>(()=>{var _el$2=_$createElement("box")
6260
+ _$setProp(_el$2,"flexDirection","row")
6261
+ _$setProp(_el$2,"gap",1)
6262
+ _$insert(_el$2,_$createComponent(For17,{get each(){return layout().rows[row]
6263
+ },children:(key,column)=>_$createComponent(ToolbarButton,_$mergeProps(props,{id:`opencode-navigator.toolbar.${key}`,row,get column(){return column()
6264
+ },get label(){return view(key)?.label??"More"
6265
+ },get icon(){return key==="toolbar:more"?"list":view(key)?.icon??"bolt"
6266
+ },get reason(){return view(key)?.reason
6267
+ },onRun:()=>key==="toolbar:more"?showMore():model.run(key),onDetails:(_id,active)=>setDetail((current)=>active?key:current===key?undefined:current)
6268
+ }))
6269
+ }))
6270
+ return _el$2
6271
+ })()
6272
+ }),null)
6273
+ _$insert(_el$,_$createComponent(Show27,{get when(){return details()
6274
+ },children:(text)=>(()=>{var _el$3=_$createElement("text")
6275
+ _$setProp(_el$3,"height",1)
6276
+ _$setProp(_el$3,"truncate",true)
6277
+ _$setProp(_el$3,"wrapMode","none")
6278
+ _$insert(_el$3,text)
6279
+ _$effect((_$p)=>_$setProp(_el$3,"fg",props.api.theme.current.textMuted,_$p))
6280
+ return _el$3
6281
+ })()
6282
+ }),null)
6283
+ return _el$
6284
+ }})
6285
+ }
6286
+
6287
+
6288
+
6289
+
6290
+
6291
+
6292
+
6293
+
6434
6294
 
6435
6295
 
6436
6296
  function createSkillSectionModel(props,query){const target=createMemo16(()=>props.controller.target())
@@ -6442,10 +6302,10 @@ const filtered=createMemo16(()=>list().filter((item)=>matchesFilter(query(),item
6442
6302
  const visibility=createListVisibility({items:filtered,limit:()=>props.preferences.sectionItemLimit?.("skills")??0,resetKey:()=>JSON.stringify([target().key,query()])
6443
6303
  })
6444
6304
  const state=createMemo16(()=>props.controller.state(target()))
6445
- createEffect17(()=>{const current=target()
6446
- const deactivate=untrack6(()=>props.controller.activate?.(current)??(()=>{}))
6447
- onCleanup19(deactivate)
6448
- untrack6(()=>void props.controller.refresh(current).catch(()=>{}))
6305
+ createEffect18(()=>{const current=target()
6306
+ const deactivate=untrack8(()=>props.controller.activate?.(current)??(()=>{}))
6307
+ onCleanup22(deactivate)
6308
+ untrack8(()=>void props.controller.refresh(current).catch(()=>{}))
6449
6309
  })
6450
6310
  async function useSkill(item){try{const isInserted=await props.controller.use(target(),item.name)
6451
6311
  if(isInserted)
@@ -6468,9 +6328,11 @@ return{target,recent,grouped,list,filtered,visibility,state,useSkill,skillGroup}
6468
6328
 
6469
6329
 
6470
6330
 
6331
+
6471
6332
  function SkillRow(props){const{api,interaction,grouped
6472
6333
  }=useSidebarList()
6473
6334
  const icons=useIcons()
6335
+ const toolbar=useToolbar()
6474
6336
  const id=()=>`${PLUGIN_ID}.skill.${props.item.location || props.item.name}`
6475
6337
  const row=useSidebarItem(api,interaction,{id:id(),position:()=>({...props.position,column:1
6476
6338
  }),activate:props.onUse
@@ -6494,24 +6356,21 @@ _$insert(_el$,()=>props.item.name,null)
6494
6356
  _$effect((_$p)=>_$setProp(_el$,"fg",row.foregroundColor(),_$p))
6495
6357
  return _el$
6496
6358
  })()
6359
+ },get trailing(){return _$createComponent(Show28,{when:toolbar,get children(){return _$createComponent(SidebarPinControl,{get id(){return id()
6360
+ },get position(){return props.position
6361
+ },get pin(){return{kind:"skill",name:props.item.name,location:props.item.location,icon:"book"
6362
+ }}})
6363
+ }})
6497
6364
  }})
6498
6365
  }
6499
6366
  function SkillsSection(props){const dialogs=useDialogs(props.api)
6500
- const [query,setQuery]=createSignal31("")
6367
+ const toolbar=useToolbar()
6368
+ const [query,setQuery]=createSignal34("")
6501
6369
  const model=createSkillSectionModel(props,query)
6502
6370
  const navigationSection=()=>props.navigationSection??3
6503
- function selectSkill(item){if(!props.preferences.shouldConfirmSkill(item)){model.useSkill(item)
6504
- return
6505
- }
6506
- showSkillDetails(item)
6507
- }
6508
- function showSkillDetails(item){dialogs.open(()=>_$createComponent(SkillDialog,{get api(){return props.api
6509
- },skill:item,get favorite(){return props.preferences.isFavoriteSkill?.(item)??false
6510
- },get favoriteDisabled(){return props.preferences.ready?.()===false
6511
- },onToggleFavorite:()=>props.preferences.toggleFavoriteSkill?.(item),onAccept:(skipConfirmation)=>{if(skipConfirmation)
6512
- props.preferences.skipSkillConfirmation(item)
6513
- model.useSkill(item)
6514
- }}))
6371
+ function selectSkill(item){activateSkill({api:props.api,controller:props.controller,access:props.preferences,dialogs,skill:item,onConfigure:toolbar?(navigation)=>toolbar.configure({kind:"skill",name:item.name,location:item.location,icon:"book"
6372
+ },navigation):undefined
6373
+ })
6515
6374
  }
6516
6375
  return _$createComponent(Section,{get api(){return props.api
6517
6376
  },get interaction(){return props.interaction
@@ -6530,7 +6389,7 @@ _$insert(_el$,_$createComponent(SectionFilter,{get api(){return props.api
6530
6389
  }},get query(){return query()
6531
6390
  },placeholder:"Filter skills...",onInput:setQuery
6532
6391
  }),null)
6533
- _$insert(_el$,_$createComponent(Show23,{get when(){return model.filtered().length>0
6392
+ _$insert(_el$,_$createComponent(Show29,{get when(){return model.filtered().length>0
6534
6393
  },get fallback(){return(()=>{var _el$2=_$createElement("text")
6535
6394
  _$insertNode(_el$2,_$createTextNode(`No matching skills`))
6536
6395
  _$effect((_$p)=>_$setProp(_el$2,"fg",props.api.theme.current.textMuted,_$p))
@@ -6540,8 +6399,8 @@ return _el$2
6540
6399
  },get interaction(){return props.interaction
6541
6400
  },get grouped(){return model.grouped
6542
6401
  },get density(){return props.preferences.rowDensity?.()??"compact"
6543
- },get children(){return _$createComponent(For17,{get each(){return model.visibility.visible()
6544
- },children:(item,index)=>[_$createComponent(Show23,{get when(){return _$memo(()=>!!model.grouped())()&&(index()===0||model.visibility.visible()[index()-1]?.bucket!==item.bucket)
6402
+ },get children(){return _$createComponent(For18,{get each(){return model.visibility.visible()
6403
+ },children:(item,index)=>[_$createComponent(Show29,{get when(){return _$memo(()=>!!model.grouped())()&&(index()===0||model.visibility.visible()[index()-1]?.bucket!==item.bucket)
6545
6404
  },get children(){var _el$4=_$createElement("text")
6546
6405
  _$setProp(_el$4,"height",1)
6547
6406
  _$setProp(_el$4,"wrapMode","none")
@@ -6586,18 +6445,18 @@ return _el$
6586
6445
  function createSubagentSectionModel(props){const list=createMemo17(()=>props.controller.list(props.sessionID))
6587
6446
  const recent=createMemo17(()=>props.controller.recent?.(props.sessionID)??[])
6588
6447
  const rows=createMemo17(()=>buildSubagentView(list(),recent()))
6589
- const [query,setQuery]=createSignal32("")
6590
- const [mode,setMode]=createSignal32("all")
6448
+ const [query,setQuery]=createSignal35("")
6449
+ const [mode,setMode]=createSignal35("all")
6591
6450
  const counts=createMemo17(()=>countSubagentView(rows(),query()))
6592
6451
  const tabs=createMemo17(()=>["all","active","recent",...counts().errors>0?["errors"]:[]])
6593
6452
  const filtered=createMemo17(()=>filterSubagentView(rows(),mode(),query()))
6594
6453
  const parentID=createMemo17(()=>props.api.state?.session?.get(props.sessionID)?.parentID)
6595
6454
  const targetKey=createMemo17(()=>props.controller.target?.(props.sessionID).key??props.sessionID)
6596
- createEffect18(()=>{targetKey()
6455
+ createEffect19(()=>{targetKey()
6597
6456
  setQuery("")
6598
6457
  setMode("all")
6599
6458
  })
6600
- createEffect18(()=>{if(mode()!=="all"&&counts()[mode()]===0)
6459
+ createEffect19(()=>{if(mode()!=="all"&&counts()[mode()]===0)
6601
6460
  setMode("all")
6602
6461
  })
6603
6462
  const visibility=createListVisibility({items:filtered,limit:()=>props.preferences.sectionItemLimit?.("subagents")??0,resetKey:()=>JSON.stringify([targetKey(),query(),mode()])
@@ -6607,11 +6466,11 @@ const now=createSubagentClock(clockKey)
6607
6466
  const byId=createMemo17(()=>new Map(visibility.visible().map((item)=>[item.session.id,item])))
6608
6467
  const ids=createMemo17(()=>visibility.visible().map((item)=>item.session.id))
6609
6468
  const state=createMemo17(()=>props.controller.state(props.sessionID))
6610
- createEffect18(()=>{const sessionID=props.sessionID
6469
+ createEffect19(()=>{const sessionID=props.sessionID
6611
6470
  targetKey()
6612
- const deactivate=untrack7(()=>props.controller.activate?.(sessionID)??(()=>{}))
6613
- onCleanup20(deactivate)
6614
- untrack7(()=>void props.controller.refresh(sessionID).catch(()=>{}))
6471
+ const deactivate=untrack9(()=>props.controller.activate?.(sessionID)??(()=>{}))
6472
+ onCleanup23(deactivate)
6473
+ untrack9(()=>void props.controller.refresh(sessionID).catch(()=>{}))
6615
6474
  })
6616
6475
  return{list,recent,rows,query,setQuery,mode,setMode,counts,tabs,filtered,parentID,visibility,now,byId,ids,state
6617
6476
  }}
@@ -6668,7 +6527,7 @@ return()=>_c$()?`${props.item.run.startedBeforeObservation ? `${icons.icon("rece
6668
6527
  _$effect((_$p)=>_$setProp(_el$3,"fg",row.focused()?row.foregroundColor():theme().textMuted,_$p))
6669
6528
  return _el$3
6670
6529
  })()
6671
- },get details(){return [_$createComponent(Show24,{get when(){return props.item.run?.errorMessage
6530
+ },get details(){return [_$createComponent(Show30,{get when(){return props.item.run?.errorMessage
6672
6531
  },get children(){var _el$4=_$createElement("text"),_el$5=_$createTextNode(`: `)
6673
6532
  _$insertNode(_el$4,_el$5)
6674
6533
  _$setProp(_el$4,"wrapMode","word")
@@ -6676,12 +6535,12 @@ _$insert(_el$4,()=>cancelled()?"Cancelled":"Error",_el$5)
6676
6535
  _$insert(_el$4,()=>props.item.run?.errorMessage,null)
6677
6536
  _$effect((_$p)=>_$setProp(_el$4,"fg",row.focused()?row.foregroundColor():failed()?theme().error:theme().textMuted,_$p))
6678
6537
  return _el$4
6679
- }}),_$createComponent(Show24,{get when(){return props.item.unavailable
6538
+ }}),_$createComponent(Show30,{get when(){return props.item.unavailable
6680
6539
  },get children(){var _el$6=_$createElement("text")
6681
6540
  _$insertNode(_el$6,_$createTextNode(`Worker status unavailable`))
6682
6541
  _$effect((_$p)=>_$setProp(_el$6,"fg",theme().warning,_$p))
6683
6542
  return _el$6
6684
- }}),_$createComponent(Show24,{get when(){return _$memo(()=>props.item.status.type==="retry")()?props.item.status:undefined
6543
+ }}),_$createComponent(Show30,{get when(){return _$memo(()=>props.item.status.type==="retry")()?props.item.status:undefined
6685
6544
  },children:(status)=>(()=>{var _el$0=_$createElement("text"),_el$1=_$createTextNode(`Retry #`),_el$10=_$createTextNode(` \xB7 `),_el$11=_$createTextNode(`s \xB7 `)
6686
6545
  _$insertNode(_el$0,_el$1)
6687
6546
  _$insertNode(_el$0,_el$10)
@@ -6693,7 +6552,7 @@ _$insert(_el$0,()=>status().message,null)
6693
6552
  _$effect((_$p)=>_$setProp(_el$0,"fg",row.focused()?row.foregroundColor():theme().warning,_$p))
6694
6553
  return _el$0
6695
6554
  })()
6696
- }),_$createComponent(Show24,{get when(){return _$memo(()=>!!idle())()&&!props.item.run?.errorMessage
6555
+ }),_$createComponent(Show30,{get when(){return _$memo(()=>!!idle())()&&!props.item.run?.errorMessage
6697
6556
  },get children(){var _el$8=_$createElement("text")
6698
6557
  _$insertNode(_el$8,_$createTextNode(`Finished`))
6699
6558
  _$effect((_$p)=>_$setProp(_el$8,"fg",theme().textMuted,_$p))
@@ -6704,12 +6563,12 @@ return _el$8
6704
6563
  function SubagentList(props){return _$createComponent(SidebarRowList,{get api(){return props.api
6705
6564
  },get interaction(){return props.interaction
6706
6565
  },get density(){return props.density
6707
- },get children(){return _$createComponent(For18,{get each(){return props.ids
6566
+ },get children(){return _$createComponent(For19,{get each(){return props.ids
6708
6567
  },children:(id,index)=>{const initial=props.itemById(id)
6709
6568
  const item=()=>props.itemById(id)??initial
6710
6569
  const startsGroup=()=>index()===0||props.visible[index()-1]?.group!==item().group
6711
6570
  return(()=>{var _el$=_$createElement("box")
6712
- _$insert(_el$,_$createComponent(Show25,{get when(){return startsGroup()
6571
+ _$insert(_el$,_$createComponent(Show31,{get when(){return startsGroup()
6713
6572
  },get children(){var _el$2=_$createElement("text"),_el$3=_$createElement("b")
6714
6573
  _$insertNode(_el$2,_el$3)
6715
6574
  _$insert(_el$3,()=>item().group)
@@ -6735,7 +6594,7 @@ return _$createComponent(Section,{get api(){return props.api
6735
6594
  },sectionId:`${PLUGIN_ID}.section.subagents`,get navigationSection(){return navigationSection()
6736
6595
  },title:"SUBAGENTS",section:"subagents",get summary(){return `${model.list().length} active \xB7 ${model.recent().length} recent`
6737
6596
  },get open(){return props.preferences.expanded().subagents
6738
- },onToggle:()=>props.preferences.toggleSectionExpanded("subagents"),get children(){return [_$createComponent(Show26,{get when(){return model.parentID()
6597
+ },onToggle:()=>props.preferences.toggleSectionExpanded("subagents"),get children(){return [_$createComponent(Show32,{get when(){return model.parentID()
6739
6598
  },children:(id)=>_$createComponent(McpBulkAction,{get api(){return props.api
6740
6599
  },get interaction(){return props.interaction
6741
6600
  },id:`${PLUGIN_ID}.subagents.parent`,get position(){return{section:navigationSection(),row:1,column:0
@@ -6758,7 +6617,7 @@ _$insert(_el$,_$createComponent(SectionFilter,{get api(){return props.api
6758
6617
  }}),_el$2)
6759
6618
  _$setProp(_el$2,"flexDirection","row")
6760
6619
  _$setProp(_el$2,"flexWrap","wrap")
6761
- _$insert(_el$2,_$createComponent(For19,{get each(){return model.tabs()
6620
+ _$insert(_el$2,_$createComponent(For20,{get each(){return model.tabs()
6762
6621
  },children:(value,index)=>_$createComponent(SectionTab,{get api(){return props.api
6763
6622
  },get interaction(){return props.interaction
6764
6623
  },id:`${PLUGIN_ID}.subagents.filter.${value}`,get position(){return{section:navigationSection(),row:4,column:index()
@@ -6769,7 +6628,7 @@ _$insert(_el$2,_$createComponent(For19,{get each(){return model.tabs()
6769
6628
  },onActivate:()=>model.setMode(value)
6770
6629
  })
6771
6630
  }))
6772
- _$insert(_el$,_$createComponent(Show26,{get when(){return model.filtered().length===0
6631
+ _$insert(_el$,_$createComponent(Show32,{get when(){return model.filtered().length===0
6773
6632
  },get children(){var _el$3=_$createElement("text")
6774
6633
  _$insertNode(_el$3,_$createTextNode(`No matching subagents`))
6775
6634
  _$effect((_$p)=>_$setProp(_el$3,"fg",props.api.theme.current.textMuted,_$p))
@@ -6810,6 +6669,23 @@ return _el$
6810
6669
 
6811
6670
 
6812
6671
 
6672
+ function NativeTodoNotice(props){const icons=useIcons()
6673
+ return(()=>{var _el$=_$createElement("text"),_el$2=_$createTextNode(` Native OpenCode Todo. Edit tasks through chat and todowrite.`)
6674
+ _$insertNode(_el$,_el$2)
6675
+ _$setProp(_el$,"wrapMode","word")
6676
+ _$insert(_el$,()=>icons.icon("info"),_el$2)
6677
+ _$insert(_el$,()=>props.empty?" OpenCode 2.1 enables the tool through experimental.todo.":"",null)
6678
+ _$effect((_$p)=>_$setProp(_el$,"fg",props.api.theme.current.textMuted,_$p))
6679
+ return _el$
6680
+ })()
6681
+ }
6682
+
6683
+
6684
+
6685
+
6686
+
6687
+
6688
+
6813
6689
 
6814
6690
 
6815
6691
 
@@ -6853,7 +6729,7 @@ _$insert(_el$2,()=>icons.icon(done()?"done":active()?"busy":cancelled()?"close":
6853
6729
  _$setProp(_el$3,"flexGrow",1)
6854
6730
  _$setProp(_el$3,"wrapMode","word")
6855
6731
  _$insert(_el$3,()=>props.item.content)
6856
- _$insert(_el$,_$createComponent(Show27,{get when(){return props.item.priority==="high"||props.item.priority==="medium"||props.item.priority==="low"
6732
+ _$insert(_el$,_$createComponent(Show33,{get when(){return props.item.priority==="high"||props.item.priority==="medium"||props.item.priority==="low"
6857
6733
  },get children(){var _el$4=_$createElement("text"),_el$5=_$createElement("b"),_el$6=_$createTextNode(` `)
6858
6734
  _$insertNode(_el$4,_el$5)
6859
6735
  _$setProp(_el$4,"width",2)
@@ -6880,7 +6756,7 @@ _$insertNode(_el$,_el$2)
6880
6756
  _$setProp(_el$,"gap",1)
6881
6757
  _$setProp(_el$2,"flexDirection","row")
6882
6758
  _$setProp(_el$2,"flexWrap","wrap")
6883
- _$insert(_el$2,_$createComponent(For20,{each:["all","active","finished"],children:(value,index)=>_$createComponent(SectionTab,{get api(){return props.api
6759
+ _$insert(_el$2,_$createComponent(For21,{each:["all","active","finished"],children:(value,index)=>_$createComponent(SectionTab,{get api(){return props.api
6884
6760
  },get interaction(){return props.interaction
6885
6761
  },id:`${PLUGIN_ID}.todo.filter.${value}`,get position(){return{section:navigationSection(),row:tabsRow(),column:index()
6886
6762
  }},get label(){return value[0].toUpperCase() + value.slice(1)
@@ -6889,17 +6765,17 @@ _$insert(_el$2,_$createComponent(For20,{each:["all","active","finished"],childre
6889
6765
  },onActivate:()=>props.setMode(value)
6890
6766
  })
6891
6767
  }))
6892
- _$insert(_el$,_$createComponent(Show28,{get when(){return props.view.rows.length>0
6768
+ _$insert(_el$,_$createComponent(Show34,{get when(){return props.view.rows.length>0
6893
6769
  },get fallback(){return _$createComponent(EmptyTodo,{get api(){return props.api
6894
6770
  },get mode(){return props.mode
6895
6771
  }})
6896
6772
  },get children(){return _$createComponent(SidebarRowList,{get api(){return props.api
6897
6773
  },get interaction(){return props.interaction
6898
6774
  },get density(){return props.density
6899
- },get children(){return _$createComponent(For20,{get each(){return props.visibility.visible()
6775
+ },get children(){return _$createComponent(For21,{get each(){return props.visibility.visible()
6900
6776
  },children:(row,index)=>{const startsGroup=()=>index()===0||props.visibility.visible()[index()-1].group!==row.group
6901
6777
  return(()=>{var _el$3=_$createElement("box")
6902
- _$insert(_el$3,_$createComponent(Show28,{get when(){return startsGroup()
6778
+ _$insert(_el$3,_$createComponent(Show34,{get when(){return startsGroup()
6903
6779
  },get children(){var _el$4=_$createElement("text"),_el$5=_$createElement("b")
6904
6780
  _$insertNode(_el$4,_el$5)
6905
6781
  _$insert(_el$5,()=>row.group)
@@ -6936,7 +6812,7 @@ return _el$6
6936
6812
 
6937
6813
 
6938
6814
  function TodoGuidanceControl(props){const state=()=>props.controller.guidance(props.sessionID)
6939
- return _$createComponent(Show29,{get when(){return state().available
6815
+ return _$createComponent(Show35,{get when(){return state().available
6940
6816
  },get children(){var _el$=_$createElement("box")
6941
6817
  _$insert(_el$,_$createComponent(SectionTab,{get api(){return props.api
6942
6818
  },get interaction(){return props.interaction
@@ -6946,7 +6822,7 @@ _$insert(_el$,_$createComponent(SectionTab,{get api(){return props.api
6946
6822
  },get disabled(){return state().saving
6947
6823
  },onActivate:()=>void props.controller.setGuidance(props.sessionID,!state().enabled)
6948
6824
  }),null)
6949
- _$insert(_el$,_$createComponent(Show29,{get when(){return state().error
6825
+ _$insert(_el$,_$createComponent(Show35,{get when(){return state().error
6950
6826
  },children:(message)=>(()=>{var _el$2=_$createElement("text")
6951
6827
  _$setProp(_el$2,"wrapMode","word")
6952
6828
  _$insert(_el$2,message)
@@ -6961,33 +6837,41 @@ function TodoSection(props){const list=createMemo18(()=>props.controller.list(pr
6961
6837
  const icons=useIcons()
6962
6838
  const unavailable=()=>hostCapabilityUnavailable(props.api,"todo")
6963
6839
  const managed=()=>("guidance" in props.controller)?props.controller:undefined
6964
- const [mode,setMode]=createSignal33("all")
6840
+ const native=()=>("source" in props.controller)&&props.controller.source==="native"
6841
+ const [mode,setMode]=createSignal36("all")
6965
6842
  const targetKey=createMemo18(()=>props.controller.target?.(props.sessionID).key??props.sessionID)
6966
- createEffect19(()=>{targetKey()
6843
+ createEffect20(()=>{targetKey()
6967
6844
  setMode("all")
6968
6845
  })
6969
6846
  const view=createMemo18(()=>buildTodoView(list(),mode()))
6970
6847
  const visibility=createListVisibility({items:()=>view().rows,limit:()=>props.preferences.sectionItemLimit?.("todo")??0,resetKey:()=>JSON.stringify([targetKey(),mode()])
6971
6848
  })
6972
6849
  const state=createMemo18(()=>props.controller.state(props.sessionID))
6973
- createEffect19(()=>{const sessionID=props.sessionID
6850
+ createEffect20(()=>{const sessionID=props.sessionID
6974
6851
  targetKey()
6975
6852
  if(unavailable())
6976
6853
  return
6977
- const deactivate=untrack8(()=>props.controller.activate?.(sessionID)??(()=>{}))
6978
- onCleanup21(deactivate)
6979
- untrack8(()=>void props.controller.refresh(sessionID).catch(()=>{}))
6854
+ const deactivate=untrack10(()=>props.controller.activate?.(sessionID)??(()=>{}))
6855
+ onCleanup24(deactivate)
6856
+ untrack10(()=>void props.controller.refresh(sessionID).catch(()=>{}))
6980
6857
  })
6981
6858
  const navigationSection=()=>props.navigationSection??1
6982
6859
  return _$createComponent(Section,{get api(){return props.api
6983
6860
  },get interaction(){return props.interaction
6984
6861
  },sectionId:`${PLUGIN_ID}.section.todo`,get navigationSection(){return navigationSection()
6985
6862
  },title:"TODO",section:"todo",get summary(){return _$memo(()=>!!(unavailable()||managed()?.missing(props.sessionID)))()?"\u2014":`${view().counts.completed}/${list().length}`
6863
+ },get headerAction(){return native()?{id:`${PLUGIN_ID}.todo.refresh`,label:()=>`${icons.icon("retry")} Refresh`,disabled:()=>state().status==="loading"||state().status==="refreshing",onActivate:()=>{props.controller.refresh(props.sessionID).catch(()=>{})
6864
+ }}:undefined
6986
6865
  },get open(){return props.preferences.expanded().todo
6987
- },onToggle:()=>props.preferences.toggleSectionExpanded("todo"),get children(){return _$createComponent(Show30,{get when(){return unavailable()
6866
+ },onToggle:()=>props.preferences.toggleSectionExpanded("todo"),get children(){return _$createComponent(Show36,{get when(){return unavailable()
6988
6867
  },get fallback(){return(()=>{var _el$=_$createElement("box")
6989
6868
  _$setProp(_el$,"gap",1)
6990
- _$insert(_el$,_$createComponent(Show30,{get when(){return managed()?.guidance(props.sessionID).available
6869
+ _$insert(_el$,_$createComponent(Show36,{get when(){return native()
6870
+ },get children(){return _$createComponent(NativeTodoNotice,{get api(){return props.api
6871
+ },get empty(){return list().length===0
6872
+ }})
6873
+ }}),null)
6874
+ _$insert(_el$,_$createComponent(Show36,{get when(){return managed()?.guidance(props.sessionID).available
6991
6875
  },get children(){return _$createComponent(TodoGuidanceControl,{get api(){return props.api
6992
6876
  },get controller(){return managed()
6993
6877
  },get sessionID(){return props.sessionID
@@ -6995,7 +6879,7 @@ _$insert(_el$,_$createComponent(Show30,{get when(){return managed()?.guidance(pr
6995
6879
  },get navigationSection(){return navigationSection()
6996
6880
  }})
6997
6881
  }}),null)
6998
- _$insert(_el$,_$createComponent(Show30,{get when(){return managed()?.missing(props.sessionID)
6882
+ _$insert(_el$,_$createComponent(Show36,{get when(){return managed()?.missing(props.sessionID)
6999
6883
  },get fallback(){return _$createComponent(SectionRequestBody,{get api(){return props.api
7000
6884
  },get interaction(){return props.interaction
7001
6885
  },id:`${PLUGIN_ID}.retry.todo`,get position(){return{section:navigationSection(),row:1,column:0
@@ -7032,8 +6916,11 @@ return _el$4
7032
6916
  }
7033
6917
  function SidebarContent(props){const sections=props.preferences.sections
7034
6918
  const visibleSections=createMemo19(()=>props.preferences.sectionOrder().filter((section)=>sections()[section]&&supportsSidebarSection(props.api,section)))
7035
- onCleanup22(()=>props.interaction.setContentRoot(undefined))
7036
- return(()=>{var _el$=_$createElement("box")
6919
+ onCleanup25(()=>props.interaction.setContentRoot(undefined))
6920
+ return _$createComponent(ToolbarProvider,{get api(){return props.api
6921
+ },get preferences(){return props.preferences
6922
+ },get skills(){return props.skills
6923
+ },get children(){var _el$=_$createElement("box")
7037
6924
  _$use((node)=>props.interaction.setContentRoot(node),_el$)
7038
6925
  _$setProp(_el$,"id",`${PLUGIN_ID}.root`)
7039
6926
  _$setProp(_el$,"focusable",true)
@@ -7044,7 +6931,8 @@ event.preventDefault()
7044
6931
  event.stopPropagation()
7045
6932
  props.interaction.leave()
7046
6933
  })
7047
- _$insert(_el$,_$createComponent(For21,{get each(){return visibleSections()
6934
+ _$insert(_el$,_$createComponent(SidebarToolbar,props),null)
6935
+ _$insert(_el$,_$createComponent(For22,{get each(){return visibleSections()
7048
6936
  },children:(section,index)=>_$createComponent(SectionBoundary,{get api(){return props.api
7049
6937
  },get divided(){return index()<visibleSections().length-1
7050
6938
  },get children(){return _$createComponent(Switch,{get children(){return [_$createComponent(Match,{when:section==="limits",get children(){return props.limitsSection(index() + 1)
@@ -7067,7 +6955,7 @@ _$insert(_el$,_$createComponent(For21,{get each(){return visibleSections()
7067
6955
  }})]
7068
6956
  }})
7069
6957
  }})
7070
- }))
6958
+ }),null)
7071
6959
  _$effect((_p$)=>{var _v$=props.interaction.syncFocus,_v$2=props.interaction.syncFocus
7072
6960
  _v$!==_p$.e&&(_p$.e=_$setProp(_el$,"on:focused",_v$,_p$.e))
7073
6961
  _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"on:blurred",_v$2,_p$.t))
@@ -7075,12 +6963,12 @@ return _p$
7075
6963
  },{e:undefined,t:undefined
7076
6964
  })
7077
6965
  return _el$
7078
- })()
6966
+ }})
7079
6967
  }
7080
6968
 
7081
6969
 
7082
6970
  function McpPersistence(props){const persist=createMemo20(()=>props.controller.persist())
7083
- createEffect20(()=>{if(!props.api.state.ready)
6971
+ createEffect21(()=>{if(!props.api.state.ready)
7084
6972
  return
7085
6973
  persist()
7086
6974
  const route=props.api.route.current
@@ -7088,20 +6976,20 @@ const params="params" in route?route.params:undefined
7088
6976
  if(typeof params?.sessionID!=="string")
7089
6977
  return
7090
6978
  const current=props.controller.target()
7091
- onCleanup23(()=>props.controller.deactivate(current))
7092
- untrack9(()=>void props.controller.activate(current).catch(()=>{}))
6979
+ onCleanup26(()=>props.controller.deactivate(current))
6980
+ untrack11(()=>void props.controller.activate(current).catch(()=>{}))
7093
6981
  })
7094
6982
  return _$createElement("box")
7095
6983
  }
7096
- function PreferencesPersistence(props){createEffect20(()=>{const location=currentLocation(props.api)
7097
- untrack9(()=>props.controller.setActiveScope(preferencesScope({directory:location.routing.directory,worktree:props.api.state.path.worktree
6984
+ function PreferencesPersistence(props){createEffect21(()=>{const location=currentLocation(props.api)
6985
+ untrack11(()=>props.controller.setActiveScope(preferencesScope({directory:location.routing.directory,worktree:props.api.state.path.worktree
7098
6986
  })))
7099
6987
  props.controller.load()
7100
6988
  })
7101
6989
  return _$createElement("box")
7102
6990
  }
7103
6991
  function FirstRunWizardPersistence(props){let isChecked=false
7104
- createEffect20(()=>{if(isChecked)
6992
+ createEffect21(()=>{if(isChecked)
7105
6993
  return
7106
6994
  isChecked=true
7107
6995
  showFirstRunWizard(props.api,props.preferences).catch(()=>{})
@@ -7128,7 +7016,7 @@ const settingsId=`${PLUGIN_ID}.settings`
7128
7016
  const settings=useSidebarItem(props.api,props.interaction,{id:settingsId,position:{section:0,row:0,column:0
7129
7017
  },activate:()=>openSettings(props.api,props.preferences,undefined,props.mcp,props.skills)
7130
7018
  },()=>theme().textMuted,"control")
7131
- onCleanup24(()=>props.interaction.setTitleRoot(undefined))
7019
+ onCleanup27(()=>props.interaction.setTitleRoot(undefined))
7132
7020
  return(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("box"),_el$3=_$createElement("box")
7133
7021
  _$insertNode(_el$,_el$2)
7134
7022
  _$use((node)=>props.interaction.setTitleRoot(node),_el$)
@@ -7139,7 +7027,7 @@ _$setProp(_el$2,"flexDirection","row")
7139
7027
  _$setProp(_el$2,"justifyContent","space-between")
7140
7028
  _$setProp(_el$2,"gap",1)
7141
7029
  _$setProp(_el$3,"flexGrow",1)
7142
- _$insert(_el$3,_$createComponent(Show31,{get when(){return props.preferences.showSessionTitle()
7030
+ _$insert(_el$3,_$createComponent(Show37,{get when(){return props.preferences.showSessionTitle()
7143
7031
  },get children(){var _el$4=_$createElement("text"),_el$5=_$createElement("b")
7144
7032
  _$insertNode(_el$4,_el$5)
7145
7033
  _$setProp(_el$4,"wrapMode","word")
@@ -7147,7 +7035,7 @@ _$insert(_el$5,()=>props.title)
7147
7035
  _$effect((_$p)=>_$setProp(_el$4,"fg",theme().text,_$p))
7148
7036
  return _el$4
7149
7037
  }}),null)
7150
- _$insert(_el$3,_$createComponent(Show31,{get when(){return _$memo(()=>!!props.preferences.showSessionDate())()&&created()
7038
+ _$insert(_el$3,_$createComponent(Show37,{get when(){return _$memo(()=>!!props.preferences.showSessionDate())()&&created()
7151
7039
  },children:(value)=>(()=>{var _el$6=_$createElement("text")
7152
7040
  _$insert(_el$6,value)
7153
7041
  _$effect((_$p)=>_$setProp(_el$6,"fg",theme().textMuted,_$p))
@@ -7196,11 +7084,11 @@ function createLimitsRefresh(options,schedule=scheduleInterval){let disposed=fal
7196
7084
  const selectedKey=createMemo22(()=>JSON.stringify(options.selectedModel?.()))
7197
7085
  const targetKey=createMemo22(()=>JSON.stringify(options.controller.current().model))
7198
7086
  const interval=createMemo22(()=>(parseLimitsRefreshMinutes(options.refreshMinutes?.())??DEFAULT_LIMITS_REFRESH_MINUTES)*60000)
7199
- createEffect21(on2(selectedKey,()=>{const model=options.selectedModel?.()
7087
+ createEffect22(on2(selectedKey,()=>{const model=options.selectedModel?.()
7200
7088
  if(model&&options.accountSource)
7201
7089
  options.accountSource.refresh(model).catch(()=>{})
7202
7090
  }))
7203
- createEffect21(on2(targetKey,()=>{const{model,adapter}=options.controller.current()
7091
+ createEffect22(on2(targetKey,()=>{const{model,adapter}=options.controller.current()
7204
7092
  if(model&&adapter)
7205
7093
  options.controller.refresh()
7206
7094
  }))
@@ -7213,9 +7101,9 @@ await options.accountSource.refresh(model)
7213
7101
  if(!disposed&&target===targetKey())
7214
7102
  await options.controller.refresh()
7215
7103
  }
7216
- createEffect21(on2(interval,(milliseconds)=>{onCleanup25(schedule(()=>void refresh().catch(()=>{}),milliseconds))
7104
+ createEffect22(on2(interval,(milliseconds)=>{onCleanup28(schedule(()=>void refresh().catch(()=>{}),milliseconds))
7217
7105
  }))
7218
- onCleanup25(()=>{disposed=true
7106
+ onCleanup28(()=>{disposed=true
7219
7107
  })
7220
7108
  }
7221
7109
  function LimitsPersistence(props){createLimitsRefresh(props)
@@ -7225,20 +7113,16 @@ import {homedir} from "os"
7225
7113
 
7226
7114
  function location(input){return input.directory?{location:{directory:input.directory}}:{}}
7227
7115
  function mcpItem(server){return{name:server.name,status:server.status.status,...server.status.error&&{error:server.status.error}}}
7228
- function skillKey(directory,name){return `${directory}\x00${name}`
7229
- }
7230
- function createV2ClientAdapter(context){const skillIDs=new Map
7231
- return{state:{mcp:()=>(context.data.location.mcp.server.list(context.location)??[]).map((server)=>mcpItem(server))
7116
+ function createV2ClientAdapter(context){return{state:{mcp:()=>(context.data.location.mcp.server.list(context.location)??[]).map((server)=>mcpItem(server))
7232
7117
  },client:{app:{async skills(input,options={}){const response=await context.client.skill.list(location(input),{signal:options.signal})
7233
- const directory=input.directory??response.location.directory
7234
- const data=response.data.map((skill)=>{skillIDs.set(skillKey(directory,skill.name),skill.id)
7235
- return{name:skill.name,description:skill.description,location:skill.path,content:skill.content
7236
- }})
7118
+ const data=response.data.map((skill)=>({name:skill.name,description:skill.description,location:skill.path,content:skill.content
7119
+ }))
7237
7120
  return{data}}},tui:{async appendPrompt(input,options={}){const route=context.ui.router.current()
7238
7121
  const name=/^\/([^\s]+)\s*$/u.exec(input.text)?.[1]
7239
7122
  const directory=input.directory??context.location?.directory??context.data.location.default().directory
7240
7123
  const session=route.type==="session"?context.data.session.get(route.sessionID):undefined
7241
- const id=name?skillIDs.get(skillKey(directory,name)):undefined
7124
+ const candidates=context.data.location.skill.list({directory})?.filter((skill)=>skill.name===name)??[]
7125
+ const id=candidates.length===1?candidates[0].id:undefined
7242
7126
  if(route.type!=="session"||session?.location.directory!==directory||!id)
7243
7127
  return{data:false}
7244
7128
  await context.client.session.skill({sessionID:route.sessionID,id},{signal:options.signal})
@@ -7247,170 +7131,202 @@ const data=Object.fromEntries(response.data.map((server)=>[server.name,server.st
7247
7131
  return{data}},async connect(input,options={}){await context.client.mcp.connect({server:input.name,...location(input)},{signal:options.signal})
7248
7132
  return{data:undefined}},async disconnect(input,options={}){await context.client.mcp.disconnect({server:input.name,...location(input)},{signal:options.signal})
7249
7133
  return{data:undefined}}}}}}
7250
- var SESSION_UPDATE_EVENTS=new Set(["session.agent.selected","session.model.selected","session.moved","session.renamed","session.permissions"])
7251
- function createV2EventAdapter(context,sessions){return{on(name,handler){let active=true
7252
- const unsubscribe=context.data.listen(({details})=>{const event=details
7253
- if(name==="server.connected"&&event.type==="server.connected"){handler({type:name,properties:{}})
7254
- return
7134
+ var TERMINAL_EVENTS=new Set(["session.execution.succeeded","session.execution.failed","session.execution.interrupted"])
7135
+ function executionStatus(name,event){const sessionID=event.data.sessionID
7136
+ const started=event.type==="session.execution.started"
7137
+ if(typeof sessionID!=="string"||!started&&!TERMINAL_EVENTS.has(event.type))
7138
+ return
7139
+ if(name!=="session.status"&&(name!=="session.idle"||started))
7140
+ return
7141
+ const status=started?{type:"busy"}:{type:"idle"}
7142
+ return{sessionID,status,properties:{sessionID,...name==="session.status"&&{status}}}}
7143
+ var updates=["session.agent.selected","session.model.selected","session.moved","session.renamed","session.permissions","session.metadata.updated"]
7144
+ var executions=["session.execution.started","session.execution.succeeded","session.execution.failed","session.execution.interrupted"]
7145
+ function eventTypes(name){if(name==="session.updated")
7146
+ return updates
7147
+ if(name==="session.status")
7148
+ return ["session.status","session.retry.scheduled",...executions]
7149
+ if(name==="session.idle")
7150
+ return ["session.idle",...executions.slice(1)]
7151
+ if(name==="session.error")
7152
+ return ["session.execution.failed"]
7153
+ if(name==="mcp.tools.changed")
7154
+ return ["mcp.status.changed","mcp.resources.changed"]
7155
+ if(["session.created","session.deleted","server.connected","installation.update-available"].includes(name))
7156
+ return [name]
7157
+ return []
7255
7158
  }
7256
- if(name==="mcp.tools.changed"&&event.type.startsWith("mcp.")){handler({type:name,properties:event.data})
7257
- return
7159
+ function statusFor(name,event){if(name==="session.idle")
7160
+ return{type:"idle"}
7161
+ if(event.type==="session.retry.scheduled")
7162
+ return{type:"retry",attempt:Number(event.data.attempt),next:Number(event.data.at),message:event.data.error?.message??"Retrying"
7258
7163
  }
7259
- if(name==="installation.update-available"&&event.type==="installation.update-available"){if(typeof event.data.version==="string"){handler({type:name,properties:{version:event.data.version}})
7164
+ return event.data.status
7260
7165
  }
7261
- return
7166
+ function createV2EventAdapter(context,sessions){return{on(name,handler){let active=true
7167
+ const disposers=eventTypes(name).map((type)=>context.data.on(type,(value)=>{const event=value
7168
+ const data=event.data??{}
7169
+ const emit=(properties)=>{if(active)
7170
+ handler({type:name,properties})
7262
7171
  }
7263
- if(name==="session.deleted"&&event.type==="session.deleted"){handler({type:name,properties:{sessionID:event.data.sessionID}})
7172
+ const execution=executionStatus(name,{type:event.type,data})
7173
+ if(execution){sessions.setStatus(execution.sessionID,execution.status)
7174
+ emit(execution.properties)
7264
7175
  return
7265
7176
  }
7266
- if(name==="session.status"&&event.type==="session.status"){const sessionID=event.data.sessionID
7267
- const status=event.data.status
7268
- if(typeof sessionID!=="string"||!status||typeof status!=="object")
7177
+ if(name==="server.connected"||name==="mcp.tools.changed"){emit(data)
7269
7178
  return
7270
- sessions.setStatus(sessionID,status)
7271
- handler({type:name,properties:{sessionID,status}})
7179
+ }
7180
+ if(name==="installation.update-available"){if(typeof data.version==="string")
7181
+ emit({version:data.version})
7272
7182
  return
7273
7183
  }
7274
- if(name==="session.idle"&&event.type==="session.idle"){const sessionID=event.data.sessionID
7184
+ const sessionID=data.sessionID
7275
7185
  if(typeof sessionID!=="string")
7276
7186
  return
7277
- sessions.setStatus(sessionID,{type:"idle"})
7278
- handler({type:name,properties:{sessionID}})
7279
- return
7187
+ if(name==="session.status"||name==="session.idle"){const status=statusFor(name,{type:event.type,data})
7188
+ if(status&&typeof status==="object"){sessions.setStatus(sessionID,status)
7189
+ emit(name==="session.idle"?{sessionID}:{sessionID,status})
7280
7190
  }
7281
- if(name==="session.error"&&event.type==="session.execution.failed"){const error=event.data.error
7282
- handler({type:name,properties:{sessionID:event.data.sessionID,error:error&&{name:error.type??"Error",data:{message:error.message??"Session error"}}}})
7283
7191
  return
7284
7192
  }
7285
- const isCreated=name==="session.created"&&event.type==="session.created"
7286
- const isUpdated=name==="session.updated"&&SESSION_UPDATE_EVENTS.has(event.type)
7287
- if(!isCreated&&!isUpdated)
7193
+ if(name==="session.deleted"){emit({sessionID})
7288
7194
  return
7289
- const sessionID=event.data.sessionID
7290
- const info=typeof sessionID==="string"?context.data.session.get(sessionID):undefined
7291
- if(info){handler({type:name,properties:{info:sessions.normalize(info)}})
7195
+ }
7196
+ if(name==="session.error"){const error=data.error
7197
+ emit({sessionID,error:error&&{name:error.type??"Error",data:{message:error.message??"Session error"}}})
7292
7198
  return
7293
7199
  }
7294
- if(typeof sessionID!=="string")
7200
+ const info=context.data.session.get(sessionID)
7201
+ if(info){emit({info:sessions.project(info)})
7295
7202
  return
7203
+ }
7296
7204
  context.data.session.sync(sessionID).then(()=>{const synced=context.data.session.get(sessionID)
7297
- if(active&&synced)
7298
- handler({type:name,properties:{info:sessions.normalize(synced)}})
7205
+ if(synced)
7206
+ emit({info:sessions.project(synced)})
7299
7207
  }).catch(()=>{})
7300
- })
7208
+ }))
7301
7209
  return()=>{active=false
7302
- unsubscribe()
7210
+ for(const dispose of disposers)
7211
+ dispose()
7303
7212
  }}}}
7304
7213
 
7305
-
7306
- var SETTINGS_COMMAND="opencode.settings"
7307
- var PERMISSIONS_ACTION="permission.mode"
7308
- function belongsTo2(renderable,ancestor){if(!renderable||!ancestor)
7309
- return false
7310
- for(let current=renderable;current; current=current.parent){if(current===ancestor)
7311
- return true
7312
- }
7313
- return false
7314
- }
7315
7214
  function enabled(value){return typeof value==="function"?value():value!==false
7316
7215
  }
7317
- function createV2Keymap(context){const [revision,setRevision]=createSignal34(0)
7318
- const layers=new Map
7319
- let sequence=0
7320
- function layerActive(layer){const mode=layer.mode??"base"
7321
- const target=layer.target
7322
- return(mode==="global"||context.keymap.mode.current()===mode)&&enabled(layer.enabled)&&(!target||belongsTo2(context.renderer.currentFocusedRenderable,target))
7323
- }
7324
- function legacyCommand(name){return [...layers].sort(([leftID,left],[rightID,right])=>(right.priority??0)-(left.priority??0)||rightID-leftID).flatMap(([,layer])=>layerActive(layer)?[layer]:[]).flatMap((layer)=>layer.commands??[]).find((command)=>command.name===name&&enabled(command.enabled))
7216
+ function v2LayerCommands(id,layer,available,run,dispatch){const named=(layer.commands??[]).map((command)=>({id:command.name,bind:command.name==="session.new"?"<leader>n":undefined,title:command.title,description:command.desc,group:command.category,palette:command.namespace==="palette"?true:undefined,suggested:command.suggested,enabled:()=>available()&&enabled(command.enabled),run:(input,event)=>run(command,input,event)
7217
+ }))
7218
+ const bindings=(layer.bindings??[]).flatMap((binding,index)=>typeof binding.key==="string"?[{id:`${PLUGIN_ID}.v2-binding.${id}.${index}`,bind:binding.key,enabled:available,run:()=>dispatch(String(binding.cmd))
7219
+ }]:[])
7220
+ return [...named,...bindings]
7325
7221
  }
7326
- function run(command,input="",event){return command.run({keymap,event,focused:context.renderer.currentFocusedRenderable,target:context.renderer.currentFocusedRenderable,data:{},command,input,payload:undefined
7222
+ var SETTINGS_COMMAND="opencode.settings"
7223
+ var PERMISSIONS_ACTION="permission.mode"
7224
+ function createV2Keymap(context){const cleanups=new Set
7225
+ let sequence=0
7226
+ async function run(command,input="",event){await command.run({keymap,event,focused:context.renderer.currentFocusedRenderable,target:context.renderer.currentFocusedRenderable,data:{},command,input,payload:undefined
7327
7227
  })
7328
7228
  }
7329
- async function runV2(command,input="",event){await run(command,input,event)
7330
- }
7331
7229
  const onKeypress=(event)=>{if(event.name!==","||!event.ctrl||event.shift||event.meta||event.super||event.hyper)
7332
7230
  return
7333
- const command=legacyCommand(`${PLUGIN_ID}.settings`)
7334
- if(!command)
7231
+ const command=context.keymap.commands().find((item)=>item.id===`${PLUGIN_ID}.settings`)
7232
+ if(!command||!enabled(command.enabled))
7335
7233
  return
7336
7234
  event.preventDefault()
7337
7235
  event.stopPropagation()
7338
- runV2(command,"",event)
7236
+ context.keymap.dispatch(command.id)
7339
7237
  }
7340
7238
  context.renderer.keyInput.on("keypress",onKeypress)
7341
- function v2Commands(id,layer){const available=()=>layerActive(layer)
7342
- const named=(layer.commands??[]).map((command)=>({id:command.name,bind:command.name==="session.new"?"<leader>n":undefined,title:command.title,description:command.desc,group:command.category,palette:command.namespace==="palette"?true:undefined,suggested:command.suggested,enabled:()=>available()&&enabled(command.enabled),run:(input,event)=>runV2(command,input,event)
7239
+ const keymap={registerLayer(layer){const id=++sequence
7240
+ const owner=getOwner()
7241
+ const [active,setActive]=createSignal37(true)
7242
+ const install=()=>{context.keymap.layer(()=>({mode:typeof layer.mode==="string"?layer.mode:"base",priority:layer.priority,enabled:()=>active()&&enabled(layer.enabled),target:layer.target?()=>layer.target:undefined,commands:v2LayerCommands(id,layer,()=>true,run,context.keymap.dispatch)
7343
7243
  }))
7344
- const bindings=(layer.bindings??[]).flatMap((binding,index)=>typeof binding.key==="string"?[{id:`${PLUGIN_ID}.v2-binding.${id}.${index}`,bind:binding.key,enabled:available,run:()=>{context.keymap.dispatch(String(binding.cmd))
7345
- }}]:[])
7346
- return [...named,...bindings]
7347
7244
  }
7348
- function Bridge(){context.keymap.layer(()=>{revision()
7349
- const current=[...layers].sort(([leftID,left],[rightID,right])=>(right.priority??0)-(left.priority??0)||rightID-leftID)
7350
- const commands=current.flatMap(([id,layer])=>v2Commands(id,layer))
7351
- const bindings=commands.flatMap((command)=>command.id?[command.id]:[])
7352
- return{mode:"global",priority:2000,commands,bindings
7353
- }})
7354
- return _$createElement("box")
7245
+ let release
7246
+ if(owner)
7247
+ release=createRoot((cleanup)=>{install()
7248
+ return cleanup
7249
+ },owner)
7250
+ else
7251
+ install()
7252
+ const dispose=()=>{setActive(false)
7253
+ release?.()
7355
7254
  }
7356
- const keymap={registerLayer(layer){const id=++sequence
7357
- layers.set(id,layer)
7358
- setRevision((value)=>value + 1)
7359
- return()=>{if(!layers.delete(id))
7360
- return
7361
- setRevision((value)=>value + 1)
7362
- }},dispatchCommand(name,options){const command=context.keymap.commands().find((candidate)=>candidate.id===(name===PERMISSIONS_ACTION?SETTINGS_COMMAND:name))
7363
- if(command){if(!enabled(command.enabled))
7255
+ cleanups.add(dispose)
7256
+ return()=>{cleanups.delete(dispose)
7257
+ dispose()
7258
+ }},dispatchCommand(name,options){const target=options?.focused??options?.target
7259
+ if(target?.parent&&!target.isDestroyed)
7260
+ target.focus()
7261
+ const command=context.keymap.commands().find((item)=>item.id===(name===PERMISSIONS_ACTION?SETTINGS_COMMAND:name))
7262
+ if(!command)
7263
+ return{ok:false,reason:"not-found"
7264
+ }
7265
+ if(!enabled(command.enabled))
7364
7266
  return{ok:false,reason:"disabled",command
7365
7267
  }
7366
7268
  context.keymap.dispatch(command.id,typeof options?.payload==="string"?options.payload:undefined)
7367
7269
  return{ok:true,command
7368
- }}
7369
- const fallback=legacyCommand(name)
7370
- if(!fallback)
7371
- return{ok:false,reason:"not-found"
7372
- }
7373
- run(fallback)
7374
- return{ok:true,command:fallback
7375
7270
  }},getCommands(){const commands=context.keymap.commands()
7376
- const result=commands.flatMap((command)=>{if(!command.id)
7377
- return []
7378
- const name=command.id
7379
- return [{...command,name,run:()=>context.keymap.dispatch(name)
7380
- }]
7381
- })
7382
- const settings=commands.find((command)=>command.id===SETTINGS_COMMAND)
7271
+ const result=commands.flatMap((command)=>command.id?[{...command,name:command.id,run:()=>context.keymap.dispatch(command.id)
7272
+ }]:[])
7273
+ const settings=commands.find((item)=>item.id===SETTINGS_COMMAND)
7383
7274
  if(settings)
7384
7275
  result.push({...settings,id:PERMISSIONS_ACTION,name:PERMISSIONS_ACTION,title:"Permissions settings",run:()=>context.keymap.dispatch(SETTINGS_COMMAND)
7385
7276
  })
7386
7277
  return result
7387
7278
  },getCommandBindings(input){return new Map(input.commands.map((name)=>[name,[...context.keymap.shortcuts(name)]]))
7388
- },parseKeySequence(value){return value.trim()?value.trim().split(/\s+/u):[]
7389
7279
  }}
7390
- return{keymap,Bridge,dispose:()=>{context.renderer.keyInput.off("keypress",onKeypress)
7280
+ return{keymap,dispose(){for(const cleanup of cleanups)
7281
+ cleanup()
7282
+ cleanups.clear()
7283
+ context.renderer.keyInput.off("keypress",onKeypress)
7391
7284
  }}}
7392
- function createV2SessionAdapter(context){const statuses=new Map
7285
+
7286
+ function createV2SessionAdapter(context){const [retryDetails,setRetryDetails]=createSignal38({})
7287
+ const projections=new WeakMap
7393
7288
  function normalize(info){const directory=info.location.directory
7394
7289
  const workspaceID=context.location?.directory===directory?context.location.workspaceID:undefined
7395
7290
  return{id:info.id,slug:info.id,projectID:info.projectID,...workspaceID&&{workspaceID},directory,...info.parentID&&{parentID:info.parentID},cost:Number(info.cost),tokens:info.tokens,title:info.title??"Untitled session",...info.agent&&{agent:info.agent},...info.model&&{model:info.model},version:context.app.version,metadata:info.metadata,time:{created:info.time.created,updated:info.time.updated,...info.time.archived&&{archived:info.time.archived}}}}
7396
- function status(sessionID){const cached=statuses.get(sessionID)
7397
- if(cached)
7398
- return cached
7399
- return context.data.session.status(sessionID)==="running"?{type:"busy"}:{type:"idle"}}
7400
- return{normalize,setStatus(sessionID,value){statuses.set(sessionID,value)
7291
+ function status(sessionID){if(context.data.session.status(sessionID)!=="running")
7292
+ return{type:"idle"}
7293
+ const messages=context.data.session.message?.list?.(sessionID)??[]
7294
+ let message
7295
+ for(let index=messages.length-1;index>=0; index--){const candidate=messages[index]
7296
+ if(candidate.type==="assistant"&&!candidate.time.completed){message=candidate
7297
+ break
7298
+ }}
7299
+ if(message?.type==="assistant"&&message.retry)
7300
+ return{type:"retry",attempt:message.retry.attempt,next:message.retry.at,message:message.retry.error.message
7301
+ }
7302
+ return retryDetails()[sessionID]??{type:"busy"}}
7303
+ function project(info){let value=projections.get(info)
7304
+ if(!value){value=normalize(info)
7305
+ for(const key of ["id","slug","projectID","workspaceID","directory","parentID","cost","tokens","title","agent","model","version","metadata","time"])
7306
+ Object.defineProperty(value,key,{enumerable:true,get:()=>normalize(info)[key]})
7307
+ projections.set(info,value)
7308
+ }
7309
+ return value
7310
+ }
7311
+ return{normalize,project,status,setStatus(sessionID,value){setRetryDetails((current)=>{const next={...current}
7312
+ if(value.type==="retry")
7313
+ next[sessionID]=value
7314
+ else
7315
+ delete next[sessionID]
7316
+ return next
7317
+ })
7401
7318
  },state:{count:()=>context.data.session.list().length,get:(sessionID)=>{const value=context.data.session.get(sessionID)
7402
- return value?normalize(value):undefined
7319
+ return value?project(value):undefined
7403
7320
  },todo:()=>[],status
7404
7321
  },client:{async create(input,options={}){const directory=input.directory??context.location?.directory??context.data.location.default().directory
7405
7322
  const session=await context.client.session.create({location:{directory}},{signal:options.signal})
7406
7323
  return{data:normalize(session)}},async children(input,options={}){const response=await context.client.session.list({parentID:input.sessionID,...input.directory&&{directory:input.directory}},{signal:options.signal})
7407
7324
  return{data:response.data.map((session)=>normalize(session))}},async status(_input,options={}){const active=await context.client.session.active({signal:options.signal})
7408
- const data=Object.fromEntries(context.data.session.list().map((session)=>[session.id,statuses.get(session.id)??(active[session.id]?{type:"busy"}:{type:"idle"})]))
7325
+ const data=Object.fromEntries(context.data.session.list().map((session)=>[session.id,active[session.id]?retryDetails()[session.id]??{type:"busy"}:{type:"idle"}]))
7409
7326
  return{data}},async todo(){return{data:[]}}}}}
7410
7327
 
7411
-
7412
- function createV2Slots(context,keymap,onDispose){return{register(plugin){const slots=plugin.slots
7413
- const cleanups=[context.ui.slot({append:"app",render:()=>[_$createComponent(keymap.Bridge,{}),_$memo(()=>slots.app?.(undefined,{}))]
7328
+ function createV2Slots(context,onDispose){return{register(plugin){const slots=plugin.slots
7329
+ const cleanups=[context.ui.slot({append:"app",render:()=>_$memo(()=>slots.app?.(undefined,{}))
7414
7330
  }),context.ui.slot({replace:"sidebar.content",render:(input)=>{const sessionID=input.sessionID
7415
7331
  return slots.sidebar_content?.(undefined,{session_id:sessionID
7416
7332
  })
@@ -7421,13 +7337,20 @@ return "opencode-navigator"
7421
7337
  }}}
7422
7338
  function legacyTheme(theme){return{primary:theme.hue.interactive[200],secondary:theme.categorical[0]?.[200]??theme.hue.accent[200],accent:theme.hue.accent[200],error:theme.text.feedback.error.base,warning:theme.text.feedback.warning.base,success:theme.text.feedback.success.base,info:theme.text.feedback.info.base,text:theme.text.base,textMuted:theme.text.muted,selectedListItemText:theme.text.action.primary.focused,background:theme.background.base,backgroundPanel:theme.background.raised.base,backgroundElement:theme.background.raised.high,backgroundMenu:theme.background.raised.max,border:theme.border.base,borderActive:theme.scrollbar.base,borderSubtle:theme.hue.neutral[500],diffAdded:theme.diff.text.added,diffRemoved:theme.diff.text.removed,diffContext:theme.diff.text.context,diffHunkHeader:theme.diff.text.hunkHeader,diffHighlightAdded:theme.diff.highlight.added,diffHighlightRemoved:theme.diff.highlight.removed,diffAddedBg:theme.diff.background.added,diffRemovedBg:theme.diff.background.removed,diffContextBg:theme.diff.background.context,diffLineNumber:theme.diff.lineNumber.text,diffAddedLineNumberBg:theme.diff.lineNumber.background.added,diffRemovedLineNumberBg:theme.diff.lineNumber.background.removed,markdownText:theme.markdown.text,markdownHeading:theme.markdown.heading,markdownLink:theme.markdown.link,markdownLinkText:theme.markdown.linkText,markdownCode:theme.markdown.code,markdownBlockQuote:theme.markdown.blockQuote,markdownEmph:theme.markdown.emphasis,markdownStrong:theme.markdown.strong,markdownHorizontalRule:theme.markdown.horizontalRule,markdownListItem:theme.markdown.listItem,markdownListEnumeration:theme.markdown.listEnumeration,markdownImage:theme.markdown.image,markdownImageText:theme.markdown.imageText,markdownCodeBlock:theme.markdown.codeBlock,syntaxComment:theme.syntax.comment,syntaxKeyword:theme.syntax.keyword,syntaxFunction:theme.syntax.function,syntaxVariable:theme.syntax.variable,syntaxString:theme.syntax.string,syntaxNumber:theme.syntax.number,syntaxType:theme.syntax.type,syntaxOperator:theme.syntax.operator,syntaxPunctuation:theme.syntax.punctuation,thinkingOpacity:0.6
7423
7339
  }}
7340
+ function bindToolbarActionState(context,api){setQuickActionStateSource(api,(id)=>{const route=context.ui.router.current()
7341
+ if(id!=="session.compact"||route.type!=="session")
7342
+ return
7343
+ const revert=context.data.session.get(route.sessionID)?.revert?.messageID
7344
+ return context.data.session.message.list(route.sessionID).some((message)=>(!revert||message.id<revert)&&message.type==="compaction"&&message.status==="running")?"compacting":"idle"
7345
+ })
7346
+ }
7424
7347
 
7425
7348
 
7426
7349
  function createV2UI(context){let dialogOpen=false
7427
7350
  function DialogPrompt(props){let active=true
7428
- onCleanup26(()=>{active=false
7351
+ onCleanup29(()=>{active=false
7429
7352
  })
7430
- onMount7(async ()=>{const value=await context.ui.dialog.prompt({title:props.title,placeholder:props.placeholder,value:props.value
7353
+ onMount6(async ()=>{const value=await context.ui.dialog.prompt({title:props.title,placeholder:props.placeholder,value:props.value
7431
7354
  })
7432
7355
  if(!active)
7433
7356
  return
@@ -7439,9 +7362,9 @@ props.onConfirm?.(value)
7439
7362
  return _$createElement("box")
7440
7363
  }
7441
7364
  function DialogConfirm(props){let active=true
7442
- onCleanup26(()=>{active=false
7365
+ onCleanup29(()=>{active=false
7443
7366
  })
7444
- onMount7(async ()=>{const confirmed=await context.ui.dialog.confirm({title:props.title,message:props.message
7367
+ onMount6(async ()=>{const confirmed=await context.ui.dialog.confirm({title:props.title,message:props.message
7445
7368
  })
7446
7369
  if(!active)
7447
7370
  return
@@ -7501,38 +7424,164 @@ context.ui.router.navigate({type:"plugin",name,data:params})
7501
7424
  },client:{...remote.client,session:sessions.client
7502
7425
  },event:createV2EventAdapter(context,sessions),theme:{get current(){return legacyTheme(context.theme)
7503
7426
  },ready:true,mode:()=>context.themeMode
7504
- },attention:context.attention,lifecycle:{signal:controller.signal,onDispose},slots:createV2Slots(context,keymap,(dispose)=>{onDispose(dispose)
7427
+ },attention:context.attention,lifecycle:{signal:controller.signal,onDispose},slots:createV2Slots(context,(dispose)=>{onDispose(dispose)
7505
7428
  })
7506
7429
  }
7507
- setHostCapabilities(api,{todo:true,lsp:false,titleVisibility:false,permissionMode:false
7430
+ setHostCapabilities(api,{todo:true,lsp:false,titleVisibility:false,permissionMode:false,commandsReachableOnly:true
7508
7431
  })
7432
+ bindToolbarActionState(context,api)
7509
7433
  return{api,async dispose(){controller.abort()
7510
7434
  for(let index=disposers.length-1;index>=0; index--)
7511
7435
  await disposers[index]()
7512
7436
  disposers.length=0
7513
7437
  }}}
7438
+ var statuses=new Set(["pending","in_progress","completed","cancelled"])
7439
+ function parseTodos(value){if(!Array.isArray(value))
7440
+ return []
7441
+ return value.flatMap((item)=>{if(!item||typeof item!=="object"||!("content" in item)||typeof item.content!=="string"||!item.content)
7442
+ return []
7443
+ const status="status" in item&&typeof item.status==="string"&&statuses.has(item.status)?item.status:"pending"
7444
+ return [{content:item.content,status}]
7445
+ })
7446
+ }
7447
+ function nativeTodos(messages,boundary){const boundaryIndex=boundary?messages.findIndex((message)=>message.id===boundary):-1
7448
+ const end=boundaryIndex===-1?messages.length:boundaryIndex
7449
+ for(let index=end-1;index>=0; index--){const message=messages[index]
7450
+ if(message.type!=="assistant")
7451
+ continue
7452
+ for(let part=message.content.length-1;part>=0; part--){const item=message.content[part]
7453
+ if(item.type==="tool"&&item.name==="todowrite"&&item.state.status==="completed")
7454
+ return parseTodos(item.state.input.todos)
7455
+ }}
7456
+ return []
7457
+ }
7458
+ function createNativeTodoController(context,api){const requests=createRequestState(api.lifecycle.signal)
7459
+ const pending=new Map
7460
+ let activeTarget
7461
+ function target(sessionID){const session=api.state.session.get(sessionID)
7462
+ const directory=session?.directory??api.state.path.directory
7463
+ const workspace=session?.workspaceID
7464
+ return{key:JSON.stringify([sessionID,directory,workspace??null]),sessionID,routing:{directory,...workspace&&{workspace}}}}
7465
+ function list(sessionID){return nativeTodos(context.data.session.message.list(sessionID),context.data.session.get(sessionID)?.revert?.messageID)
7466
+ }
7467
+ function refresh(sessionID,force=false){if(api.lifecycle.signal.aborted)
7468
+ return Promise.resolve([])
7469
+ const current=target(sessionID)
7470
+ const existing=pending.get(current.key)
7471
+ if(existing&&!force)
7472
+ return existing
7473
+ const requestState=requests.start(current.key,"refresh native todos",context.data.session.message.list(sessionID).length>0,force)
7474
+ if(!requestState)
7475
+ return existing
7476
+ const request=Promise.try(()=>Promise.all([context.data.session.sync(sessionID),context.data.session.message.sync(sessionID)])).then(()=>{if(!requestState.isCurrent())
7477
+ return []
7478
+ requestState.succeed()
7479
+ return list(sessionID)
7480
+ }).catch((error)=>{requestState.fail(error)
7481
+ throw error
7482
+ }).finally(()=>{requestState.finish()
7483
+ if(pending.get(current.key)===request)
7484
+ pending.delete(current.key)
7485
+ })
7486
+ pending.set(current.key,request)
7487
+ return request
7488
+ }
7489
+ return{source:"native",target,list,refresh,state:(sessionID)=>requests.state(target(sessionID).key),retry:(sessionID)=>refresh(sessionID,true),activate(sessionID){const key=target(sessionID).key
7490
+ if(activeTarget!==key){requests.abortAll()
7491
+ pending.clear()
7492
+ activeTarget=key
7493
+ }
7494
+ return()=>{if(activeTarget!==key)
7495
+ return
7496
+ activeTarget=undefined
7497
+ requests.abortAll()
7498
+ pending.clear()
7499
+ }}}}
7500
+ function collectionLocation(target){return{directory:target.routing.directory??"",...target.routing.workspace&&{workspaceID:target.routing.workspace}}}
7501
+ async function syncCollection(collection,target,force,signal){signal.throwIfAborted()
7502
+ const ref=collectionLocation(target)
7503
+ if(force)
7504
+ collection.invalidate(ref)
7505
+ await collection.sync(ref)
7506
+ signal.throwIfAborted()
7507
+ }
7508
+ function createV2McpSource(context){const collection=context.data.location.mcp.server
7509
+ const projections=new WeakMap
7510
+ const list=(target)=>(collection.list(collectionLocation(target))??[]).map((server)=>{let item=projections.get(server)
7511
+ if(!item){item={get name(){return server.name
7512
+ },get title(){return server.title
7513
+ },get status(){return server.status.status
7514
+ },get error(){return "error" in server.status?server.status.error:undefined
7515
+ }}
7516
+ projections.set(server,item)
7517
+ }
7518
+ return item
7519
+ })
7520
+ return{list,async refresh(target,force,signal){await syncCollection(collection,target,force,signal)
7521
+ return list(target)
7522
+ }}}
7523
+ function createV2SkillSource(context){const projections=new WeakMap
7524
+ const collection=context.data.location.skill
7525
+ const list=(target)=>(collection.list(collectionLocation(target))??[]).map((skill)=>{let item=projections.get(skill)
7526
+ if(!item){item={get id(){return skill.id
7527
+ },get name(){return skill.name
7528
+ },get description(){return skill.description
7529
+ },get location(){return skill.path
7530
+ },get content(){return skill.content
7531
+ }}
7532
+ projections.set(skill,item)
7533
+ }
7534
+ return item
7535
+ })
7536
+ return{list,async refresh(target,force,signal){await syncCollection(collection,target,force,signal)
7537
+ return list(target)
7538
+ },async use(target,skill,signal){signal.throwIfAborted()
7539
+ const route=context.ui.router.current()
7540
+ const session=route.type==="session"&&context.data.session.get(route.sessionID)
7541
+ const actual=list(target).find((item)=>item.id===skill.id&&item.location===skill.location)
7542
+ if(route.type!=="session"||!session||session.location.directory!==target.routing.directory||!actual?.id)
7543
+ throw new Error("Skill target changed; select the source again")
7544
+ await context.client.session.skill({sessionID:route.sessionID,id:actual.id},{signal})
7545
+ return !signal.aborted
7546
+ }}}
7547
+ function createV2SubagentSource(context,api){return{list:(parentID)=>context.data.session.list().filter((item)=>item.parentID===parentID).flatMap((item)=>{const value=api.state.session.get(item.id)
7548
+ return value?[value]:[]
7549
+ }),status:(id)=>api.state.session.status(id)??{type:"idle"},async refresh(parentID,signal){signal.throwIfAborted()
7550
+ let cursor
7551
+ do{const page=await context.client.session.list(cursor?{cursor,limit:100}:{parentID,limit:100},{signal
7552
+ })
7553
+ await Promise.all(page.data.filter((item)=>!context.data.session.get(item.id)).map((item)=>context.data.session.sync(item.id)))
7554
+ cursor=page.cursor.next??undefined
7555
+ signal.throwIfAborted()
7556
+ } while(cursor)
7557
+ }}}
7558
+ function createOpenCodeV2Sources(context,api){return{skills:createV2SkillSource(context),mcp:createV2McpSource(context),subagents:createV2SubagentSource(context,api)
7559
+ }}
7514
7560
  function loadNavigatorUpdates(){const path=import.meta.url.includes("/dist/tui.js")?"./navigator-updates.js":"../navigator-updates"
7515
7561
  return import(path)
7516
7562
  }
7517
- async function setupNavigator(api,options,readProject,managedTodo,hostContext){const config=pluginConfig(undefined)
7563
+ async function setupNavigator(api,options,readProject,todoController,hostContext){const config=pluginConfig(undefined)
7518
7564
  const configured=await loadConfiguredDefaults(api,options,readProject)
7519
- const todo=managedTodo??createTodoController(api)
7520
- const subagents=createSubagentController(api)
7521
- const skills=createSkillController(api)
7565
+ const todo=todoController??createTodoController(api)
7566
+ const nativeSources=hostContext&&createOpenCodeV2Sources(hostContext,api)
7567
+ const subagents=createSubagentController(api,{source:nativeSources?.subagents
7568
+ })
7569
+ const skills=createSkillController(api,nativeSources?.skills)
7522
7570
  const preferences=createPreferencesController(api,config,createPreferencesStore(api.state.path.state),configured)
7523
7571
  const limitsPath=import.meta.url.includes("/dist/tui.js")?"./provider-limits.js":"../provider-limits"
7524
7572
  const limitsModule=await import(limitsPath)
7525
7573
  const LimitsSection=limitsModule.ProviderLimitsSection
7526
7574
  const{controller:limits,codex,accountSource,selectModel,modelSelection
7527
- }=limitsModule.createProviderQuotaIntegration(api,preferences,"0.21.8",hostContext)
7528
- const mcp=createMcpController(api,preferences.persistMcp,preferences)
7529
- const interaction=createSidebarInteraction(api,()=>openKeyboardHelp(api,preferences.lspIconStyle,preferences.cornerFont))
7575
+ }=limitsModule.createProviderQuotaIntegration(api,preferences,"0.23.0",hostContext)
7576
+ const mcp=createMcpController(api,preferences.persistMcp,preferences,nativeSources?.mcp)
7577
+ const interaction=createSidebarInteraction(api,()=>openKeyboardHelp(api,preferences.lspIconStyle,preferences.cornerFont,sidebarShortcutActions(api)))
7530
7578
  const startup=createStartupSessionController(api,preferences)
7531
7579
  api.lifecycle.onDispose(()=>preferences.flush())
7532
7580
  api.lifecycle.onDispose(()=>limits.dispose())
7533
7581
  api.lifecycle.onDispose(()=>accountSource?.dispose())
7534
7582
  api.lifecycle.onDispose(()=>interaction.dispose())
7535
- const unsubscribeMcp=api.event.on("mcp.tools.changed",()=>{mcp.refresh().catch(()=>{})
7583
+ const unsubscribeMcp=api.event.on("mcp.tools.changed",()=>{if(!nativeSources)
7584
+ mcp.refresh().catch(()=>{})
7536
7585
  })
7537
7586
  const unsubscribeConnected=api.event.on("server.connected",()=>{if(!api.state.ready||!api.kv.ready)
7538
7587
  return
@@ -7552,7 +7601,7 @@ api.slots.register({order:100,slots:{app(){return _$createComponent(IconProvider
7552
7601
  },interaction,skills,subagents,mcp
7553
7602
  }),_$createComponent(FirstRunWizardPersistence,{api,preferences
7554
7603
  }),_$createComponent(StartupSessionBinding,{api,controller:startup
7555
- }),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.21.8"
7604
+ }),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.23.0"
7556
7605
  }),_$createComponent(McpPersistence,{api,controller:mcp
7557
7606
  })]
7558
7607
  }})
@@ -7585,19 +7634,19 @@ return result.data?.type==="text"?result.data.content:undefined
7585
7634
  })
7586
7635
  const{createVersionStatus,createVersionUpdateActions,createOpenCodeV1VersionUpdater
7587
7636
  }=await loadNavigatorUpdates()
7588
- const versionStatus=createVersionStatus(api,"0.21.8")
7589
- const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.21.8"))
7637
+ const versionStatus=createVersionStatus(api,"0.23.0")
7638
+ const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.23.0"))
7590
7639
  api.slots.register({order:90,slots:{sidebar_footer(_context,props){return _$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
7591
7640
  },get multilineCorners(){return preferences.cornerFont
7592
7641
  },get children(){return _$createComponent(VersionFooter,{api,get sessionID(){return props.session_id
7593
- },navigatorVersion:"0.21.8",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
7642
+ },navigatorVersion:"0.23.0",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
7594
7643
  },get onNavigatorUpdate(){return versionUpdates.navigator
7595
7644
  }})
7596
7645
  }})
7597
7646
  }}})
7598
7647
  }
7599
7648
  var setupOpenCodeV2=async (context)=>{const adapter=createOpenCodeV2Api(context)
7600
- const todo=createNavigatorTodoController(context,adapter.api)
7649
+ const todo=createNativeTodoController(context,adapter.api)
7601
7650
  const{mcp,skills,preferences
7602
7651
  }=await setupNavigator(adapter.api,context.options,async ()=>{if(!context.client.file?.read)
7603
7652
  return
@@ -7606,15 +7655,15 @@ return new TextDecoder().decode(await context.client.file.read({location:context
7606
7655
  },todo,context)
7607
7656
  const{createVersionStatus,createVersionUpdateActions,createOpenCodeV2VersionUpdater
7608
7657
  }=await loadNavigatorUpdates()
7609
- const versionStatus=createVersionStatus(adapter.api,"0.21.8")
7610
- const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.21.8"))
7658
+ const versionStatus=createVersionStatus(adapter.api,"0.23.0")
7659
+ const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.23.0"))
7611
7660
  const disposeFooter=context.ui.slot({append:"sidebar.footer",render:()=>_$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
7612
7661
  },get multilineCorners(){return preferences.cornerFont
7613
7662
  },get children(){var _el$=_$createElement("box")
7614
7663
  _$setProp(_el$,"flexDirection","row")
7615
7664
  _$setProp(_el$,"justifyContent","space-between")
7616
7665
  _$insert(_el$,_$createComponent(VersionSummary,{get api(){return adapter.api
7617
- },navigatorVersion:"0.21.8",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
7666
+ },navigatorVersion:"0.23.0",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
7618
7667
  },get onNavigatorUpdate(){return versionUpdates.navigator
7619
7668
  }}),null)
7620
7669
  _$insert(_el$,_$createComponent(SettingsFooterButton,{get api(){return adapter.api
@@ -7629,5 +7678,5 @@ await adapter.dispose()
7629
7678
  var plugin={id:PLUGIN_ID,tui:setupOpenCodeV1,setup:setupOpenCodeV2
7630
7679
  }
7631
7680
  var plugin_default=plugin
7632
- export{DEFAULT_SECTION_EXPANSION,DialogAction,DialogHeader,DialogSurface,FOCUS_COMMAND,FirstRunWizard,GuardedConfirmation,KeyboardHelpDialog,LspBadge,McpSection,SelectionMenu as PresetMenu,QUICK_ACTIONS,Section,SectionFilter,SelectionBox,SelectionMenu,SettingsDialog,SidebarFocusBinding,SidebarToggleBinding,SkillsSection,createDialogStack,createMcpController,createPreferencesController,createSidebarInteraction,createSkillController,createSubagentController,createTodoController,plugin_default as default,isEffectivelyVisible,lspIcon,matchesFilter,openFirstRunWizard,openKeyboardHelp,openSettings,showFirstRunWizard,subtleLineColor,useDialogScroll,useDialogState,useDialogs,useIcons
7681
+ export{DEFAULT_SECTION_EXPANSION,DialogAction,DialogHeader,DialogSurface,FOCUS_COMMAND,FirstRunWizard,GuardedConfirmation,IconControl,IconPicker,KeyboardHelpDialog,LspBadge,McpSection,SelectionMenu as PresetMenu,QUICK_ACTIONS,QUICK_ACTION_IDS,Section,SectionFilter,SelectionBox,SelectionMenu,SettingsDialog,SidebarFocusBinding,SidebarToggleBinding,SkillsSection,Tab,TodoSection,createDialogStack,createMcpController,createNativeTodoController,createPreferencesController,createQuickActionRevision,createSidebarInteraction,createSkillController,createSubagentController,createTodoController,currentPermissionMode,plugin_default as default,hostCapabilities,hostCapabilityUnavailable,isEffectivelyVisible,lspIcon,matchesFilter,openFirstRunWizard,openKeyboardHelp,openSettings,orderQuickActionIds,parseQuickActionOrder,parseQuickActionVisibility,quickActionDisabledReason,quickActionLabel,quickActionRequiresSession,quickActionState,quickActionStates,setHostCapabilities,setQuickActionStateSource,showFirstRunWizard,subtleLineColor,supportsPermissionMode,supportsSidebarSection,supportsTitleVisibility,terminalIcon,terminalIconIDs,terminalIconLabel,useDialogScroll,useDialogState,useDialogs,useIcons
7633
7682
  }