opencode-navigator 0.21.8 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +93 -19
- package/dist/{chunk-d1bws32s.js → chunk-dz8cfnfs.js} +4 -3
- package/dist/chunk-qmntexwm.js +0 -0
- package/dist/chunk-v6bz59xn.js +20 -0
- package/dist/icon-picker.js +175 -0
- package/dist/layout-preset-actions.js +4 -20
- package/dist/navigator-updates.js +12 -4
- package/dist/project-profile.js +12 -4
- package/dist/provider-limits.js +3 -1
- package/dist/quick-actions-settings.js +5 -13
- package/dist/rpc.js +1 -0
- package/dist/runtime-dependencies.json +10 -0
- package/dist/server.js +16 -54
- package/dist/settings-import.js +4 -3
- package/dist/sidebar-settings.js +828 -0
- package/dist/sidebar-shortcuts.js +261 -0
- package/dist/toolbar-settings.js +161 -0
- package/dist/tui.js +949 -990
- package/package.json +8 -7
- package/scripts/snapshot-runtime.mjs +32 -0
- package/scripts/update-local-snapshot.mjs +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## [0.22.0] - 2026-10-23
|
|
4
|
+
|
|
5
|
+
- Pin Quick Actions and Skills to a compact sidebar toolbar independently of bookmarks. Choose icons in a searchable picker, customize supported state icons, reorder buttons, and select a More menu or wrapping rows. Preserve Skill confirmations, unavailable reasons, keyboard navigation, and Text fallback; hide the toolbar entirely when empty.
|
|
6
|
+
- Use OpenCode 2's built-in Todo history for the sidebar, with native completed-write and revert semantics, existing filters/progress, and manual Refresh. Keep edits in ordinary chat, preserve previous Navigator tasks as a read-only archive, and retain the independent provider-quota server integration.
|
|
7
|
+
- Support OpenCode 2.1's plugin and rendering APIs while retaining the OpenCode 1.x adapter; restore custom dialogs and rounded selections on the newer native renderer.
|
|
8
|
+
- Replace the shortcut toast with an icon-led hint featuring highlighted keys, navigation/update groups, a distinct Escape action, and responsive Text/no-corner-font layouts. Keep prompt focus and share its action list with scrollable keyboard help.
|
|
9
|
+
- Update Subagent status immediately from OpenCode 2's execution lifecycle and keep unresolved external credentials separate from verified provider accounts.
|
|
10
|
+
- Keep OpenCode updates on the current major line and preserve pinned-source Navigator updates when a target release needs newer runtime dependencies.
|
|
4
11
|
|
|
5
12
|
## [0.21.8] - 2026-10-09
|
|
6
13
|
|
|
@@ -112,6 +119,7 @@
|
|
|
112
119
|
|
|
113
120
|
Earlier release notes are available on [GitHub Releases](https://github.com/St1ggy/opencode-navigator/releases).
|
|
114
121
|
|
|
122
|
+
[0.22.0]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.8...v0.22.0
|
|
115
123
|
[0.21.8]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.7...v0.21.8
|
|
116
124
|
[0.21.7]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.6...v0.21.7
|
|
117
125
|
[0.21.6]: https://github.com/St1ggy/opencode-navigator/compare/v0.21.5...v0.21.6
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ See the [changelog](CHANGELOG.md) for release-by-release changes.
|
|
|
12
12
|
|
|
13
13
|
- Theme-aware session title with the session creation date
|
|
14
14
|
- First-run setup guide with interactive section settings
|
|
15
|
-
- Collapsible Todo section with status filters, grouped tasks
|
|
15
|
+
- Collapsible Todo section with status filters, grouped tasks and progress; OpenCode 2 follows the host's native Todo history, while OpenCode 1.x retains supported priority indicators
|
|
16
16
|
- Active subagent list with live statuses and click-to-open navigation, including dev-team workers running in separate local processes
|
|
17
17
|
- Compact, searchable workspace skill list with user-wide favorites and groups, recent skills, source details, and click-to-confirm slash commands
|
|
18
18
|
- Configurable host quick actions, including OpenCode 1.x's auto-approve toggle and OpenCode 2.x's Permissions settings, with user-wide bookmarks and availability reasons
|
|
@@ -34,6 +34,7 @@ See the [changelog](CHANGELOG.md) for release-by-release changes.
|
|
|
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
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
|
+
- Scan an icon-led shortcut hint with highlighted keys, separate navigation/update groups, and a clear Escape action; narrow terminals and Text fallback use the same controls
|
|
37
38
|
- Optionally open new sessions directly in an empty chat with the sidebar, skipping Home on startup and from New session
|
|
38
39
|
- 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
40
|
|
|
@@ -41,10 +42,13 @@ Todo starts expanded. Subagents, skills, quick actions, LSP, and MCP start
|
|
|
41
42
|
collapsed. Use `Save current layout as default` in sidebar settings to reuse the
|
|
42
43
|
current visible/hidden, expanded/collapsed, and ordering states in new sessions.
|
|
43
44
|
|
|
44
|
-
Supports OpenCode 1.18.30 and newer, including OpenCode 2.x.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
Supports OpenCode 1.18.30 and newer, including OpenCode 2.x. The compatibility
|
|
46
|
+
matrix covers 1.18.30, 1.19.3, 2.0.21, and 2.1.0 with separate real-host checks.
|
|
47
|
+
The 2.1 integration adapts its plugin API and native renderer while retaining
|
|
48
|
+
the 1.x adapter. On OpenCode 2, Navigator reads the same native Todo history as
|
|
49
|
+
the host sidebar, including completed `todowrite` calls and the current revert
|
|
50
|
+
boundary. Viewing Todo needs no Navigator server plugin. OpenCode 2.1 exposes
|
|
51
|
+
content and four statuses, without priorities or direct Todo CRUD. LSP is hidden on 2.x while retaining Subagents,
|
|
48
52
|
Skills, Quick Actions, MCP, Search, settings, and presets. All interface icons use Nerd Font glyphs by
|
|
49
53
|
default (Codicons for controls, keyboard symbols for hints, language logos for LSP). Use a Nerd Fonts v3
|
|
50
54
|
terminal font, or select **Settings → Behavior → Icon style → Text fallback**.
|
|
@@ -190,9 +194,28 @@ OpenCode 2.x CLI plugins are global terminal settings; there is no project-local
|
|
|
190
194
|
plugin overrides are required. OpenCode validates `cli.json` strictly, so keep it
|
|
191
195
|
within the linked schema and restart OpenCode after changing it.
|
|
192
196
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
OpenCode 2.1's built-in Todo tool is opt-in. Enable it in the OpenCode server
|
|
198
|
+
configuration used by that host, then restart OpenCode:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"$schema": "https://opencode.ai/config.json",
|
|
203
|
+
"experimental": { "todo": true }
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Ask the agent in ordinary chat to create or change the list through `todowrite`.
|
|
208
|
+
Navigator displays the latest completed native call before the session's revert
|
|
209
|
+
boundary, reacts to host updates, and offers All / Active / Finished filters,
|
|
210
|
+
status groups, progress, Refresh, and retry after read failures. It does not start
|
|
211
|
+
model requests from Todo controls. Running or failed writes leave the last
|
|
212
|
+
completed list visible; a completed write with an empty array clears it.
|
|
213
|
+
Native tasks have `content` and one of `pending`, `in_progress`, `completed`, or
|
|
214
|
+
`cancelled`; priorities remain unavailable in OpenCode 2's native schema.
|
|
215
|
+
|
|
216
|
+
The optional **server** half of Navigator is used for provider-native quotas and
|
|
217
|
+
read-only access to the previous Navigator Todo archive. Add it to the server
|
|
218
|
+
configuration only when those integrations are needed:
|
|
196
219
|
|
|
197
220
|
```json
|
|
198
221
|
{
|
|
@@ -204,14 +227,25 @@ Add the same package to `~/.config/opencode/opencode.json` (or the project
|
|
|
204
227
|
For a local source installation, use the directory containing Navigator's
|
|
205
228
|
`server.js` in the `plugin` array. Keep the TUI package in `cli.json` as above;
|
|
206
229
|
the server configuration alone does not replace it. Restart OpenCode after
|
|
207
|
-
configuring both.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
230
|
+
configuring both. OpenCode owns native Todo persistence and tool instructions;
|
|
231
|
+
the separate `navigator_todo_write` tool and Navigator Todo-instructions control
|
|
232
|
+
are retired. OpenCode 1.x continues to show its supported host Todo source.
|
|
233
|
+
|
|
234
|
+
Previous Navigator tasks stay in their original plugin-scoped storage. Their
|
|
235
|
+
existing RPC is now a read-only archive; it never replaces native history or
|
|
236
|
+
deletes the saved list. To inspect a previous session explicitly:
|
|
237
|
+
|
|
238
|
+
```sh
|
|
239
|
+
opencode api --standalone rpc.call --param rpcID=opencode-navigator.todo --param method=list --data '{"input":{"sessionID":"ses_previous"},"location":{"directory":"/path/to/project"}}'
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
After reviewing the archive, an ordinary chat request can transfer its content
|
|
243
|
+
and statuses through the host's native tool. Archive reads do not change tasks
|
|
244
|
+
or add model instructions.
|
|
212
245
|
|
|
213
246
|
If you use both OpenCode 1.x and 2.x with the same global `opencode.json`, keep
|
|
214
|
-
that shared server config compatible with 1.x. Place the
|
|
247
|
+
that shared server config compatible with 1.x. Place the 2.x experimental Todo
|
|
248
|
+
setting and optional server-plugin entry
|
|
215
249
|
in a separate JSON file and set `OPENCODE_CONFIG` to its path **only when
|
|
216
250
|
launching OpenCode 2.x**. The TUI configuration in `cli.json` remains separate;
|
|
217
251
|
the OpenCode 1.x launch must not load Navigator's 2.x server plugin.
|
|
@@ -346,6 +380,36 @@ Search Everything. Usage never changes the order. Visibility remains independent
|
|
|
346
380
|
so any action, including a bookmarked one, can be hidden from the sidebar while it
|
|
347
381
|
remains searchable. Unavailable actions stay visible with a route- or host-specific reason.
|
|
348
382
|
|
|
383
|
+
### Pinned toolbar
|
|
384
|
+
|
|
385
|
+
Pin frequently used Quick Actions and Skills to an icon toolbar above the sidebar's
|
|
386
|
+
sections. In OpenCode 2.x it sits below the host-owned title. An empty toolbar takes
|
|
387
|
+
no space. Pins are independent of bookmarks, section visibility, filters, and item limits.
|
|
388
|
+
|
|
389
|
+
Use the pin control on an Action or Skill row, or open **Settings → Behavior →
|
|
390
|
+
Pinned toolbar…**. The command palette also offers **Manage pinned toolbar**.
|
|
391
|
+
Choose a base icon in the searchable picker, then select **Pin to toolbar**.
|
|
392
|
+
The manager lets you change icons, move buttons, or unpin them. Cancelling the
|
|
393
|
+
picker returns to the draft; cancelling the draft discards its changes.
|
|
394
|
+
|
|
395
|
+
Where the host exposes a state, the same button can use a different icon for each
|
|
396
|
+
state: auto-approve On/Off on OpenCode 1.x, and Idle/Compacting on OpenCode 2.x.
|
|
397
|
+
The 2.x permissions button opens host Settings and uses its base icon. Hover or
|
|
398
|
+
keyboard focus shows the button's name, observed state, or unavailable reason.
|
|
399
|
+
Skill buttons retain confirmation and trust settings; a missing or ambiguous
|
|
400
|
+
source stays pinned but cannot run.
|
|
401
|
+
|
|
402
|
+
**Behavior → Toolbar overflow** switches between one row with a **More** menu
|
|
403
|
+
(the default) and wrapping rows. Left/Right moves along a row; Up/Down moves
|
|
404
|
+
between rows. The setting follows Global/Worktree scope and portable defaults.
|
|
405
|
+
Pins, their order, icons, and exact Skill sources are private user-wide preferences
|
|
406
|
+
and are excluded from portable exports. Use **Reload settings from file** in other
|
|
407
|
+
running sessions after saving changes in another instance.
|
|
408
|
+
|
|
409
|
+

|
|
410
|
+
|
|
411
|
+

|
|
412
|
+
|
|
349
413
|
In OpenCode 1.x, Navigator saves changes to the auto-approve mode as a user-wide
|
|
350
414
|
default, including changes made through OpenCode's own command palette. Set the
|
|
351
415
|
default under **Navigator Settings → Behavior → Default auto-approve permissions**;
|
|
@@ -372,7 +436,7 @@ account usage. Separate model-specific buckets require explicit model associatio
|
|
|
372
436
|
Switching provider, model, session, or account invalidates stale reads and credit actions.
|
|
373
437
|
In OpenCode 2.x, Limits follows the prompt's selected model immediately, before a
|
|
374
438
|
message is sent, through the public reactive `ui.model.current()` API. OpenCode
|
|
375
|
-
1.x
|
|
439
|
+
1.x, rechecked at 1.19.3, exposes only the saved session model: a newly selected prompt
|
|
376
440
|
model becomes visible to Navigator when the host saves it, normally on submission.
|
|
377
441
|
An immediate pre-submission switch in 1.x needs a new public host accessor or event.
|
|
378
442
|
CodexBar is useful for discovering providers, but its cookie, credential-file,
|
|
@@ -519,6 +583,7 @@ Navigator plugin tuple:
|
|
|
519
583
|
"cornerFont": true,
|
|
520
584
|
"lspIconStyle": "nerd",
|
|
521
585
|
"rowDensity": "compact",
|
|
586
|
+
"toolbarOverflow": "menu",
|
|
522
587
|
"sectionItemLimits": { "todo": 0, "skills": 5, "mcp": 5 },
|
|
523
588
|
"quickActionOrder": ["session.rename", "session.copy", "session.fork"],
|
|
524
589
|
"quickActionVisibility": { "session.export": false }
|
|
@@ -556,7 +621,7 @@ density, item limits, and Navigator's safe Quick Action allowlist. Unknown value
|
|
|
556
621
|
sections, actions, and MCP states are discarded. The previous snake_case tuple
|
|
557
622
|
options (`toggle_key`, `focus_key`, `search_key`, `persist_mcp`, `limits_refresh_minutes`, `start_in_chat`, `show_session_title`,
|
|
558
623
|
`show_session_date`, `corner_font`, `icon_style`,
|
|
559
|
-
`lsp_icon_style`, `row_density`, `section_item_limits`, `quick_action_order`,
|
|
624
|
+
`lsp_icon_style`, `row_density`, `toolbar_overflow`, `section_item_limits`, `quick_action_order`,
|
|
560
625
|
`quick_action_visibility`, `sections`, and `section_order`) remain compatible;
|
|
561
626
|
canonical nested fields win when both forms are present.
|
|
562
627
|
|
|
@@ -667,14 +732,23 @@ Press `Ctrl+Shift+B` to enter Navigator shortcuts, then choose an action:
|
|
|
667
732
|
| `u` | Check for a Navigator update, then open its confirmation if available |
|
|
668
733
|
| `Escape` | Cancel shortcut mode |
|
|
669
734
|
|
|
670
|
-
The mode ends after an action or five seconds of inactivity. Its
|
|
671
|
-
|
|
735
|
+
The mode ends after an action or five seconds of inactivity. Its compact,
|
|
736
|
+
non-modal hint groups section navigation separately from update actions, uses
|
|
737
|
+
icons and highlighted key tokens, and keeps Escape visible. It adapts to narrow
|
|
738
|
+
or short terminals, light/dark themes, Text fallback, and the no-corner-font
|
|
739
|
+
setting without taking focus from the prompt. Keyboard help uses the same
|
|
740
|
+
action inventory and supports arrow-key and page-key scrolling. Only actions
|
|
741
|
+
supported by the current host are listed; LSP is omitted on OpenCode 2.x. Change the
|
|
672
742
|
entry shortcut under **Settings → Behavior**. The command palette also offers
|
|
673
743
|
**Check Navigator updates** and **Update Navigator**.
|
|
674
744
|
|
|
675
745
|
Manual checks report when Navigator is current or the update source is unavailable.
|
|
676
746
|
Updates require confirmation, preserve the existing installation method and scope,
|
|
677
|
-
and show a restart reminder after completion.
|
|
747
|
+
and show a restart reminder after completion. OpenCode updates stay on the running
|
|
748
|
+
major line; moving from 1.x to 2.x remains a separate installation decision.
|
|
749
|
+
Confirmed pinned-source Navigator updates install the target release's runtime
|
|
750
|
+
dependencies in a new snapshot before switching its wrapper. The previous
|
|
751
|
+
snapshot and private settings remain intact. Background check failures stay quiet.
|
|
678
752
|
|
|
679
753
|
### Search Everything
|
|
680
754
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
var PLUGIN_ID="opencode-navigator"
|
|
2
2
|
var TOGGLE_COMMAND=`${PLUGIN_ID}.toggle`
|
|
3
3
|
var FOCUS_COMMAND=`${PLUGIN_ID}.focus`
|
|
4
|
-
var SEARCH_COMMAND=`${PLUGIN_ID}.search
|
|
5
|
-
var
|
|
4
|
+
var SEARCH_COMMAND=`${PLUGIN_ID}.search`
|
|
5
|
+
var DEFAULT_SEARCH_KEY="ctrl+shift+k";
|
|
6
|
+
var SIDEBAR_SECTIONS=["limits","todo","subagents","skills","quick_actions","lsp","mcp"]
|
|
6
7
|
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
8
|
var MAX_LIMITS_REFRESH_MINUTES=Math.floor(2147483647 / 60000)
|
|
8
|
-
export{
|
|
9
|
+
export{SIDEBAR_SECTIONS,SECTION_DEFINITIONS,PLUGIN_ID,DEFAULT_SEARCH_KEY}
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function mcpToggleAction(status){if(status==="pending")
|
|
2
|
+
return
|
|
3
|
+
return status==="connected"?"disconnect":"connect"
|
|
4
|
+
}
|
|
5
|
+
function mcpPresetPreview(items,states){const byName=new Map(items.map((item)=>[item.name,item]))
|
|
6
|
+
const names=[...new Set([...Object.keys(states),...byName.keys()])].sort((a,b)=>a.localeCompare(b))
|
|
7
|
+
const rows=names.map((name)=>{const item=byName.get(name)
|
|
8
|
+
const desired=Object.hasOwn(states,name)?states[name]:undefined
|
|
9
|
+
const action=item&&mcpToggleAction(item.status)
|
|
10
|
+
let change="unchanged"
|
|
11
|
+
if(desired&&!item)
|
|
12
|
+
change="missing"
|
|
13
|
+
else if(desired&&!action)
|
|
14
|
+
change="unavailable"
|
|
15
|
+
else if(desired==="enabled"&&action==="connect"||desired==="disabled"&&action==="disconnect"){change=action
|
|
16
|
+
}
|
|
17
|
+
return{name,status:item?.status,desired,change}})
|
|
18
|
+
const changes=rows.flatMap((row)=>row.change==="connect"||row.change==="disconnect"?[{name:row.name,action:row.change}]:[])
|
|
19
|
+
return{rows,changes}}
|
|
20
|
+
export{mcpPresetPreview}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {use as _$use} from "@opentui/solid"
|
|
2
|
+
import {effect as _$effect3} from "@opentui/solid"
|
|
3
|
+
import {createTextNode as _$createTextNode} from "@opentui/solid"
|
|
4
|
+
import {insertNode as _$insertNode} from "@opentui/solid"
|
|
5
|
+
import {insert as _$insert3} from "@opentui/solid"
|
|
6
|
+
import {memo as _$memo3} from "@opentui/solid"
|
|
7
|
+
import {setProp as _$setProp3} from "@opentui/solid"
|
|
8
|
+
import {createElement as _$createElement3} from "@opentui/solid"
|
|
9
|
+
import {createComponent as _$createComponent3} from "@opentui/solid"
|
|
10
|
+
import {useTerminalDimensions} from "@opentui/solid"
|
|
11
|
+
import {For,createEffect,createMemo,createSignal as createSignal2,onCleanup} from "solid-js"
|
|
12
|
+
import {DialogHeader,DialogSurface,SelectionBox as SelectionBox3,terminalIcon as terminalIcon2,terminalIconIDs,terminalIconLabel as terminalIconLabel2,useDialogState,useDialogs,useIcons as useIcons3} from "./tui.js"
|
|
13
|
+
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
14
|
+
import {effect as _$effect} from "@opentui/solid"
|
|
15
|
+
import {insert as _$insert} from "@opentui/solid"
|
|
16
|
+
import {setProp as _$setProp} from "@opentui/solid"
|
|
17
|
+
import {createElement as _$createElement} from "@opentui/solid"
|
|
18
|
+
import {memo as _$memo} from "@opentui/solid"
|
|
19
|
+
import {SelectionBox,terminalIcon,terminalIconLabel,useIcons} from "./tui.js"
|
|
20
|
+
function IconPickerItem(props){const icons=useIcons()
|
|
21
|
+
const theme=()=>props.api.theme.current
|
|
22
|
+
return _$createComponent(SelectionBox,{get id(){return `icon-picker.${props.id}`
|
|
23
|
+
},width:9,height:2,paddingLeft:1,paddingRight:1,get backgroundColor(){return _$memo(()=>!!props.active)()?theme().backgroundElement:undefined
|
|
24
|
+
},get onMouseOver(){return props.onHover
|
|
25
|
+
},onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
|
|
26
|
+
props.onSelect()
|
|
27
|
+
},get children(){return [(()=>{var _el$=_$createElement("text")
|
|
28
|
+
_$setProp(_el$,"truncate",true)
|
|
29
|
+
_$setProp(_el$,"wrapMode","none")
|
|
30
|
+
_$insert(_el$,()=>terminalIcon(props.id,icons.style()),null)
|
|
31
|
+
_$insert(_el$,()=>props.selected?" *":"",null)
|
|
32
|
+
_$effect((_$p)=>_$setProp(_el$,"fg",props.active||props.selected?theme().accent:theme().text,_$p))
|
|
33
|
+
return _el$
|
|
34
|
+
})(),(()=>{var _el$2=_$createElement("text")
|
|
35
|
+
_$setProp(_el$2,"truncate",true)
|
|
36
|
+
_$setProp(_el$2,"wrapMode","none")
|
|
37
|
+
_$insert(_el$2,()=>terminalIconLabel(props.id))
|
|
38
|
+
_$effect((_$p)=>_$setProp(_el$2,"fg",theme().textMuted,_$p))
|
|
39
|
+
return _el$2
|
|
40
|
+
})()]
|
|
41
|
+
}})
|
|
42
|
+
}
|
|
43
|
+
import {createComponent as _$createComponent2} from "@opentui/solid"
|
|
44
|
+
import {setProp as _$setProp2} from "@opentui/solid"
|
|
45
|
+
import {effect as _$effect2} from "@opentui/solid"
|
|
46
|
+
import {insert as _$insert2} from "@opentui/solid"
|
|
47
|
+
import {createElement as _$createElement2} from "@opentui/solid"
|
|
48
|
+
import {memo as _$memo2} from "@opentui/solid"
|
|
49
|
+
import {createSignal} from "solid-js"
|
|
50
|
+
import {SelectionBox as SelectionBox2,useIcons as useIcons2} from "./tui.js"
|
|
51
|
+
function IconPickerSearch(props){const icons=useIcons2()
|
|
52
|
+
const [focused,setFocused]=createSignal(true)
|
|
53
|
+
const theme=()=>props.api.theme.current
|
|
54
|
+
const fg=()=>focused()?theme().selectedListItemText:theme().text
|
|
55
|
+
return _$createComponent2(SelectionBox2,{paddingLeft:1,paddingRight:1,flexDirection:"row",gap:1,get backgroundColor(){return _$memo2(()=>!!focused())()?theme().primary:theme().backgroundElement
|
|
56
|
+
},get children(){return [(()=>{var _el$=_$createElement2("text")
|
|
57
|
+
_$insert2(_el$,()=>icons.icon("search"))
|
|
58
|
+
_$effect2((_$p)=>_$setProp2(_el$,"fg",fg(),_$p))
|
|
59
|
+
return _el$
|
|
60
|
+
})(),(()=>{var _el$2=_$createElement2("input")
|
|
61
|
+
_$setProp2(_el$2,"id","icon-picker.search")
|
|
62
|
+
_$setProp2(_el$2,"flexGrow",1)
|
|
63
|
+
_$setProp2(_el$2,"focused",true)
|
|
64
|
+
_$setProp2(_el$2,"placeholder","Search icons...")
|
|
65
|
+
_$setProp2(_el$2,"on:focused",()=>setFocused(true))
|
|
66
|
+
_$setProp2(_el$2,"on:blurred",()=>setFocused(false))
|
|
67
|
+
_$setProp2(_el$2,"backgroundColor","transparent")
|
|
68
|
+
_$setProp2(_el$2,"focusedBackgroundColor","transparent")
|
|
69
|
+
_$effect2((_p$)=>{var{query:_v$,onInput:_v$2}=props,_v$3=fg(),_v$4=fg(),_v$5=fg(),_v$6=fg()
|
|
70
|
+
_v$!==_p$.e&&(_p$.e=_$setProp2(_el$2,"value",_v$,_p$.e))
|
|
71
|
+
_v$2!==_p$.t&&(_p$.t=_$setProp2(_el$2,"onInput",_v$2,_p$.t))
|
|
72
|
+
_v$3!==_p$.a&&(_p$.a=_$setProp2(_el$2,"textColor",_v$3,_p$.a))
|
|
73
|
+
_v$4!==_p$.o&&(_p$.o=_$setProp2(_el$2,"focusedTextColor",_v$4,_p$.o))
|
|
74
|
+
_v$5!==_p$.i&&(_p$.i=_$setProp2(_el$2,"placeholderColor",_v$5,_p$.i))
|
|
75
|
+
_v$6!==_p$.n&&(_p$.n=_$setProp2(_el$2,"cursorColor",_v$6,_p$.n))
|
|
76
|
+
return _p$
|
|
77
|
+
},{e:undefined,t:undefined,a:undefined,o:undefined,i:undefined,n:undefined
|
|
78
|
+
})
|
|
79
|
+
return _el$2
|
|
80
|
+
})()]
|
|
81
|
+
}})
|
|
82
|
+
}
|
|
83
|
+
function IconPicker(props){const icons=useIcons3()
|
|
84
|
+
const dialogs=useDialogs(props.api)
|
|
85
|
+
const dimensions=useTerminalDimensions()
|
|
86
|
+
const [query,setQuery]=useDialogState("icon-query","")
|
|
87
|
+
const [active,setActive]=useDialogState("icon-active",props.value)
|
|
88
|
+
const keywords={bolt:"action lightning",gear:"settings configuration",shield:"permissions security",copy:"clipboard transcript",check:"done success",refresh:"compact reload retry",book:"skill documentation",pin:"favorite bookmark"
|
|
89
|
+
}
|
|
90
|
+
const items=createMemo(()=>terminalIconIDs.filter((id)=>`${terminalIconLabel2(id)} ${keywords[id] ?? ""}`.includes(query().toLowerCase().trim())))
|
|
91
|
+
const [width,setWidth]=createSignal2(Math.max(10,dimensions().width-12))
|
|
92
|
+
const columns=createMemo(()=>Math.max(1,Math.min(6,Math.floor(width() / 10))))
|
|
93
|
+
const rows=createMemo(()=>Array.from({length:Math.ceil(items().length / columns())
|
|
94
|
+
},(_,index)=>items().slice(index*columns(),(index + 1)*columns())))
|
|
95
|
+
let body
|
|
96
|
+
createEffect(()=>{if(!items().includes(active()))
|
|
97
|
+
setActive(items()[0]??"")
|
|
98
|
+
})
|
|
99
|
+
function move(offset,horizontal=false){const index=items().indexOf(active())
|
|
100
|
+
const start=horizontal?Math.floor(index / columns())*columns():0
|
|
101
|
+
const end=horizontal?Math.min(items().length-1,start + columns()-1):items().length-1
|
|
102
|
+
const next=items()[Math.max(start,Math.min(end,index + offset))]
|
|
103
|
+
if(next){setActive(next)
|
|
104
|
+
body?.scrollChildIntoView(`icon-picker.${next}`)
|
|
105
|
+
}}
|
|
106
|
+
function select(id=active()){if(items().includes(id))
|
|
107
|
+
props.onSelect(id)
|
|
108
|
+
}
|
|
109
|
+
const prefix="opencode-navigator.icon-picker"
|
|
110
|
+
const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,commands:[{name:`${prefix}.left`,run:()=>move(-1,true)
|
|
111
|
+
},{name:`${prefix}.right`,run:()=>move(1,true)
|
|
112
|
+
},{name:`${prefix}.up`,run:()=>move(-columns())
|
|
113
|
+
},{name:`${prefix}.down`,run:()=>move(columns())
|
|
114
|
+
},{name:`${prefix}.select`,run:()=>select()
|
|
115
|
+
}],bindings:["left","right","up","down","return"].map((key)=>({key,cmd:`${prefix}.${key === "return" ? "select" : key}`
|
|
116
|
+
}))
|
|
117
|
+
})
|
|
118
|
+
onCleanup(unregister)
|
|
119
|
+
const theme=()=>props.api.theme.current
|
|
120
|
+
return _$createComponent3(DialogSurface,{get api(){return props.api
|
|
121
|
+
},id:"opencode-navigator.icon-picker",get children(){return [_$createComponent3(DialogHeader,{get api(){return props.api
|
|
122
|
+
},title:"Choose an icon",get onBack(){return dialogs.back
|
|
123
|
+
}}),_$createComponent3(IconPickerSearch,{get api(){return props.api
|
|
124
|
+
},get query(){return query()
|
|
125
|
+
},onInput:setQuery
|
|
126
|
+
}),_$createComponent3(SelectionBox3,{paddingLeft:1,paddingRight:1,get backgroundColor(){return theme().backgroundElement
|
|
127
|
+
},get children(){var _el$=_$createElement3("text"),_el$2=_$createTextNode(` `)
|
|
128
|
+
_$insertNode(_el$,_el$2)
|
|
129
|
+
_$setProp3(_el$,"wrapMode","none")
|
|
130
|
+
_$setProp3(_el$,"truncate",true)
|
|
131
|
+
_$insert3(_el$,()=>terminalIcon2(active(),icons.style()),_el$2)
|
|
132
|
+
_$insert3(_el$,()=>terminalIconLabel2(active())||"No matching icons",null)
|
|
133
|
+
_$insert3(_el$,()=>active()===props.value?" \xB7 selected":"",null)
|
|
134
|
+
_$effect3((_$p)=>_$setProp3(_el$,"fg",theme().accent,_$p))
|
|
135
|
+
return _el$
|
|
136
|
+
}}),(()=>{var _el$3=_$createElement3("scrollbox")
|
|
137
|
+
_$use((node)=>{body=node
|
|
138
|
+
},_el$3)
|
|
139
|
+
_$setProp3(_el$3,"onSizeChange",function(){setWidth(this.width)
|
|
140
|
+
})
|
|
141
|
+
_$setProp3(_el$3,"scrollX",false)
|
|
142
|
+
_$insert3(_el$3,_$createComponent3(For,{get each(){return rows()
|
|
143
|
+
},children:(row)=>(()=>{var _el$0=_$createElement3("box")
|
|
144
|
+
_$setProp3(_el$0,"flexDirection","row")
|
|
145
|
+
_$setProp3(_el$0,"gap",1)
|
|
146
|
+
_$insert3(_el$0,_$createComponent3(For,{each:row,children:(id)=>_$createComponent3(IconPickerItem,{get api(){return props.api
|
|
147
|
+
},id,get active(){return id===active()
|
|
148
|
+
},get selected(){return id===props.value
|
|
149
|
+
},onHover:()=>setActive(id),onSelect:()=>select(id)
|
|
150
|
+
})
|
|
151
|
+
}))
|
|
152
|
+
return _el$0
|
|
153
|
+
})()
|
|
154
|
+
}))
|
|
155
|
+
_$effect3((_$p)=>_$setProp3(_el$3,"height",Math.max(2,Math.min(10,Math.floor(dimensions().height*0.6)-9)),_$p))
|
|
156
|
+
return _el$3
|
|
157
|
+
})(),(()=>{var _el$4=_$createElement3("text"),_el$5=_$createTextNode(` rows \xB7 `),_el$6=_$createTextNode(` icons \xB7 `),_el$7=_$createTextNode(` choose \xB7 `),_el$8=_$createTextNode(` cancel`)
|
|
158
|
+
_$insertNode(_el$4,_el$5)
|
|
159
|
+
_$insertNode(_el$4,_el$6)
|
|
160
|
+
_$insertNode(_el$4,_el$7)
|
|
161
|
+
_$insertNode(_el$4,_el$8)
|
|
162
|
+
_$setProp3(_el$4,"height",1)
|
|
163
|
+
_$setProp3(_el$4,"truncate",true)
|
|
164
|
+
_$setProp3(_el$4,"wrapMode","none")
|
|
165
|
+
_$insert3(_el$4,()=>icons.key("up/down"),_el$5)
|
|
166
|
+
_$insert3(_el$4,()=>icons.key("left/right"),_el$6)
|
|
167
|
+
_$insert3(_el$4,()=>icons.key("enter"),_el$7)
|
|
168
|
+
_$insert3(_el$4,()=>icons.key("esc"),_el$8)
|
|
169
|
+
_$effect3((_$p)=>_$setProp3(_el$4,"fg",theme().textMuted,_$p))
|
|
170
|
+
return _el$4
|
|
171
|
+
})()]
|
|
172
|
+
}})
|
|
173
|
+
}
|
|
174
|
+
export{IconPicker
|
|
175
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import {SECTION_DEFINITIONS,PLUGIN_ID
|
|
2
|
-
} from "./chunk-
|
|
2
|
+
} from "./chunk-dz8cfnfs.js"
|
|
3
|
+
import"./chunk-qmntexwm.js"
|
|
4
|
+
import {mcpPresetPreview
|
|
5
|
+
} from "./chunk-v6bz59xn.js";
|
|
3
6
|
import {createComponent as _$createComponent7} from "@opentui/solid"
|
|
4
7
|
import {setProp as _$setProp5} from "@opentui/solid"
|
|
5
8
|
import {effect as _$effect5} from "@opentui/solid"
|
|
@@ -13,25 +16,6 @@ import {memo as _$memo4} from "@opentui/solid"
|
|
|
13
16
|
import {For as For3,createMemo as createMemo3,onMount as onMount2} from "solid-js"
|
|
14
17
|
import {useDialogs as useDialogs3,useIcons as useIcons6} from "./tui.js"
|
|
15
18
|
import {createMemo} from "solid-js"
|
|
16
|
-
function mcpToggleAction(status){if(status==="pending")
|
|
17
|
-
return
|
|
18
|
-
return status==="connected"?"disconnect":"connect"
|
|
19
|
-
}
|
|
20
|
-
function mcpPresetPreview(items,states){const byName=new Map(items.map((item)=>[item.name,item]))
|
|
21
|
-
const names=[...new Set([...Object.keys(states),...byName.keys()])].sort((a,b)=>a.localeCompare(b))
|
|
22
|
-
const rows=names.map((name)=>{const item=byName.get(name)
|
|
23
|
-
const desired=Object.hasOwn(states,name)?states[name]:undefined
|
|
24
|
-
const action=item&&mcpToggleAction(item.status)
|
|
25
|
-
let change="unchanged"
|
|
26
|
-
if(desired&&!item)
|
|
27
|
-
change="missing"
|
|
28
|
-
else if(desired&&!action)
|
|
29
|
-
change="unavailable"
|
|
30
|
-
else if(desired==="enabled"&&action==="connect"||desired==="disabled"&&action==="disconnect"){change=action
|
|
31
|
-
}
|
|
32
|
-
return{name,status:item?.status,desired,change}})
|
|
33
|
-
const changes=rows.flatMap((row)=>row.change==="connect"||row.change==="disconnect"?[{name:row.name,action:row.change}]:[])
|
|
34
|
-
return{rows,changes}}
|
|
35
19
|
function createLayoutPresetPreview(preferences,name){const scope=preferences.selectedScopeKey()
|
|
36
20
|
const valid=()=>preferences.selectedScopeKey()===scope
|
|
37
21
|
const preset=createMemo(()=>preferences.layoutPresets()[name])
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {PLUGIN_ID
|
|
2
|
-
} from "./chunk-
|
|
2
|
+
} from "./chunk-dz8cfnfs.js";
|
|
3
3
|
import {createSignal} from "solid-js"
|
|
4
4
|
function versionParts(value){const match=/^v?(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/.exec(value)
|
|
5
5
|
return match?{numbers:match.slice(1,4).map(Number),prerelease:match[4]||undefined}:undefined
|
|
@@ -13,6 +13,10 @@ return next.numbers[index]>installed.numbers[index]
|
|
|
13
13
|
}
|
|
14
14
|
return installed.prerelease!==undefined&&next.prerelease===undefined
|
|
15
15
|
}
|
|
16
|
+
function isSameMajorVersion(left,right){const first=versionParts(left)
|
|
17
|
+
const second=versionParts(right)
|
|
18
|
+
return Boolean(first&&second&&first.numbers[0]===second.numbers[0])
|
|
19
|
+
}
|
|
16
20
|
var NAVIGATOR_PACKAGE_URL="https://registry.npmjs.org/opencode-navigator/latest"
|
|
17
21
|
var REQUEST_TIMEOUT_MS=5000
|
|
18
22
|
async function readNavigatorVersion(request,signal){const response=await request(NAVIGATOR_PACKAGE_URL,{headers:{accept:"application/json"},signal})
|
|
@@ -29,7 +33,7 @@ let controller
|
|
|
29
33
|
let pending
|
|
30
34
|
let disposed=false
|
|
31
35
|
const unsubscribe=api.event.on("installation.update-available",(event)=>{const version=event.properties.version
|
|
32
|
-
setOpenCodeUpdate(isNewerVersion(version,api.app.version)?version:undefined)
|
|
36
|
+
setOpenCodeUpdate(isSameMajorVersion(version,api.app.version)&&isNewerVersion(version,api.app.version)?version:undefined)
|
|
33
37
|
})
|
|
34
38
|
api.lifecycle.onDispose(()=>{disposed=true
|
|
35
39
|
controller?.abort()
|
|
@@ -170,6 +174,10 @@ return{openCode:(version)=>open("openCode",version),navigator:(version)=>open("n
|
|
|
170
174
|
import {homedir} from "os"
|
|
171
175
|
import {basename,dirname,isAbsolute,join} from "path"
|
|
172
176
|
import {fileURLToPath} from "url"
|
|
177
|
+
async function upgradeHost(current,target,execute){if(!isSameMajorVersion(current,target))
|
|
178
|
+
throw new Error("OpenCode updates must stay on the current major version")
|
|
179
|
+
await execute([process.execPath,"upgrade",target])
|
|
180
|
+
}
|
|
173
181
|
var run=async (command)=>{const child=Bun.spawn([...command],{stdout:"ignore",stderr:"pipe"})
|
|
174
182
|
const error=new Response(child.stderr).text()
|
|
175
183
|
const exitCode=await child.exited
|
|
@@ -207,7 +215,7 @@ if(configHasPlugin(await read(path),spec))
|
|
|
207
215
|
return false
|
|
208
216
|
return configHasPlugin(await read(global),spec)
|
|
209
217
|
}
|
|
210
|
-
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>
|
|
218
|
+
function createOpenCodeV1VersionUpdater(api,meta,execute=run,read=readConfig){return{openCode:(target)=>upgradeHost(api.app.version,target,execute),async navigator(target){if(meta.source==="file"){const wrapper=meta.spec.startsWith("file://")?fileURLToPath(meta.spec):meta.spec
|
|
211
219
|
return pinnedUpdate(wrapper,target,execute)
|
|
212
220
|
}
|
|
213
221
|
if(meta.source!=="npm")
|
|
@@ -217,7 +225,7 @@ const result=await api.plugins.install(`opencode-navigator@${target}`,{global:aw
|
|
|
217
225
|
if(!result.ok)
|
|
218
226
|
throw new Error(result.message)
|
|
219
227
|
}}}
|
|
220
|
-
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>
|
|
228
|
+
function createOpenCodeV2VersionUpdater(context,execute=run){return{openCode:(target)=>upgradeHost(context.app.version,target,execute),async navigator(target){const response=await context.client.plugin.list(context.location?{location:context.location}:{})
|
|
221
229
|
const item=response.data.find((plugin)=>plugin.id===PLUGIN_ID)
|
|
222
230
|
if(!item)
|
|
223
231
|
throw new Error("Navigator is not in the active plugin list")
|
package/dist/project-profile.js
CHANGED
|
@@ -65,7 +65,8 @@ function parsePluginSettings(value){const input=record(value)
|
|
|
65
65
|
if(!input)
|
|
66
66
|
return{}
|
|
67
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},...
|
|
68
|
+
},...typeof input.startInChat==="boolean"&&{startInChat:input.startInChat},...(input.toolbarOverflow==="menu"||input.toolbarOverflow==="wrap")&&{toolbarOverflow:input.toolbarOverflow
|
|
69
|
+
},...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
|
|
69
70
|
},...Object.keys(parseSectionItemLimits(input.sectionItemLimits)).length>0&&{sectionItemLimits:parseSectionItemLimits(input.sectionItemLimits)
|
|
70
71
|
},...parseQuickActionOrder(input.quickActionOrder)&&{quickActionOrder:parseQuickActionOrder(input.quickActionOrder)
|
|
71
72
|
},...Object.keys(parseQuickActionVisibility(input.quickActionVisibility)).length>0&&{quickActionVisibility:parseQuickActionVisibility(input.quickActionVisibility)
|
|
@@ -189,12 +190,19 @@ throw new Error(`Expected format ${PORTABLE_SETTINGS_FORMAT}`)
|
|
|
189
190
|
if(input.version!==1)
|
|
190
191
|
throw new Error(`Unsupported settings version ${String(input.version)}`)
|
|
191
192
|
const unsupported=[]
|
|
192
|
-
unknownKeys(input,["format","version","layout","mcp"],"",unsupported)
|
|
193
|
+
unknownKeys(input,["format","version","layout","mcp","behavior"],"",unsupported)
|
|
193
194
|
const hasLayout=Object.hasOwn(input,"layout")
|
|
194
195
|
const hasMcp=Object.hasOwn(input,"mcp")
|
|
195
|
-
|
|
196
|
+
const behavior={}
|
|
197
|
+
if(input.behavior!==undefined){const raw=object(input.behavior,"/behavior")
|
|
198
|
+
unknownKeys(raw,["toolbarOverflow"],"/behavior",unsupported)
|
|
199
|
+
if(raw.toolbarOverflow!==undefined){if(raw.toolbarOverflow!=="menu"&&raw.toolbarOverflow!=="wrap")
|
|
200
|
+
throw new Error("/behavior/toolbarOverflow must be menu or wrap")
|
|
201
|
+
behavior.toolbarOverflow=raw.toolbarOverflow
|
|
202
|
+
}}
|
|
203
|
+
if(!hasLayout&&!hasMcp&&!behavior.toolbarOverflow)
|
|
196
204
|
throw new Error("Settings JSON contains no supported settings")
|
|
197
|
-
const settings={format:PORTABLE_SETTINGS_FORMAT,version:1,...hasLayout&&{layout:parseLayout(input.layout,unsupported)},...hasMcp&&{mcp:parseMcp(input.mcp)}}
|
|
205
|
+
const settings={format:PORTABLE_SETTINGS_FORMAT,version:1,...hasLayout&&{layout:parseLayout(input.layout,unsupported)},...hasMcp&&{mcp:parseMcp(input.mcp)},...behavior.toolbarOverflow&&{behavior}}
|
|
198
206
|
unsupported.sort()
|
|
199
207
|
return{settings,unsupported}}
|
|
200
208
|
var FILENAME=join(".opencode","navigator.json")
|
package/dist/provider-limits.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {PLUGIN_ID
|
|
2
|
-
} from "./chunk-
|
|
2
|
+
} from "./chunk-dz8cfnfs.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
|
|
@@ -1029,6 +1029,8 @@ if(active.length!==1)
|
|
|
1029
1029
|
return{status:"unavailable"}
|
|
1030
1030
|
const credential=active[0]
|
|
1031
1031
|
const id=`credential:${credential.id}`
|
|
1032
|
+
if(credential.value.type==="external")
|
|
1033
|
+
return{status:"unsupported",id}
|
|
1032
1034
|
const providerID=provider.canonical??provider.id
|
|
1033
1035
|
if(credential.value.type==="key")
|
|
1034
1036
|
return{status:"ready",id,method:"api",providerID}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
} from "./chunk-
|
|
1
|
+
import {PLUGIN_ID
|
|
2
|
+
} from "./chunk-dz8cfnfs.js";
|
|
3
3
|
import {memo as _$memo} from "@opentui/solid"
|
|
4
4
|
import {createComponent as _$createComponent} from "@opentui/solid"
|
|
5
5
|
import {use as _$use} from "@opentui/solid"
|
|
@@ -11,16 +11,8 @@ import {setProp as _$setProp} from "@opentui/solid"
|
|
|
11
11
|
import {createElement as _$createElement} from "@opentui/solid"
|
|
12
12
|
import {TextAttributes} from "@opentui/core"
|
|
13
13
|
import {useTerminalDimensions} from "@opentui/solid"
|
|
14
|
-
import {For,createEffect,createMemo,onCleanup
|
|
15
|
-
import {
|
|
16
|
-
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"]]
|
|
17
|
-
var QUICK_ACTIONS=QUICK_ACTION_IDS.map((command,index)=>({command,icon:QUICK_ACTION_METADATA[index][0],label:QUICK_ACTION_METADATA[index][1]
|
|
18
|
-
}))
|
|
19
|
-
function quickActionLabel(api,action){if(action.command!=="permission.mode")
|
|
20
|
-
return action.label
|
|
21
|
-
const command=api.keymap.getCommands?.({visibility:"registered"}).find((candidate)=>candidate.name===action.command)
|
|
22
|
-
return typeof command?.title==="string"?command.title:action.label
|
|
23
|
-
}
|
|
14
|
+
import {For,createEffect,createMemo,onCleanup} from "solid-js"
|
|
15
|
+
import {QUICK_ACTIONS,quickActionLabel} from "./tui.js"
|
|
24
16
|
import {DialogSurface,SelectionBox,useDialogScroll,useDialogState,useDialogs,useIcons} from "./tui.js"
|
|
25
17
|
function QuickActionsDialog(props){const order=props.preferences.selectedQuickActionOrder
|
|
26
18
|
const dialogs=useDialogs(props.api)
|
|
@@ -59,7 +51,7 @@ const unregister=props.api.keymap.registerLayer({mode:"modal",priority:1000,comm
|
|
|
59
51
|
},{key:"escape",cmd:`${prefix}.back`
|
|
60
52
|
}]
|
|
61
53
|
})
|
|
62
|
-
|
|
54
|
+
onCleanup(unregister)
|
|
63
55
|
return _$createComponent(DialogSurface,{get api(){return props.api
|
|
64
56
|
},id:prefix,lift:true,get children(){return [(()=>{var _el$=_$createElement("box"),_el$2=_$createElement("text"),_el$3=_$createTextNode(` Quick actions`),_el$4=_$createElement("text"),_el$5=_$createTextNode(` Back (`),_el$6=_$createTextNode(`)`)
|
|
65
57
|
_$insertNode(_el$,_el$2)
|
package/dist/rpc.js
CHANGED
|
@@ -11,6 +11,7 @@ var NavigatorTodoRpc={id:"opencode-navigator.todo",methods:{list:{input:{type:"o
|
|
|
11
11
|
},output
|
|
12
12
|
}},events:{updated:{schema:{type:"object",properties:{sessionID,todos,guidance:{type:"boolean"}},required:["sessionID","todos","guidance"],additionalProperties:false
|
|
13
13
|
}}}};
|
|
14
|
+
var LegacyTodoArchiveRpc={id:NavigatorTodoRpc.id,methods:{list:NavigatorTodoRpc.methods.list},events:{}};
|
|
14
15
|
var text={type:"string",minLength:1,maxLength:512}
|
|
15
16
|
var model={type:"object",properties:{providerID:text,modelID:text,sessionID:text,connectionID:text,variant:text,force:{type:"boolean"}},required:["providerID","modelID","sessionID"],additionalProperties:false
|
|
16
17
|
}
|