opencode-navigator 0.21.3 → 0.21.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +38 -6
- package/dist/{chunk-cmmnfes2.js → chunk-d1bws32s.js} +2 -1
- package/dist/layout-preset-actions.js +1 -1
- package/dist/navigator-updates.js +237 -0
- package/dist/project-profile.js +5 -1
- package/dist/provider-limits.js +7 -7
- package/dist/quick-actions-settings.js +1 -1
- package/dist/tui.js +101 -169
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## [0.21.5] - 2026-10-07
|
|
6
|
+
|
|
7
|
+
- Make automatic Limits refresh configurable in scoped Behavior settings and portable configuration, with a five-minute default and one-minute minimum. Keep manual Refresh and supported model/account switches immediate.
|
|
8
|
+
- Avoid extra quota polling from unrelated preference changes and unchanged provider-account metadata observations.
|
|
9
|
+
|
|
10
|
+
## [0.21.4] - 2026-10-07
|
|
11
|
+
|
|
12
|
+
- Add `c` to Navigator shortcuts for a manual update check and `u` to check then confirm a Navigator update. Report available, current, or unavailable results, preserve the installation method and scope, and require a restart after updating.
|
|
13
|
+
- Ignore cancelled, outdated, and repeated update confirmations, and recover from stalled update checks without blocking later checks.
|
|
14
|
+
|
|
5
15
|
## [0.21.3] - 2026-10-06
|
|
6
16
|
|
|
7
17
|
- Replace block quota meters with full-width adaptive thin-line scales and keep quota rows inside the sidebar's padding after resize. Show only reset time below each meter, removing technical account and window-duration suffixes.
|
|
@@ -90,6 +100,8 @@
|
|
|
90
100
|
|
|
91
101
|
Earlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).
|
|
92
102
|
|
|
103
|
+
[0.21.5]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.4...v0.21.5
|
|
104
|
+
[0.21.4]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.3...v0.21.4
|
|
93
105
|
[0.21.3]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.2...v0.21.3
|
|
94
106
|
[0.21.2]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.1...v0.21.2
|
|
95
107
|
[0.21.1]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.0...v0.21.1
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ See the [changelog](CHANGELOG.md) for release-by-release changes.
|
|
|
33
33
|
- Save visibility, expansion, and order globally or for the current worktree
|
|
34
34
|
- Copy the selected scope's layout and MCP states as versioned JSON, then validate and preview imports
|
|
35
35
|
- Focus the sidebar with `Ctrl+Shift+F`, then navigate with arrows or `j`/`k`
|
|
36
|
-
- Open sidebar shortcut mode with `Ctrl+Shift+B`; press `h` to toggle the panel
|
|
36
|
+
- Open sidebar shortcut mode with `Ctrl+Shift+B`; press `h` to toggle the panel, `c` to check Navigator updates, or `u` to check and confirm an update
|
|
37
37
|
- Optionally open new sessions directly in an empty chat with the sidebar, skipping Home on startup and from New session
|
|
38
38
|
- Keep OpenCode's compact footer while showing host and Navigator versions with independent update indicators; click a version label or its update icon to confirm an in-place update through the current installation method and scope
|
|
39
39
|
|
|
@@ -145,7 +145,7 @@ the uninstalled-font result remains visible rather than being documented only in
|
|
|
145
145
|
|
|
146
146
|

|
|
147
147
|
|
|
148
|
-
The [complete
|
|
148
|
+
The [complete 47-state screenshot gallery](screenshots/README.md) shows every
|
|
149
149
|
Todo and Subagent filter, sidebar section, Search and Settings tab, preset menu
|
|
150
150
|
and preview, confirmation, keyboard-help, setup, and icon-fallback state.
|
|
151
151
|
|
|
@@ -370,6 +370,11 @@ across models. The protocol can return `normalModelSlug: null` for this ordinary
|
|
|
370
370
|
bucket; that field is display metadata for quota aliases, not a prerequisite for
|
|
371
371
|
account usage. Separate model-specific buckets require explicit model association.
|
|
372
372
|
Switching provider, model, session, or account invalidates stale reads and credit actions.
|
|
373
|
+
In OpenCode 2.x, Limits follows the prompt's selected model immediately, before a
|
|
374
|
+
message is sent, through the public reactive `ui.model.current()` API. OpenCode
|
|
375
|
+
1.x through 1.18.35 exposes only the saved session model: a newly selected prompt
|
|
376
|
+
model becomes visible to Navigator when the host saves it, normally on submission.
|
|
377
|
+
An immediate pre-submission switch in 1.x needs a new public host accessor or event.
|
|
373
378
|
CodexBar is useful for discovering providers, but its cookie, credential-file,
|
|
374
379
|
and undocumented endpoint integrations are not Navigator data sources.
|
|
375
380
|
|
|
@@ -436,11 +441,18 @@ durations describe provider quota windows, not time remaining until reset. Balan
|
|
|
436
441
|
currency or point unit; a missing total does not become a full progress scale.
|
|
437
442
|
|
|
438
443
|
The header has no section counter. Its compact **Refresh** control requests a
|
|
439
|
-
read immediately
|
|
440
|
-
hidden.
|
|
444
|
+
read immediately. Automatic refresh defaults to **five minutes**, including while
|
|
445
|
+
hidden. Change **Settings → Behavior → Limits refresh interval** in Global or
|
|
446
|
+
Current worktree scope; enter a whole number of minutes, with a minimum of one.
|
|
447
|
+
Changing the effective interval reschedules the timer without an extra quota read.
|
|
448
|
+
Model/account switches and manual Refresh remain immediate; unrelated settings
|
|
449
|
+
updates and provider-response observations do not trigger extra quota polling.
|
|
450
|
+
Failed reads retain cached windows with stale guidance and the same header
|
|
441
451
|
control for retrying. Unsupported mappings, authentication, and setup states have
|
|
442
452
|
separate muted guidance.
|
|
443
453
|
|
|
454
|
+

|
|
455
|
+
|
|
444
456
|
### Review and manually use a banked reset
|
|
445
457
|
|
|
446
458
|
The header's **Banked Resets** button appears when credits or an unresolved attempt
|
|
@@ -492,6 +504,7 @@ Navigator plugin tuple:
|
|
|
492
504
|
"focusKey": "ctrl+shift+f",
|
|
493
505
|
"searchKey": "ctrl+shift+k",
|
|
494
506
|
"persistMcp": true,
|
|
507
|
+
"limitsRefreshMinutes": 5,
|
|
495
508
|
"startInChat": false,
|
|
496
509
|
"showSessionTitle": true,
|
|
497
510
|
"showSessionDate": true,
|
|
@@ -530,10 +543,10 @@ For example, the schema-valid `opencode.json` entry is:
|
|
|
530
543
|
}
|
|
531
544
|
```
|
|
532
545
|
|
|
533
|
-
Behavior keys control the optional start-in-chat flow, shortcuts, MCP persistence, `nerd`/`text` icon style, row
|
|
546
|
+
Behavior keys control the optional start-in-chat flow, shortcuts, MCP persistence, Limits refresh cadence, `nerd`/`text` icon style, row
|
|
534
547
|
density, item limits, and Navigator's safe Quick Action allowlist. Unknown values,
|
|
535
548
|
sections, actions, and MCP states are discarded. The previous snake_case tuple
|
|
536
|
-
options (`toggle_key`, `focus_key`, `search_key`, `persist_mcp`, `start_in_chat`, `show_session_title`,
|
|
549
|
+
options (`toggle_key`, `focus_key`, `search_key`, `persist_mcp`, `limits_refresh_minutes`, `start_in_chat`, `show_session_title`,
|
|
537
550
|
`show_session_date`, `corner_font`, `icon_style`,
|
|
538
551
|
`lsp_icon_style`, `row_density`, `section_item_limits`, `quick_action_order`,
|
|
539
552
|
`quick_action_visibility`, `sections`, and `section_order`) remain compatible;
|
|
@@ -636,6 +649,25 @@ The command palette also exposes `Focus sidebar` and direct commands for Todo,
|
|
|
636
649
|
Subagents, Skills, Quick Actions, LSP, and MCP. Both sidebar shortcuts can be
|
|
637
650
|
changed at runtime in settings.
|
|
638
651
|
|
|
652
|
+
Press `Ctrl+Shift+B` to enter Navigator shortcuts, then choose an action:
|
|
653
|
+
|
|
654
|
+
| Key | Action |
|
|
655
|
+
| --- | --- |
|
|
656
|
+
| `h` | Toggle sidebar visibility |
|
|
657
|
+
| `t` / `a` / `s` / `q` / `l` / `m` | Focus Todo / Subagents / Skills / Quick Actions / LSP / MCP |
|
|
658
|
+
| `c` | Check for a Navigator update and report whether one is available |
|
|
659
|
+
| `u` | Check for a Navigator update, then open its confirmation if available |
|
|
660
|
+
| `Escape` | Cancel shortcut mode |
|
|
661
|
+
|
|
662
|
+
The mode ends after an action or five seconds of inactivity. Its toast lists only
|
|
663
|
+
actions supported by the current host; LSP is omitted on OpenCode 2.x. Change the
|
|
664
|
+
entry shortcut under **Settings → Behavior**. The command palette also offers
|
|
665
|
+
**Check Navigator updates** and **Update Navigator**.
|
|
666
|
+
|
|
667
|
+
Manual checks report when Navigator is current or the update source is unavailable.
|
|
668
|
+
Updates require confirmation, preserve the existing installation method and scope,
|
|
669
|
+
and show a restart reminder after completion. Background check failures stay quiet.
|
|
670
|
+
|
|
639
671
|
### Search Everything
|
|
640
672
|
|
|
641
673
|
Press `Ctrl+Shift+K` or run **Search Everything** from the command palette. Use
|
|
@@ -3,5 +3,6 @@ var TOGGLE_COMMAND=`${PLUGIN_ID}.toggle`
|
|
|
3
3
|
var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
|
|
4
4
|
var SEARCH_COMMAND=`${PLUGIN_ID}.search`;
|
|
5
5
|
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"]
|
|
6
|
-
var SECTION_DEFINITIONS=[{name:"limits",label:"Limits"},{name:"todo",label:"Todo"},{name:"subagents",label:"Subagents"},{name:"skills",label:"Skills"},{name:"quick_actions",label:"Quick actions"},{name:"lsp",label:"LSP"},{name:"mcp",label:"MCP"}]
|
|
6
|
+
var SECTION_DEFINITIONS=[{name:"limits",label:"Limits"},{name:"todo",label:"Todo"},{name:"subagents",label:"Subagents"},{name:"skills",label:"Skills"},{name:"quick_actions",label:"Quick actions"},{name:"lsp",label:"LSP"},{name:"mcp",label:"MCP"}];
|
|
7
|
+
var MAX_LIMITS_REFRESH_MINUTES=Math.floor(2147483647 / 60000)
|
|
7
8
|
export{QUICK_ACTION_IDS,SECTION_DEFINITIONS,PLUGIN_ID}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {SECTION_DEFINITIONS,PLUGIN_ID
|
|
2
|
-
} from "./chunk-
|
|
2
|
+
} from "./chunk-d1bws32s.js";
|
|
3
3
|
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
4
4
|
import {setProp as _$setProp5} from "@opentui/solid"
|
|
5
5
|
import {effect as _$effect5} from "@opentui/solid"
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import {PLUGIN_ID
|
|
2
|
+
} from "./chunk-d1bws32s.js";
|
|
3
|
+
import {createSignal} from "solid-js"
|
|
4
|
+
function versionParts(value){const match=/^v?(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/.exec(value)
|
|
5
|
+
return match?{numbers:match.slice(1,4).map(Number),prerelease:match[4]||undefined}:undefined
|
|
6
|
+
}
|
|
7
|
+
function isNewerVersion(latest,current){const next=versionParts(latest)
|
|
8
|
+
const installed=versionParts(current)
|
|
9
|
+
if(!next||!installed)
|
|
10
|
+
return false
|
|
11
|
+
for(let index=0;index<3; index++){if(next.numbers[index]!==installed.numbers[index])
|
|
12
|
+
return next.numbers[index]>installed.numbers[index]
|
|
13
|
+
}
|
|
14
|
+
return installed.prerelease!==undefined&&next.prerelease===undefined
|
|
15
|
+
}
|
|
16
|
+
var NAVIGATOR_PACKAGE_URL="https://registry.npmjs.org/opencode-navigator/latest"
|
|
17
|
+
var REQUEST_TIMEOUT_MS=5000
|
|
18
|
+
async function readNavigatorVersion(request,signal){const response=await request(NAVIGATOR_PACKAGE_URL,{headers:{accept:"application/json"},signal})
|
|
19
|
+
if(!response.ok)
|
|
20
|
+
throw new Error("Update source unavailable")
|
|
21
|
+
const metadata=await response.json()
|
|
22
|
+
if(typeof metadata.version!=="string"||!/^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(metadata.version))
|
|
23
|
+
throw new Error("Invalid update version")
|
|
24
|
+
return metadata.version
|
|
25
|
+
}
|
|
26
|
+
function createVersionStatus(api,navigatorVersion,request=fetch,timeoutMs=REQUEST_TIMEOUT_MS){const [openCodeUpdate,setOpenCodeUpdate]=createSignal()
|
|
27
|
+
const [navigatorUpdate,setNavigatorUpdate]=createSignal()
|
|
28
|
+
let controller
|
|
29
|
+
let pending
|
|
30
|
+
let disposed=false
|
|
31
|
+
const unsubscribe=api.event.on("installation.update-available",(event)=>{const version=event.properties.version
|
|
32
|
+
setOpenCodeUpdate(isNewerVersion(version,api.app.version)?version:undefined)
|
|
33
|
+
})
|
|
34
|
+
api.lifecycle.onDispose(()=>{disposed=true
|
|
35
|
+
controller?.abort()
|
|
36
|
+
unsubscribe()
|
|
37
|
+
})
|
|
38
|
+
function refreshNavigator(){if(disposed)
|
|
39
|
+
return Promise.resolve("unavailable")
|
|
40
|
+
if(pending)
|
|
41
|
+
return pending
|
|
42
|
+
const active=new AbortController
|
|
43
|
+
controller=active
|
|
44
|
+
const timeout=setTimeout(()=>active.abort(),timeoutMs)
|
|
45
|
+
let abort
|
|
46
|
+
const cancelled=new Promise((_,reject)=>{abort=()=>reject(new Error("Update check interrupted"))
|
|
47
|
+
active.signal.addEventListener("abort",abort,{once:true})
|
|
48
|
+
})
|
|
49
|
+
const reading=Promise.race([readNavigatorVersion(request,active.signal),cancelled]).then((version)=>{if(disposed||active.signal.aborted)
|
|
50
|
+
return "unavailable"
|
|
51
|
+
const newer=isNewerVersion(version,navigatorVersion)
|
|
52
|
+
setNavigatorUpdate(newer?version:undefined)
|
|
53
|
+
return newer?"update":"current"
|
|
54
|
+
}).catch(()=>"unavailable").finally(()=>{clearTimeout(timeout)
|
|
55
|
+
active.signal.removeEventListener("abort",abort)
|
|
56
|
+
if(controller===active)
|
|
57
|
+
controller=undefined
|
|
58
|
+
if(pending===reading)
|
|
59
|
+
pending=undefined
|
|
60
|
+
})
|
|
61
|
+
pending=reading
|
|
62
|
+
return reading
|
|
63
|
+
}
|
|
64
|
+
refreshNavigator()
|
|
65
|
+
return{openCodeUpdate,navigatorUpdate,refreshNavigator}}
|
|
66
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
67
|
+
import {insertNode as _$insertNode3} from "@opentui/solid"
|
|
68
|
+
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
69
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
70
|
+
import {setProp as _$setProp3} from "@opentui/solid"
|
|
71
|
+
import {createElement as _$createElement3} from "@opentui/solid"
|
|
72
|
+
import {effect as _$effect2} from "@opentui/solid"
|
|
73
|
+
import {insert as _$insert2} from "@opentui/solid"
|
|
74
|
+
import {createTextNode as _$createTextNode2} from "@opentui/solid"
|
|
75
|
+
import {insertNode as _$insertNode2} from "@opentui/solid"
|
|
76
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
77
|
+
import {setProp as _$setProp2} from "@opentui/solid"
|
|
78
|
+
import {createElement as _$createElement2} from "@opentui/solid"
|
|
79
|
+
import {effect as _$effect} from "@opentui/solid"
|
|
80
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
81
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
82
|
+
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
83
|
+
import {insert as _$insert} from "@opentui/solid"
|
|
84
|
+
import {setProp as _$setProp} from "@opentui/solid"
|
|
85
|
+
import {createElement as _$createElement} from "@opentui/solid"
|
|
86
|
+
import {useIcons} from "./tui.js"
|
|
87
|
+
import {createComponent as _$createComponent3} from "@opentui/solid"
|
|
88
|
+
function createManualUpdateCheck(api,status,current,onUpdate){let checking=false
|
|
89
|
+
async function read(){try{return await status.refreshNavigator?.()??"unavailable"
|
|
90
|
+
} catch{return "unavailable"
|
|
91
|
+
}}
|
|
92
|
+
return{checking:()=>checking,async run(offerUpdate=false){if(!current()||checking)
|
|
93
|
+
return
|
|
94
|
+
checking=true
|
|
95
|
+
api.ui.toast({variant:"info",title:"Navigator update",message:"Checking for updates\u2026"})
|
|
96
|
+
try{const result=await read()
|
|
97
|
+
if(!current())
|
|
98
|
+
return
|
|
99
|
+
if(result==="update"&&offerUpdate){onUpdate()
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
api.ui.toast({variant:result==="unavailable"?"warning":"info",title:"Navigator update",message:{update:`Navigator ${status.navigatorUpdate()} is available. Use u in Navigator shortcuts to update.`,current:"Navigator is up to date.",unavailable:"Could not check Navigator updates. Try again."
|
|
103
|
+
}[result]
|
|
104
|
+
})
|
|
105
|
+
} finally{checking=false
|
|
106
|
+
}}}}
|
|
107
|
+
function createVersionUpdateActions(api,status,updater,rememberNavigatorVersion){const busy=new Set
|
|
108
|
+
const installed={}
|
|
109
|
+
let disposed=false
|
|
110
|
+
let confirmation=0
|
|
111
|
+
function target(kind){return kind==="openCode"?status.openCodeUpdate():status.navigatorUpdate()
|
|
112
|
+
}
|
|
113
|
+
function label(kind){return kind==="openCode"?"OpenCode":"Navigator"
|
|
114
|
+
}
|
|
115
|
+
function update(kind,version){if(disposed||busy.has(kind))
|
|
116
|
+
return
|
|
117
|
+
if(version!==target(kind)){api.ui.toast({variant:"warning",title:"Update changed",message:"Check for updates again before confirming."
|
|
118
|
+
})
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
api.ui.dialog.clear()
|
|
122
|
+
busy.add(kind)
|
|
123
|
+
api.ui.toast({variant:"info",title:`Updating ${label(kind)}`,message:`Installing ${version}...`
|
|
124
|
+
});
|
|
125
|
+
(async ()=>{if(kind==="navigator")
|
|
126
|
+
await rememberNavigatorVersion?.()
|
|
127
|
+
if(disposed||version!==target(kind))
|
|
128
|
+
throw new Error("Update target changed; check again")
|
|
129
|
+
await updater[kind](version)
|
|
130
|
+
})().then(()=>{installed[kind]=version
|
|
131
|
+
if(disposed)
|
|
132
|
+
return
|
|
133
|
+
api.ui.toast({variant:"success",title:`${label(kind)} updated`,message:"Restart OpenCode to use the new version.",duration:6000
|
|
134
|
+
})
|
|
135
|
+
}).catch((error)=>{if(disposed)
|
|
136
|
+
return
|
|
137
|
+
api.ui.toast({variant:"error",title:`Could not update ${label(kind)}`,message:error instanceof Error?error.message:"Update failed",duration:6000
|
|
138
|
+
})
|
|
139
|
+
}).finally(()=>busy.delete(kind))
|
|
140
|
+
}
|
|
141
|
+
function open(kind,version=target(kind)){if(disposed||!version||version!==target(kind)||busy.has(kind))
|
|
142
|
+
return
|
|
143
|
+
if(installed[kind]===version){api.ui.toast({variant:"info",title:`${label(kind)} updated`,message:"Restart OpenCode to use the installed update."
|
|
144
|
+
})
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
const id=++confirmation
|
|
148
|
+
api.ui.dialog.replace(()=>_$createComponent3(api.ui.DialogConfirm,{get title(){return `Update ${label(kind)}`
|
|
149
|
+
},message:`Update to ${version} using the current installation method? OpenCode must be restarted afterward.`,onConfirm:()=>{if(id!==confirmation)
|
|
150
|
+
return
|
|
151
|
+
confirmation++
|
|
152
|
+
update(kind,version)
|
|
153
|
+
},onCancel:()=>{if(id!==confirmation)
|
|
154
|
+
return
|
|
155
|
+
confirmation++
|
|
156
|
+
api.ui.dialog.clear()
|
|
157
|
+
}}))
|
|
158
|
+
}
|
|
159
|
+
const manual=createManualUpdateCheck(api,status,()=>!disposed&&!busy.has("navigator"),()=>open("navigator"))
|
|
160
|
+
const unregister=api.keymap.registerLayer({commands:[{name:`${PLUGIN_ID}.check-update`,title:"Check Navigator updates",category:"Navigator",namespace:"palette",enabled:()=>!manual.checking()&&!busy.has("navigator"),run:()=>void manual.run()
|
|
161
|
+
},{name:`${PLUGIN_ID}.update-opencode`,title:"Update OpenCode",category:"Navigator",namespace:"palette",enabled:()=>Boolean(target("openCode"))&&!busy.has("openCode"),run:()=>open("openCode")
|
|
162
|
+
},{name:`${PLUGIN_ID}.update-navigator`,title:"Update Navigator",category:"Navigator",namespace:"palette",enabled:()=>!manual.checking()&&!busy.has("navigator"),run:()=>void manual.run(true)
|
|
163
|
+
}]
|
|
164
|
+
})
|
|
165
|
+
api.lifecycle.onDispose(()=>{disposed=true
|
|
166
|
+
unregister()
|
|
167
|
+
})
|
|
168
|
+
return{openCode:(version)=>open("openCode",version),navigator:(version)=>open("navigator",version)
|
|
169
|
+
}}
|
|
170
|
+
import {homedir} from "os"
|
|
171
|
+
import {basename,dirname,isAbsolute,join} from "path"
|
|
172
|
+
import {fileURLToPath} from "url"
|
|
173
|
+
var run=async (command)=>{const child=Bun.spawn([...command],{stdout:"ignore",stderr:"pipe"})
|
|
174
|
+
const error=new Response(child.stderr).text()
|
|
175
|
+
const exitCode=await child.exited
|
|
176
|
+
if(exitCode===0)
|
|
177
|
+
return
|
|
178
|
+
const message=await error
|
|
179
|
+
throw new Error(message.trim()||`Command failed with exit code ${child.exitCode}`)
|
|
180
|
+
}
|
|
181
|
+
var readConfig=async (path)=>{const file=Bun.file(path)
|
|
182
|
+
return await file.exists()?Bun.JSONC.parse(await file.text()):undefined
|
|
183
|
+
}
|
|
184
|
+
function pinnedUpdate(wrapper,target,execute){if(basename(wrapper)!=="tui.js"||basename(dirname(wrapper))!=="opencode-navigator")
|
|
185
|
+
throw new Error("Unrecognized local Navigator source")
|
|
186
|
+
const installer=fileURLToPath(new URL("../scripts/update-local-snapshot.mjs",import.meta.url))
|
|
187
|
+
return execute(["node",installer,wrapper,target])
|
|
188
|
+
}
|
|
189
|
+
function configHasPlugin(value,spec){if(!value||typeof value!=="object")
|
|
190
|
+
return false
|
|
191
|
+
const plugins=value.plugin
|
|
192
|
+
return Array.isArray(plugins)&&plugins.some((item)=>{let configured=item
|
|
193
|
+
if(Array.isArray(item))
|
|
194
|
+
configured=item[0]
|
|
195
|
+
else if(item&&typeof item==="object")
|
|
196
|
+
configured=item.package
|
|
197
|
+
return configured===spec
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
async function v1Global(api,spec,read){const configRoot=process.env.OPENCODE_CONFIG_DIR??join(process.env.XDG_CONFIG_HOME??join(homedir(),".config"),"opencode")
|
|
201
|
+
const global=join(configRoot,"tui.json")
|
|
202
|
+
const configured=api.state.path.config.endsWith(".json")?api.state.path.config:join(api.state.path.config,"tui.json")
|
|
203
|
+
const local=new Set([configured,join(api.state.path.worktree,".opencode","tui.json")])
|
|
204
|
+
local.delete(global)
|
|
205
|
+
for(const path of local)
|
|
206
|
+
if(configHasPlugin(await read(path),spec))
|
|
207
|
+
return false
|
|
208
|
+
return configHasPlugin(await read(global),spec)
|
|
209
|
+
}
|
|
210
|
+
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>execute([process.execPath,"upgrade",target]),async navigator(target){if(meta.source==="file"){const wrapper=meta.spec.startsWith("file://")?fileURLToPath(meta.spec):meta.spec
|
|
211
|
+
return pinnedUpdate(wrapper,target,execute)
|
|
212
|
+
}
|
|
213
|
+
if(meta.source!=="npm")
|
|
214
|
+
throw new Error("Unrecognized local Navigator source")
|
|
215
|
+
const result=await api.plugins.install(`opencode-navigator@${target}`,{global:await v1Global(api,meta.spec,read)
|
|
216
|
+
})
|
|
217
|
+
if(!result.ok)
|
|
218
|
+
throw new Error(result.message)
|
|
219
|
+
}}}
|
|
220
|
+
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>execute([process.execPath,"upgrade",target]),async navigator(target){const response=await context.client.plugin.list(context.location?{location:context.location}:{})
|
|
221
|
+
const item=response.data.find((plugin)=>plugin.id===PLUGIN_ID)
|
|
222
|
+
if(!item)
|
|
223
|
+
throw new Error("Navigator is not in the active plugin list")
|
|
224
|
+
if(item.source.type==="local")
|
|
225
|
+
return pinnedUpdate(basename(item.source.path)==="tui.js"?item.source.path:join(item.source.path,"tui.js"),target,execute)
|
|
226
|
+
if(item.source.type!=="package")
|
|
227
|
+
throw new Error("Unrecognized local Navigator source")
|
|
228
|
+
if(isAbsolute(item.source.target))
|
|
229
|
+
return pinnedUpdate(join(item.source.target,"tui.js"),target,execute)
|
|
230
|
+
if(item.source.target.startsWith("file://"))
|
|
231
|
+
return pinnedUpdate(join(fileURLToPath(item.source.target),"tui.js"),target,execute)
|
|
232
|
+
if(item.source.target.startsWith("."))
|
|
233
|
+
throw new Error("Unrecognized local Navigator source")
|
|
234
|
+
await context.client.plugin.update({location:response.location,targets:[item.source.target]})
|
|
235
|
+
}}}
|
|
236
|
+
export{createOpenCodeV1VersionUpdater,createOpenCodeV2VersionUpdater,createVersionStatus,createVersionUpdateActions
|
|
237
|
+
}
|
package/dist/project-profile.js
CHANGED
|
@@ -50,6 +50,9 @@ return Object.fromEntries(SIDEBAR_SECTIONS.flatMap((section)=>{const limit=input
|
|
|
50
50
|
return typeof limit==="number"&&Number.isSafeInteger(limit)&&limit>=0?[[section,limit]]:[]
|
|
51
51
|
}))
|
|
52
52
|
}
|
|
53
|
+
var MAX_LIMITS_REFRESH_MINUTES=Math.floor(2147483647 / 60000)
|
|
54
|
+
function parseLimitsRefreshMinutes(value){return typeof value==="number"&&Number.isSafeInteger(value)&&value>=1&&value<=MAX_LIMITS_REFRESH_MINUTES?value:undefined
|
|
55
|
+
}
|
|
53
56
|
var PLUGIN_ID="opencode-navigator"
|
|
54
57
|
var TOGGLE_COMMAND=`${PLUGIN_ID}.toggle`
|
|
55
58
|
var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
|
|
@@ -61,7 +64,8 @@ return value
|
|
|
61
64
|
function parsePluginSettings(value){const input=record(value)
|
|
62
65
|
if(!input)
|
|
63
66
|
return{}
|
|
64
|
-
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},...
|
|
67
|
+
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)
|
|
68
|
+
},...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
|
|
65
69
|
},...Object.keys(parseSectionItemLimits(input.sectionItemLimits)).length>0&&{sectionItemLimits:parseSectionItemLimits(input.sectionItemLimits)
|
|
66
70
|
},...parseQuickActionOrder(input.quickActionOrder)&&{quickActionOrder:parseQuickActionOrder(input.quickActionOrder)
|
|
67
71
|
},...Object.keys(parseQuickActionVisibility(input.quickActionVisibility)).length>0&&{quickActionVisibility:parseQuickActionVisibility(input.quickActionVisibility)
|
package/dist/provider-limits.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {PLUGIN_ID
|
|
2
|
-
} from "./chunk-
|
|
2
|
+
} from "./chunk-d1bws32s.js";
|
|
3
3
|
function createCodexAppServerClient(input){const command=input.command??["codex","app-server","--stdio"]
|
|
4
4
|
const timeoutMs=input.timeoutMs??1e4
|
|
5
5
|
const pending=new Map
|
|
@@ -1042,13 +1042,17 @@ try{return await promise
|
|
|
1042
1042
|
} finally{if(pending?.promise===promise)
|
|
1043
1043
|
pending=undefined
|
|
1044
1044
|
}}
|
|
1045
|
-
function invalidate(){generation++
|
|
1045
|
+
function invalidate(eager=true){generation++
|
|
1046
|
+
if(eager)
|
|
1046
1047
|
setConnections({})
|
|
1048
|
+
else{const active=lastModel&&key(lastModel)
|
|
1049
|
+
setConnections((values)=>Object.fromEntries(Object.entries(values).filter(([target])=>target===active)))
|
|
1050
|
+
}
|
|
1047
1051
|
if(lastModel&&!disposed)
|
|
1048
1052
|
read(lastModel)
|
|
1049
1053
|
}
|
|
1050
1054
|
const events=["credential.switched","credential.updated","integration.updated","provider.updated","server.connected"]
|
|
1051
|
-
const unsubscribes=events.map((event)=>context.data.on(event,()=>untrack2(invalidate)))
|
|
1055
|
+
const unsubscribes=events.map((event)=>context.data.on(event,()=>untrack2(()=>invalidate(event!=="provider.updated"))))
|
|
1052
1056
|
return{current(model){lastModel=model
|
|
1053
1057
|
return{...model,hostConnection:connections()[key(model)]??{status:"loading"}}},async refresh(model){await read(model)
|
|
1054
1058
|
},async validate(model,signal){const actual=await read(model,signal)
|
|
@@ -1102,10 +1106,6 @@ return model?bindCodexAccount(accountSource?.current(model)??model,preferences):
|
|
|
1102
1106
|
if(model)
|
|
1103
1107
|
await accountSource.refresh(model)
|
|
1104
1108
|
}))
|
|
1105
|
-
native?.onUpdated((providerID,modelID)=>{const selected=selectModel()
|
|
1106
|
-
if(selected?.providerID===providerID&&selected.modelID===modelID)
|
|
1107
|
-
controller.refresh()
|
|
1108
|
-
})
|
|
1109
1109
|
return{controller,codex,accountSource,selectModel,modelSelection:createLimitsModelSelection(api,selectModel,context)
|
|
1110
1110
|
}}
|
|
1111
1111
|
export{ProviderLimitsSection,bindCodexAccount,createCodexAppServerClient,createCodexQuotaAdapter,createOpenCodeV2AccountSource,createProviderLimitsController,createProviderQuotaIntegration,selectedV1Model
|
package/dist/tui.js
CHANGED
|
@@ -3,7 +3,7 @@ import {insert as _$insert,setProp as _$setProp,createElement as _$createElement
|
|
|
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 Show19,createSignal as createSignal27,untrack as untrack5,createSignal as createSignal28,createSignal as createSignal29,createEffect as createEffect15,For as For14,Show as Show15,Show as Show16,Show as Show17,Show as Show18,For as For15,Show as Show21,createMemo as createMemo15,Show as Show20,createMemo as createMemo14,createSignal as createSignal30,createEffect as createEffect16,onCleanup as onCleanup18,For as For20,Match,Switch,createMemo as createMemo19,onCleanup as onCleanup22,For as For16,Show as Show22,createSignal as createSignal31,createEffect as createEffect17,createMemo as createMemo16,onCleanup as onCleanup19,untrack as untrack6,For as For18,Show as Show25,createEffect as createEffect18,createMemo as createMemo17,createSignal as createSignal32,onCleanup as onCleanup20,untrack as untrack7,For as For17,Show as Show24,Show as Show23,Show as Show29,createEffect as createEffect19,createMemo as createMemo18,createSignal as createSignal33,onCleanup as onCleanup21,untrack as untrack8,For as For19,Show as Show27,Show as Show26,Show as Show28,createEffect as createEffect20,createMemo as createMemo20,onCleanup as onCleanup23,untrack as untrack9,Show as Show30,createMemo as createMemo21,onCleanup as onCleanup24,createEffect as createEffect21,
|
|
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 Show19,createSignal as createSignal27,untrack as untrack5,createSignal as createSignal28,createSignal as createSignal29,createEffect as createEffect15,For as For14,Show as Show15,Show as Show16,Show as Show17,Show as Show18,For as For15,Show as Show21,createMemo as createMemo15,Show as Show20,createMemo as createMemo14,createSignal as createSignal30,createEffect as createEffect16,onCleanup as onCleanup18,For as For20,Match,Switch,createMemo as createMemo19,onCleanup as onCleanup22,For as For16,Show as Show22,createSignal as createSignal31,createEffect as createEffect17,createMemo as createMemo16,onCleanup as onCleanup19,untrack as untrack6,For as For18,Show as Show25,createEffect as createEffect18,createMemo as createMemo17,createSignal as createSignal32,onCleanup as onCleanup20,untrack as untrack7,For as For17,Show as Show24,Show as Show23,Show as Show29,createEffect as createEffect19,createMemo as createMemo18,createSignal as createSignal33,onCleanup as onCleanup21,untrack as untrack8,For as For19,Show as Show27,Show as Show26,Show as Show28,createEffect as createEffect20,createMemo as createMemo20,onCleanup as onCleanup23,untrack as untrack9,Show as Show30,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"
|
|
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"
|
|
@@ -66,6 +66,10 @@ return Object.fromEntries(Object.entries(defaults).map(([name,visible])=>[name,t
|
|
|
66
66
|
function parseSectionVisibility(value){return resolveSectionVisibility({limits:true,todo:true,subagents:true,skills:true,quick_actions:true,lsp:true,mcp:true
|
|
67
67
|
},value)
|
|
68
68
|
}
|
|
69
|
+
var DEFAULT_LIMITS_REFRESH_MINUTES=5
|
|
70
|
+
var MAX_LIMITS_REFRESH_MINUTES=Math.floor(2147483647 / 60000)
|
|
71
|
+
function parseLimitsRefreshMinutes(value){return typeof value==="number"&&Number.isSafeInteger(value)&&value>=1&&value<=MAX_LIMITS_REFRESH_MINUTES?value:undefined
|
|
72
|
+
}
|
|
69
73
|
var PLUGIN_ID="opencode-navigator"
|
|
70
74
|
var LEGACY_PLUGIN_ID="opencode-pretty-sidebar"
|
|
71
75
|
var TOGGLE_COMMAND=`${PLUGIN_ID}.toggle`
|
|
@@ -73,7 +77,7 @@ var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
|
|
|
73
77
|
var SEARCH_COMMAND=`${PLUGIN_ID}.search`
|
|
74
78
|
var DEFAULT_SEARCH_KEY="ctrl+shift+k";
|
|
75
79
|
function pluginConfig(options){const iconStyle=options?.icon_style==="nerd"||options?.icon_style==="text"?options.icon_style:options?.lsp_icon_style
|
|
76
|
-
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,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",sectionItemLimits:parseSectionItemLimits(options?.section_item_limits),quickActionOrder:parseQuickActionOrder(options?.quick_action_order)??[...QUICK_ACTION_IDS],quickActionVisibility:parseQuickActionVisibility(options?.quick_action_visibility)
|
|
77
81
|
}}
|
|
78
82
|
function currentLocation(api){const route=api.route.current
|
|
79
83
|
const params="params" in route?route.params:undefined
|
|
@@ -1206,7 +1210,8 @@ return value
|
|
|
1206
1210
|
function parsePluginSettings(value){const input=record(value)
|
|
1207
1211
|
if(!input)
|
|
1208
1212
|
return{}
|
|
1209
|
-
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},...
|
|
1213
|
+
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)
|
|
1214
|
+
},...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
|
|
1210
1215
|
},...Object.keys(parseSectionItemLimits(input.sectionItemLimits)).length>0&&{sectionItemLimits:parseSectionItemLimits(input.sectionItemLimits)
|
|
1211
1216
|
},...parseQuickActionOrder(input.quickActionOrder)&&{quickActionOrder:parseQuickActionOrder(input.quickActionOrder)
|
|
1212
1217
|
},...Object.keys(parseQuickActionVisibility(input.quickActionVisibility)).length>0&&{quickActionVisibility:parseQuickActionVisibility(input.quickActionVisibility)
|
|
@@ -1337,7 +1342,7 @@ Object.assign(desiredMcpStates,layer.desiredMcpStates)
|
|
|
1337
1342
|
return{behavior,layout:{sections,expanded,order},desiredMcpStates}}
|
|
1338
1343
|
import {randomUUID} from "crypto"
|
|
1339
1344
|
import {link,mkdir,readFile,readdir,rename,rm,unlink,writeFile,readFile as readFile2} from "fs/promises"
|
|
1340
|
-
import {join,dirname,join as join2,join as join3
|
|
1345
|
+
import {join,dirname,join as join2,join as join3} from "path"
|
|
1341
1346
|
var LOCK_TIMEOUT_MS=3000
|
|
1342
1347
|
function errno(error,code){return error instanceof Error&&"code" in error&&error.code===code
|
|
1343
1348
|
}
|
|
@@ -1638,7 +1643,7 @@ return{behavior:scope.behavior,layout:scope.layout,desiredMcpStates:scope.mcp
|
|
|
1638
1643
|
}}
|
|
1639
1644
|
function mergeSessionLayout(base,session){const order=session.order??base?.order
|
|
1640
1645
|
return{sections:{...base?.sections,...session.sections},expanded:{...base?.expanded,...session.expanded},...order&&{order:[...order]}}}
|
|
1641
|
-
function createPreferencesController(api,defaults,store,configured={}){const builtIns={behavior:{toggleKey:defaults.toggleKey,focusKey:defaults.focusKey,searchKey:defaults.searchKey,persistMcp:defaults.persistMcp,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
|
|
1646
|
+
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
|
|
1642
1647
|
},layout:{sections:defaults.sections,expanded:DEFAULT_SECTION_EXPANSION,order:defaults.sectionOrder??[...SIDEBAR_SECTIONS]
|
|
1643
1648
|
},desiredMcpStates:{}}
|
|
1644
1649
|
const [resolved,setResolved]=createSignal4(resolvePreferences({builtIns,pluginOptions:configured}))
|
|
@@ -1881,9 +1886,13 @@ next.add(id)
|
|
|
1881
1886
|
setFavoriteQuickActions(next)
|
|
1882
1887
|
update({user:{favoriteQuickAction:{id,favorite:next.has(id)}}})
|
|
1883
1888
|
}
|
|
1884
|
-
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,showSessionTitle:()=>resolved().behavior.showSessionTitle,showSessionDate:()=>resolved().behavior.showSessionDate,startInChatForScope:(scope)=>{revision()
|
|
1889
|
+
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()
|
|
1885
1890
|
return resolveTarget(targetForScope(scope),false).behavior.startInChat
|
|
1886
|
-
},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,
|
|
1891
|
+
},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)
|
|
1892
|
+
throw new Error("Enter whole minutes (at least 1 minute, within the supported timer range)")
|
|
1893
|
+
load()
|
|
1894
|
+
update({target:selectedTarget(),behavior:{limitsRefreshMinutes:value}})
|
|
1895
|
+
},selectedStartInChat:()=>selectedResolved().behavior.startInChat,selectedShowSessionTitle:()=>selectedResolved().behavior.showSessionTitle,selectedShowSessionDate:()=>selectedResolved().behavior.showSessionDate,selectedCornerFont:()=>selectedResolved().behavior.cornerFont,selectedLspIconStyle:()=>selectedResolved().behavior.lspIconStyle,selectedRowDensity:()=>selectedResolved().behavior.rowDensity,quickActionOrder:()=>resolved().behavior.quickActionOrder,quickActionVisible:(id)=>resolved().behavior.quickActionVisibility[id]!==false,selectedQuickActionOrder:()=>selectedResolved().behavior.quickActionOrder,selectedQuickActionVisible:(id)=>selectedResolved().behavior.quickActionVisibility[id]!==false,toggleQuickAction(id){load()
|
|
1887
1896
|
update({target:selectedTarget(),behavior:{quickActionVisibility:{[id]:selectedResolved().behavior.quickActionVisibility[id]===false}}})
|
|
1888
1897
|
},moveQuickAction(id,direction){load()
|
|
1889
1898
|
const order=[...selectedResolved().behavior.quickActionOrder]
|
|
@@ -2904,7 +2913,7 @@ return{groups,rows:groups.flatMap((group)=>group.items.map((item)=>({item,group:
|
|
|
2904
2913
|
|
|
2905
2914
|
function KeyboardHelpDialog(props){const icons=useIcons()
|
|
2906
2915
|
const theme=()=>props.api.theme.current
|
|
2907
|
-
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+,",`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`]
|
|
2916
|
+
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`]
|
|
2908
2917
|
return _$createComponent(DialogSurface,{get api(){return props.api
|
|
2909
2918
|
},get children(){return [(()=>{var _el$=_$createElement("text"),_el$2=_$createTextNode(` Navigator keyboard help`)
|
|
2910
2919
|
_$insertNode(_el$,_el$2)
|
|
@@ -4142,6 +4151,20 @@ dialogs.open(()=>_$createComponent(SelectionMenu,{api,title:"MCP presets",get op
|
|
|
4142
4151
|
|
|
4143
4152
|
|
|
4144
4153
|
|
|
4154
|
+
function behaviorSettingsOptions(api,preferences,icons){const permission=preferences.autoApprovePermissions()
|
|
4155
|
+
const permissionDescription=permission?"on for new sessions":"off for new sessions"
|
|
4156
|
+
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
|
|
4157
|
+
}]:[],{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"
|
|
4158
|
+
},{title:`${icons.icon(preferences.selectedPersistMcp() ? "checked" : "unchecked")} Remember MCP states`,value:"persist_mcp",description:preferences.selectedPersistMcp()?"on":"off"
|
|
4159
|
+
},{title:`${icons.icon("settings")} Icon style`,value:"lsp_icon_style",description:preferences.selectedLspIconStyle()==="nerd"?"Nerd Font":"Text fallback"
|
|
4160
|
+
},{title:`${icons.icon(preferences.selectedCornerFont() ? "checked" : "unchecked")} Multiline corner font`,value:"corner_font",description:preferences.selectedCornerFont()?"Installed":"Not installed \xB7 rectangular highlights"
|
|
4161
|
+
},{title:`${icons.icon("sections")} Row density`,value:"row_density",description:preferences.selectedRowDensity()==="compact"?"Compact":"Comfortable"
|
|
4162
|
+
},{title:`${icons.icon("sections")} Sidebar shortcut`,value:"toggle_key",description:preferences.selectedToggleKey()
|
|
4163
|
+
},{title:`${icons.icon("selected")} Focus shortcut`,value:"focus_key",description:preferences.selectedFocusKey()
|
|
4164
|
+
},{title:`${icons.icon("search")} Search Everything shortcut`,value:"search_key",description:preferences.selectedSearchKey?.()??DEFAULT_SEARCH_KEY
|
|
4165
|
+
},{title:`${icons.icon("retry")} Limits refresh interval`,value:"limits_refresh",description:`${preferences.selectedLimitsRefreshMinutes()} min \xB7 minimum 1 min`
|
|
4166
|
+
}]
|
|
4167
|
+
}
|
|
4145
4168
|
function titleVisibilityOptions(api,preferences,icons){if(!supportsTitleVisibility(api))
|
|
4146
4169
|
return []
|
|
4147
4170
|
const title=preferences.selectedShowSessionTitle()
|
|
@@ -4151,11 +4174,6 @@ return [{title:`${icons.icon(title ? "checked" : "unchecked")} Session title`,va
|
|
|
4151
4174
|
}]
|
|
4152
4175
|
}
|
|
4153
4176
|
function createSettingsGroups(api,preferences,icons){const supportedSections=()=>SIDEBAR_SECTIONS.filter((name)=>supportsSidebarSection(api,name))
|
|
4154
|
-
const permissionDefaultDescription=()=>{const value=preferences.autoApprovePermissions()
|
|
4155
|
-
if(value===undefined)
|
|
4156
|
-
return "follow OpenCode startup mode"
|
|
4157
|
-
return value?"on for new sessions":"off for new sessions"
|
|
4158
|
-
}
|
|
4159
4177
|
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"
|
|
4160
4178
|
},{title:`${icons.icon(preferences.preferenceScope() === "worktree" ? "radioOn" : "radioOff")} Current worktree`,value:"scope:worktree",description:preferences.canUseWorktreeScope()?preferences.preferenceScopeLabel():"unavailable outside a worktree"
|
|
4161
4179
|
}]
|
|
@@ -4165,16 +4183,7 @@ const groups=createMemo7(()=>[{id:"scope",tab:"Scope",title:"Preference scope",o
|
|
|
4165
4183
|
},{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)
|
|
4166
4184
|
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"
|
|
4167
4185
|
}})]
|
|
4168
|
-
},{id:"behavior",tab:"Behavior",title:"Behavior",options:
|
|
4169
|
-
}]:[],{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"
|
|
4170
|
-
},{title:`${icons.icon(preferences.selectedPersistMcp() ? "checked" : "unchecked")} Remember MCP states`,value:"persist_mcp",description:preferences.selectedPersistMcp()?"on":"off"
|
|
4171
|
-
},{title:`${icons.icon("settings")} Icon style`,value:"lsp_icon_style",description:preferences.selectedLspIconStyle()==="nerd"?"Nerd Font":"Text fallback"
|
|
4172
|
-
},{title:`${icons.icon(preferences.selectedCornerFont() ? "checked" : "unchecked")} Multiline corner font`,value:"corner_font",description:preferences.selectedCornerFont()?"Installed":"Not installed \xB7 rectangular highlights"
|
|
4173
|
-
},{title:`${icons.icon("sections")} Row density`,value:"row_density",description:preferences.selectedRowDensity()==="compact"?"Compact":"Comfortable"
|
|
4174
|
-
},{title:`${icons.icon("sections")} Sidebar shortcut`,value:"toggle_key",description:preferences.selectedToggleKey()
|
|
4175
|
-
},{title:`${icons.icon("selected")} Focus shortcut`,value:"focus_key",description:preferences.selectedFocusKey()
|
|
4176
|
-
},{title:`${icons.icon("search")} Search Everything shortcut`,value:"search_key",description:preferences.selectedSearchKey?.()??DEFAULT_SEARCH_KEY
|
|
4177
|
-
}]
|
|
4186
|
+
},{id:"behavior",tab:"Behavior",title:"Behavior",options:behaviorSettingsOptions(api,preferences,icons)
|
|
4178
4187
|
},{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`
|
|
4179
4188
|
},{title:`${icons.icon("export")} Copy portable settings`,value:"export_settings",description:"versioned layout and MCP JSON"
|
|
4180
4189
|
},{title:`${icons.icon("add")} Import portable settings\u2026`,value:"import_settings",description:"preview pasted JSON before applying"
|
|
@@ -4209,6 +4218,24 @@ input.openLimitPrompt(section)
|
|
|
4209
4218
|
|
|
4210
4219
|
|
|
4211
4220
|
|
|
4221
|
+
|
|
4222
|
+
|
|
4223
|
+
|
|
4224
|
+
|
|
4225
|
+
|
|
4226
|
+
function openLimitsRefreshPrompt(api,preferences,dialogs){const scope=preferences.preferenceScopeLabel()
|
|
4227
|
+
dialogs.prompt({title:"Limits refresh interval",description:()=>(()=>{var _el$=_$createElement("text")
|
|
4228
|
+
_$insertNode(_el$,_$createTextNode(`Automatic refresh in minutes (minimum 1; default 5). Manual Refresh stays immediate.`))
|
|
4229
|
+
_$effect((_$p)=>_$setProp(_el$,"fg",api.theme.current.textMuted,_$p))
|
|
4230
|
+
return _el$
|
|
4231
|
+
})(),value:String(preferences.selectedLimitsRefreshMinutes()),onConfirm(value){if(preferences.preferenceScopeLabel()!==scope)
|
|
4232
|
+
throw new Error("Preference scope changed; reopen this setting")
|
|
4233
|
+
if(!/^\d+$/.test(value.trim()))
|
|
4234
|
+
throw new Error("Enter whole minutes (at least 1 minute)")
|
|
4235
|
+
preferences.setLimitsRefreshMinutes(Number(value))
|
|
4236
|
+
dialogs.back()
|
|
4237
|
+
}})
|
|
4238
|
+
}
|
|
4212
4239
|
function createSettingsSelection(input){const dialogClosed=()=>("open" in input.api.ui.dialog)&&!input.api.ui.dialog.open
|
|
4213
4240
|
function openLimitPrompt(section){const index=input.options().findIndex((option)=>option.value===section)
|
|
4214
4241
|
if(index!==-1)
|
|
@@ -4289,6 +4316,9 @@ break
|
|
|
4289
4316
|
case "persist_mcp":{input.preferences.toggleMcpPersistence()
|
|
4290
4317
|
break
|
|
4291
4318
|
}
|
|
4319
|
+
case "limits_refresh":{openLimitsRefreshPrompt(input.api,input.preferences,input.dialogs)
|
|
4320
|
+
break
|
|
4321
|
+
}
|
|
4292
4322
|
case "start_in_chat":{input.preferences.toggleStartInChat()
|
|
4293
4323
|
break
|
|
4294
4324
|
}
|
|
@@ -4901,27 +4931,6 @@ clearTimeout(pending)
|
|
|
4901
4931
|
return _$createElement("box")
|
|
4902
4932
|
}
|
|
4903
4933
|
|
|
4904
|
-
var NAVIGATOR_PACKAGE_URL="https://registry.npmjs.org/opencode-navigator/latest"
|
|
4905
|
-
var REQUEST_TIMEOUT_MS=5000
|
|
4906
|
-
function createVersionStatus(api,navigatorVersion,request=fetch){const [openCodeUpdate,setOpenCodeUpdate]=createSignal17()
|
|
4907
|
-
const [navigatorUpdate,setNavigatorUpdate]=createSignal17()
|
|
4908
|
-
const controller=new AbortController
|
|
4909
|
-
const timeout=setTimeout(()=>controller.abort(),REQUEST_TIMEOUT_MS)
|
|
4910
|
-
const unsubscribe=api.event.on("installation.update-available",(event)=>{const version=event.properties.version
|
|
4911
|
-
setOpenCodeUpdate(isNewerVersion(version,api.app.version)?version:undefined)
|
|
4912
|
-
})
|
|
4913
|
-
api.lifecycle.onDispose(()=>{clearTimeout(timeout)
|
|
4914
|
-
controller.abort()
|
|
4915
|
-
unsubscribe()
|
|
4916
|
-
})
|
|
4917
|
-
request(NAVIGATOR_PACKAGE_URL,{headers:{accept:"application/json"},signal:controller.signal
|
|
4918
|
-
}).then(async (response)=>{if(!response.ok)
|
|
4919
|
-
return
|
|
4920
|
-
const metadata=await response.json()
|
|
4921
|
-
if(typeof metadata.version==="string")
|
|
4922
|
-
setNavigatorUpdate(isNewerVersion(metadata.version,navigatorVersion)?metadata.version:undefined)
|
|
4923
|
-
}).catch(()=>{}).finally(()=>clearTimeout(timeout))
|
|
4924
|
-
return{openCodeUpdate,navigatorUpdate}}
|
|
4925
4934
|
|
|
4926
4935
|
|
|
4927
4936
|
|
|
@@ -5011,39 +5020,6 @@ return _el$
|
|
|
5011
5020
|
})()
|
|
5012
5021
|
}
|
|
5013
5022
|
|
|
5014
|
-
function createVersionUpdateActions(api,status,updater,rememberNavigatorVersion){const busy=new Set
|
|
5015
|
-
function target(kind){return kind==="openCode"?status.openCodeUpdate():status.navigatorUpdate()
|
|
5016
|
-
}
|
|
5017
|
-
function label(kind){return kind==="openCode"?"OpenCode":"Navigator"
|
|
5018
|
-
}
|
|
5019
|
-
function update(kind,version){if(busy.has(kind))
|
|
5020
|
-
return
|
|
5021
|
-
api.ui.dialog.clear()
|
|
5022
|
-
busy.add(kind)
|
|
5023
|
-
api.ui.toast({variant:"info",title:`Updating ${label(kind)}`,message:`Installing ${version}...`
|
|
5024
|
-
});
|
|
5025
|
-
(async ()=>{if(kind==="navigator")
|
|
5026
|
-
await rememberNavigatorVersion?.()
|
|
5027
|
-
await updater[kind](version)
|
|
5028
|
-
})().then(()=>{api.ui.toast({variant:"success",title:`${label(kind)} updated`,message:"Restart OpenCode to use the new version.",duration:6000
|
|
5029
|
-
})
|
|
5030
|
-
}).catch((error)=>{api.ui.toast({variant:"error",title:`Could not update ${label(kind)}`,message:error instanceof Error?error.message:"Update failed",duration:6000
|
|
5031
|
-
})
|
|
5032
|
-
}).finally(()=>busy.delete(kind))
|
|
5033
|
-
}
|
|
5034
|
-
function open(kind,version=target(kind)){if(!version||busy.has(kind))
|
|
5035
|
-
return
|
|
5036
|
-
api.ui.dialog.replace(()=>_$createComponent(api.ui.DialogConfirm,{get title(){return `Update ${label(kind)}`
|
|
5037
|
-
},message:`Update to ${version} using the current installation method? OpenCode must be restarted afterward.`,onConfirm:()=>update(kind,version),onCancel:()=>api.ui.dialog.clear()
|
|
5038
|
-
}))
|
|
5039
|
-
}
|
|
5040
|
-
const unregister=api.keymap.registerLayer({commands:[{name:`${PLUGIN_ID}.update-opencode`,title:"Update OpenCode",category:"Navigator",namespace:"palette",enabled:()=>Boolean(target("openCode"))&&!busy.has("openCode"),run:()=>open("openCode")
|
|
5041
|
-
},{name:`${PLUGIN_ID}.update-navigator`,title:"Update Navigator",category:"Navigator",namespace:"palette",enabled:()=>Boolean(target("navigator"))&&!busy.has("navigator"),run:()=>open("navigator")
|
|
5042
|
-
}]
|
|
5043
|
-
})
|
|
5044
|
-
api.lifecycle.onDispose(unregister)
|
|
5045
|
-
return{openCode:(version)=>open("openCode",version),navigator:(version)=>open("navigator",version)
|
|
5046
|
-
}}
|
|
5047
5023
|
function matchesFilter(query,...values){const needle=query.trim().toLocaleLowerCase()
|
|
5048
5024
|
return !needle||values.some((value)=>value?.toLocaleLowerCase().includes(needle))
|
|
5049
5025
|
}
|
|
@@ -6363,8 +6339,9 @@ var ENTRY_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.enter`
|
|
|
6363
6339
|
var CANCEL_COMMAND=`${PLUGIN_ID}.sidebar-shortcuts.cancel`
|
|
6364
6340
|
var MODE=`${PLUGIN_ID}.sidebar-shortcuts`
|
|
6365
6341
|
var DEFAULT_TIMEOUT_MS=5000
|
|
6366
|
-
var ACTIONS=[{key:"h",command:"session.sidebar.toggle",section:undefined},{key:"t",command:`${PLUGIN_ID}.focus.todo`,section:"todo"},{key:"a",command:`${PLUGIN_ID}.focus.subagents`,section:"subagents"},{key:"s",command:`${PLUGIN_ID}.focus.skills`,section:"skills"},{key:"q",command:`${PLUGIN_ID}.focus.quick_actions`,section:"quick_actions"},{key:"l",command:`${PLUGIN_ID}.focus.lsp`,section:"lsp"},{key:"m",command:`${PLUGIN_ID}.focus.mcp`,section:"mcp"}]
|
|
6342
|
+
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}]
|
|
6367
6343
|
function createSidebarShortcutMode(api,options={}){const actions=ACTIONS.filter(({section})=>!section||supportsSidebarSection(api,section))
|
|
6344
|
+
const hints=actions.map(({key,hint})=>`${key} ${hint}`).join(" | ")
|
|
6368
6345
|
const timeoutMs=options.timeoutMs??DEFAULT_TIMEOUT_MS
|
|
6369
6346
|
let shortcutKey=""
|
|
6370
6347
|
let unregisterBinding
|
|
@@ -6391,7 +6368,7 @@ unregisterMode=api.keymap.registerLayer({mode:MODE,priority:2000,commands:[{name
|
|
|
6391
6368
|
})
|
|
6392
6369
|
leaveMode=api.mode.push(MODE)
|
|
6393
6370
|
timeout=setTimeout(cancel,timeoutMs)
|
|
6394
|
-
api.ui?.toast?.({variant:"info",title:"Navigator shortcuts",message
|
|
6371
|
+
api.ui?.toast?.({variant:"info",title:"Navigator shortcuts",message:`${hints} | Esc cancel`,duration:timeoutMs
|
|
6395
6372
|
})
|
|
6396
6373
|
return true
|
|
6397
6374
|
}
|
|
@@ -7203,25 +7180,39 @@ return mergeConfiguredDefaults(configuredDefaultsFromPluginOptions(options),user
|
|
|
7203
7180
|
}
|
|
7204
7181
|
|
|
7205
7182
|
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7183
|
+
var scheduleInterval=(callback,milliseconds)=>{const timer=setInterval(callback,milliseconds)
|
|
7184
|
+
return()=>clearInterval(timer)
|
|
7185
|
+
}
|
|
7186
|
+
function createLimitsRefresh(options,schedule=scheduleInterval){let disposed=false
|
|
7187
|
+
const selectedKey=createMemo22(()=>JSON.stringify(options.selectedModel?.()))
|
|
7188
|
+
const targetKey=createMemo22(()=>JSON.stringify(options.controller.current().model))
|
|
7189
|
+
const interval=createMemo22(()=>(parseLimitsRefreshMinutes(options.refreshMinutes?.())??DEFAULT_LIMITS_REFRESH_MINUTES)*60000)
|
|
7190
|
+
createEffect21(on2(selectedKey,()=>{const model=options.selectedModel?.()
|
|
7191
|
+
if(model&&options.accountSource)
|
|
7192
|
+
options.accountSource.refresh(model).catch(()=>{})
|
|
7193
|
+
}))
|
|
7194
|
+
createEffect21(on2(targetKey,()=>{const{model,adapter}=options.controller.current()
|
|
7212
7195
|
if(model&&adapter)
|
|
7213
|
-
|
|
7196
|
+
options.controller.refresh()
|
|
7197
|
+
}))
|
|
7198
|
+
async function refresh(){if(disposed)
|
|
7199
|
+
return
|
|
7200
|
+
const target=targetKey()
|
|
7201
|
+
const model=options.selectedModel?.()
|
|
7202
|
+
if(model&&options.accountSource)
|
|
7203
|
+
await options.accountSource.refresh(model)
|
|
7204
|
+
if(!disposed&&target===targetKey())
|
|
7205
|
+
await options.controller.refresh()
|
|
7206
|
+
}
|
|
7207
|
+
createEffect21(on2(interval,(milliseconds)=>{onCleanup25(schedule(()=>void refresh().catch(()=>{}),milliseconds))
|
|
7208
|
+
}))
|
|
7209
|
+
onCleanup25(()=>{disposed=true
|
|
7214
7210
|
})
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
props.accountSource.refresh(model).then(()=>untrack10(()=>props.controller.refresh()))
|
|
7218
|
-
else
|
|
7219
|
-
props.controller.refresh()
|
|
7220
|
-
},5000)
|
|
7221
|
-
onCleanup25(()=>clearInterval(timer))
|
|
7211
|
+
}
|
|
7212
|
+
function LimitsPersistence(props){createLimitsRefresh(props)
|
|
7222
7213
|
return _$createElement("box")
|
|
7223
7214
|
}
|
|
7224
|
-
import {homedir
|
|
7215
|
+
import {homedir} from "os"
|
|
7225
7216
|
|
|
7226
7217
|
function location(input){return input.directory?{location:{directory:input.directory}}:{}}
|
|
7227
7218
|
function mcpItem(server){return{name:server.name,status:server.status.status,...server.status.error&&{error:server.status.error}}}
|
|
@@ -7511,72 +7502,9 @@ for(let index=disposers.length-1;index>=0; index--)
|
|
|
7511
7502
|
await disposers[index]()
|
|
7512
7503
|
disposers.length=0
|
|
7513
7504
|
}}}
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
import {fileURLToPath} from "url"
|
|
7517
|
-
var run=async (command)=>{const child=Bun.spawn([...command],{stdout:"ignore",stderr:"pipe"})
|
|
7518
|
-
const error=new Response(child.stderr).text()
|
|
7519
|
-
const exitCode=await child.exited
|
|
7520
|
-
if(exitCode===0)
|
|
7521
|
-
return
|
|
7522
|
-
const message=await error
|
|
7523
|
-
throw new Error(message.trim()||`Command failed with exit code ${child.exitCode}`)
|
|
7524
|
-
}
|
|
7525
|
-
var readConfig=async (path)=>{const file=Bun.file(path)
|
|
7526
|
-
return await file.exists()?Bun.JSONC.parse(await file.text()):undefined
|
|
7505
|
+
function loadNavigatorUpdates(){const path=import.meta.url.includes("/dist/tui.js")?"./navigator-updates.js":"../navigator-updates"
|
|
7506
|
+
return import(path)
|
|
7527
7507
|
}
|
|
7528
|
-
function pinnedUpdate(wrapper,target,execute){if(basename(wrapper)!=="tui.js"||basename(dirname2(wrapper))!=="opencode-navigator")
|
|
7529
|
-
throw new Error("Unrecognized local Navigator source")
|
|
7530
|
-
const installer=fileURLToPath(new URL("../scripts/update-local-snapshot.mjs",import.meta.url))
|
|
7531
|
-
return execute(["node",installer,wrapper,target])
|
|
7532
|
-
}
|
|
7533
|
-
function configHasPlugin(value,spec){if(!value||typeof value!=="object")
|
|
7534
|
-
return false
|
|
7535
|
-
const plugins=value.plugin
|
|
7536
|
-
return Array.isArray(plugins)&&plugins.some((item)=>{let configured=item
|
|
7537
|
-
if(Array.isArray(item))
|
|
7538
|
-
configured=item[0]
|
|
7539
|
-
else if(item&&typeof item==="object")
|
|
7540
|
-
configured=item.package
|
|
7541
|
-
return configured===spec
|
|
7542
|
-
})
|
|
7543
|
-
}
|
|
7544
|
-
async function v1Global(api,spec,read){const configRoot=process.env.OPENCODE_CONFIG_DIR??join4(process.env.XDG_CONFIG_HOME??join4(homedir2(),".config"),"opencode")
|
|
7545
|
-
const global=join4(configRoot,"tui.json")
|
|
7546
|
-
const configured=api.state.path.config.endsWith(".json")?api.state.path.config:join4(api.state.path.config,"tui.json")
|
|
7547
|
-
const local=new Set([configured,join4(api.state.path.worktree,".opencode","tui.json")])
|
|
7548
|
-
local.delete(global)
|
|
7549
|
-
for(const path of local)
|
|
7550
|
-
if(configHasPlugin(await read(path),spec))
|
|
7551
|
-
return false
|
|
7552
|
-
return configHasPlugin(await read(global),spec)
|
|
7553
|
-
}
|
|
7554
|
-
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>execute([process.execPath,"upgrade",target]),async navigator(target){if(meta.source==="file"){const wrapper=meta.spec.startsWith("file://")?fileURLToPath(meta.spec):meta.spec
|
|
7555
|
-
return pinnedUpdate(wrapper,target,execute)
|
|
7556
|
-
}
|
|
7557
|
-
if(meta.source!=="npm")
|
|
7558
|
-
throw new Error("Unrecognized local Navigator source")
|
|
7559
|
-
const result=await api.plugins.install(`opencode-navigator@${target}`,{global:await v1Global(api,meta.spec,read)
|
|
7560
|
-
})
|
|
7561
|
-
if(!result.ok)
|
|
7562
|
-
throw new Error(result.message)
|
|
7563
|
-
}}}
|
|
7564
|
-
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>execute([process.execPath,"upgrade",target]),async navigator(target){const response=await context.client.plugin.list(context.location?{location:context.location}:{})
|
|
7565
|
-
const item=response.data.find((plugin)=>plugin.id===PLUGIN_ID)
|
|
7566
|
-
if(!item)
|
|
7567
|
-
throw new Error("Navigator is not in the active plugin list")
|
|
7568
|
-
if(item.source.type==="local")
|
|
7569
|
-
return pinnedUpdate(basename(item.source.path)==="tui.js"?item.source.path:join4(item.source.path,"tui.js"),target,execute)
|
|
7570
|
-
if(item.source.type!=="package")
|
|
7571
|
-
throw new Error("Unrecognized local Navigator source")
|
|
7572
|
-
if(isAbsolute(item.source.target))
|
|
7573
|
-
return pinnedUpdate(join4(item.source.target,"tui.js"),target,execute)
|
|
7574
|
-
if(item.source.target.startsWith("file://"))
|
|
7575
|
-
return pinnedUpdate(join4(fileURLToPath(item.source.target),"tui.js"),target,execute)
|
|
7576
|
-
if(item.source.target.startsWith("."))
|
|
7577
|
-
throw new Error("Unrecognized local Navigator source")
|
|
7578
|
-
await context.client.plugin.update({location:response.location,targets:[item.source.target]})
|
|
7579
|
-
}}}
|
|
7580
7508
|
async function setupNavigator(api,options,readProject,managedTodo,hostContext){const config=pluginConfig(undefined)
|
|
7581
7509
|
const configured=await loadConfiguredDefaults(api,options,readProject)
|
|
7582
7510
|
const todo=managedTodo??createTodoController(api)
|
|
@@ -7587,7 +7515,7 @@ const limitsPath=import.meta.url.includes("/dist/tui.js")?"./provider-limits.js"
|
|
|
7587
7515
|
const limitsModule=await import(limitsPath)
|
|
7588
7516
|
const LimitsSection=limitsModule.ProviderLimitsSection
|
|
7589
7517
|
const{controller:limits,codex,accountSource,selectModel,modelSelection
|
|
7590
|
-
}=limitsModule.createProviderQuotaIntegration(api,preferences,"0.21.
|
|
7518
|
+
}=limitsModule.createProviderQuotaIntegration(api,preferences,"0.21.5",hostContext)
|
|
7591
7519
|
const mcp=createMcpController(api,preferences.persistMcp,preferences)
|
|
7592
7520
|
const interaction=createSidebarInteraction(api,()=>openKeyboardHelp(api,preferences.lspIconStyle,preferences.cornerFont))
|
|
7593
7521
|
const startup=createStartupSessionController(api,preferences)
|
|
@@ -7606,8 +7534,8 @@ api.lifecycle.onDispose(unsubscribeConnected)
|
|
|
7606
7534
|
api.slots.register({order:100,slots:{app(){return _$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7607
7535
|
},get multilineCorners(){return preferences.cornerFont
|
|
7608
7536
|
},get children(){return [_$createComponent(PreferencesPersistence,{api,controller:preferences
|
|
7609
|
-
}),_$createComponent(LimitsPersistence,{controller:limits,accountSource,selectedModel:selectModel
|
|
7610
|
-
}),_$memo(()=>_$memo(()=>!!supportsPermissionMode(api))()&&_$createComponent(PermissionModeBinding,{api,preferences
|
|
7537
|
+
}),_$createComponent(LimitsPersistence,{controller:limits,accountSource,selectedModel:selectModel,get refreshMinutes(){return preferences.limitsRefreshMinutes
|
|
7538
|
+
}}),_$memo(()=>_$memo(()=>!!supportsPermissionMode(api))()&&_$createComponent(PermissionModeBinding,{api,preferences
|
|
7611
7539
|
})),_$createComponent(SettingsBinding,{api,preferences,mcp,skills
|
|
7612
7540
|
}),_$createComponent(SidebarToggleBinding,{api,preferences
|
|
7613
7541
|
}),_$createComponent(SidebarFocusBinding,{api,preferences,interaction
|
|
@@ -7615,7 +7543,7 @@ api.slots.register({order:100,slots:{app(){return _$createComponent(IconProvider
|
|
|
7615
7543
|
},interaction,skills,subagents,mcp
|
|
7616
7544
|
}),_$createComponent(FirstRunWizardPersistence,{api,preferences
|
|
7617
7545
|
}),_$createComponent(StartupSessionBinding,{api,controller:startup
|
|
7618
|
-
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.21.
|
|
7546
|
+
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.21.5"
|
|
7619
7547
|
}),_$createComponent(McpPersistence,{api,controller:mcp
|
|
7620
7548
|
})]
|
|
7621
7549
|
}})
|
|
@@ -7646,12 +7574,14 @@ throw result.error
|
|
|
7646
7574
|
}
|
|
7647
7575
|
return result.data?.type==="text"?result.data.content:undefined
|
|
7648
7576
|
})
|
|
7649
|
-
const
|
|
7650
|
-
|
|
7577
|
+
const{createVersionStatus,createVersionUpdateActions,createOpenCodeV1VersionUpdater
|
|
7578
|
+
}=await loadNavigatorUpdates()
|
|
7579
|
+
const versionStatus=createVersionStatus(api,"0.21.5")
|
|
7580
|
+
const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.21.5"))
|
|
7651
7581
|
api.slots.register({order:90,slots:{sidebar_footer(_context,props){return _$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7652
7582
|
},get multilineCorners(){return preferences.cornerFont
|
|
7653
7583
|
},get children(){return _$createComponent(VersionFooter,{api,get sessionID(){return props.session_id
|
|
7654
|
-
},navigatorVersion:"0.21.
|
|
7584
|
+
},navigatorVersion:"0.21.5",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7655
7585
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7656
7586
|
}})
|
|
7657
7587
|
}})
|
|
@@ -7665,15 +7595,17 @@ return
|
|
|
7665
7595
|
return new TextDecoder().decode(await context.client.file.read({location:context.location,path:".opencode/navigator.json"
|
|
7666
7596
|
}))
|
|
7667
7597
|
},todo,context)
|
|
7668
|
-
const
|
|
7669
|
-
|
|
7598
|
+
const{createVersionStatus,createVersionUpdateActions,createOpenCodeV2VersionUpdater
|
|
7599
|
+
}=await loadNavigatorUpdates()
|
|
7600
|
+
const versionStatus=createVersionStatus(adapter.api,"0.21.5")
|
|
7601
|
+
const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.21.5"))
|
|
7670
7602
|
const disposeFooter=context.ui.slot({append:"sidebar.footer",render:()=>_$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7671
7603
|
},get multilineCorners(){return preferences.cornerFont
|
|
7672
7604
|
},get children(){var _el$=_$createElement("box")
|
|
7673
7605
|
_$setProp(_el$,"flexDirection","row")
|
|
7674
7606
|
_$setProp(_el$,"justifyContent","space-between")
|
|
7675
7607
|
_$insert(_el$,_$createComponent(VersionSummary,{get api(){return adapter.api
|
|
7676
|
-
},navigatorVersion:"0.21.
|
|
7608
|
+
},navigatorVersion:"0.21.5",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7677
7609
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7678
7610
|
}}),null)
|
|
7679
7611
|
_$insert(_el$,_$createComponent(SettingsFooterButton,{get api(){return adapter.api
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-navigator",
|
|
4
|
-
"version": "0.21.
|
|
4
|
+
"version": "0.21.5",
|
|
5
5
|
"description": "Search, navigate, and manage OpenCode sessions from the TUI",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.4.2",
|