opencode-navigator 0.25.0 → 0.26.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 +5 -0
- package/HOST_API.md +21 -12
- package/LINT_COVERAGE.md +27 -29
- package/README.md +11 -7
- package/dist/provider-limits.js +6 -5
- package/dist/runtime-dependencies.json +3 -3
- package/dist/sidebar-settings.js +5 -3
- package/dist/tui.js +68 -35
- package/package.json +8 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.26.0] - 2026-11-06
|
|
4
|
+
|
|
5
|
+
- Prevent background retries from accumulating cancellation listeners and preferences loading from waiting indefinitely on recovery markers.
|
|
6
|
+
- Show exact active Subagent durations from OpenCode 2's native execution start time, preserving the observation fallback when timing is unavailable. Keep interrupted executions marked as cancelled in recent history.
|
|
7
|
+
|
|
3
8
|
## [0.25.0] - 2026-10-31
|
|
4
9
|
|
|
5
10
|
- Offer Enable Todo when OpenCode 2's native tool is disabled, with an existing server-config picker, exact change preview and separate confirmation. Preserve unrelated JSONC content and refuse stale targets; distinguish disabled Todo from an enabled empty list.
|
package/HOST_API.md
CHANGED
|
@@ -9,9 +9,9 @@ define the boundary; internal host components are not plugin APIs.
|
|
|
9
9
|
| Capability | OpenCode 1.19.5 | OpenCode 2.2.5 |
|
|
10
10
|
| --- | --- | --- |
|
|
11
11
|
| Todo | Supported host Todo source/events | Public message cache, completed `todowrite` and revert boundary |
|
|
12
|
-
| Skills | Host discovery and prompt insertion | Native Skill cache and `session.skill` with exact ID |
|
|
13
|
-
| MCP | Host status and connection API | Native cache, sync/invalidate and connect/disconnect |
|
|
14
|
-
| Subagents | Supported child/status API and events | Native session cache/status and typed execution events |
|
|
12
|
+
| Skills | Host discovery and prompt insertion | Native Skill cache and `experimental.session.skill` with exact ID |
|
|
13
|
+
| MCP | Host status and connection API | Native cache, sync/invalidate and `experimental.mcp.connect/disconnect` |
|
|
14
|
+
| Subagents | Supported child/status API and events | Native session cache/status, execution start time and typed execution events |
|
|
15
15
|
| Commands | Public keymap | Public owned layers, targets, priorities, modes, discovery and dispatch |
|
|
16
16
|
| Dialogs/toasts | Public dialog components and mounting | Public show/prompt/confirm/set/clear and toast |
|
|
17
17
|
| Model/variant | Saved session model and host pickers | Reactive prompt model, variant API and host pickers |
|
|
@@ -31,10 +31,10 @@ justify bypassing a native API.
|
|
|
31
31
|
| Bug-report transport and external browser launch | Neither supported public TUI contract provides GitHub issue creation or an external browser opener. Direct sending uses the user's authenticated `gh` without reading credential files; a `type: Bug` repository form handles browser reports. Bounded argv-based OS launch has a visible link/clipboard fallback on remote or headless hosts. | Equivalent public host issue/browser APIs preserving authentication ownership, editable draft, real issue type and confirmation semantics. |
|
|
32
32
|
| Literal Ctrl+, hook on 2.x | Public plugin bindings are strings; the comma expander splits literal commas into alternatives. The named parser does not normalize `comma` to the actual comma event. Dispatch still uses the native command API. | A documented literal-comma binding passing the real Settings smoke. |
|
|
33
33
|
| Subagent child discovery | Published TUI Data caches sessions but has no complete children-sync operation. Initial/manual/reconnect discovery uses the public paginated API and syncs unknown IDs into the host cache. | A complete children-sync/query on the supplied public Data interface. |
|
|
34
|
-
| Subagent observation history and retry details | Native status and cached
|
|
34
|
+
| Subagent observation history and retry details | Native status, `SessionInfo.time.busy` and cached retry data are used first. Valid current-execution start times give exact active durations without a pre-observation marker; missing/invalid timing keeps the observed fallback. Recent runs, errors and unloaded-child retry details remain observation history. The prior execution's `idle`/`outcome` never completes a currently running execution. | Equivalent public observed-run/retry history without loading every transcript. |
|
|
35
35
|
| Read-only Todo projection | Native completed tool calls and revert are public; the host's `sessionTodos` helper is not exported. No direct CRUD/priority API exists. | A public equivalent projection; editing also requires an explicitly selected interaction and supported API. |
|
|
36
36
|
| Native Todo enablement | `config.get` exposes ordered sources, but `experimental.config.update` supports only shell. The setup feature previews and confirms a JSONC leaf edit in an existing discovered source through public server file APIs. File reads are location-confined, so selected-file IO is routed to its server-side parent; the original session/location remains the stale-target guard. Reads immediately before writes reject changed previews, and readback verifies the file and effective flag. The public write API has no CAS, so this is not an atomic transaction against concurrent external writers; uncertain outcomes require Refresh before retry. No model, shell or Todo event is used. | A public Todo config patch API preserving source precedence, unrelated JSONC content and conditional-write semantics. |
|
|
37
|
-
| Console/Go request lifecycle and projection | `client.usage.limits` is public, but the internal usage cache and budget selectors are not in published Plugin Context. Workspace IDs are not provider account IDs. | Equivalent public cache and selector on the plugin interface. |
|
|
37
|
+
| Console/Go request lifecycle and projection | `client.experimental.usage.limits` is public, but the internal usage cache and budget selectors are not in published Plugin Context. Workspace IDs are not provider account IDs. | Equivalent public cache and selector on the plugin interface. |
|
|
38
38
|
| External quotas / reset credits | Console/Go is not a universal provider API and has no Codex reset-credit consume operation. Sources stay documented, account-bound and portable. Native auth/request errors never enable a bypass reader. | Host APIs matching provider/account/units/resets and idempotent consume semantics. |
|
|
39
39
|
| Pinned-file snapshot installer | Native package updates do not implement the recognized versioned wrapper/staging layout. Preserve installation source and scope. | A public atomic file-snapshot update API with equivalent verification. |
|
|
40
40
|
| Corner masks and product UI | Multiline shape, three-cell controls, filters, groups, presets and pins are product features. Paint hooks only draw; scroll restoration runs outside paint. | Equivalent public primitives preserving geometry, behavior and fallback mode. |
|
|
@@ -55,7 +55,7 @@ exercise migration only; they do not extend the supported host matrix.
|
|
|
55
55
|
The published 2.2.5 TUI context, plugin, index and Solid declarations are identical
|
|
56
56
|
to 2.2.0. OpenTUI 0.8 retains the drawing-only paint-hook contract; renderer tests,
|
|
57
57
|
nested dialogs and frame-level typing probes run against the updated runtime.
|
|
58
|
-
Development uses Bun 1.4.4 and OpenTUI 0.8.
|
|
58
|
+
Development uses Bun 1.4.4 and OpenTUI 0.8.2, leaving Solid/OpenTUI external so the
|
|
59
59
|
host owns its runtime. The 1.x host ships older runtime modules; its actual smoke
|
|
60
60
|
must pass rather than injecting the development modules into it.
|
|
61
61
|
|
|
@@ -67,13 +67,22 @@ renderer/FFI support. CI and package verification use Node 26.12.1.
|
|
|
67
67
|
### Deliberate Compatibility Pins
|
|
68
68
|
|
|
69
69
|
- `web-tree-sitter` stays at **0.25.10**, the exact peer required by OpenTUI
|
|
70
|
-
0.8.
|
|
70
|
+
0.8.2. Upgrade it when the supported host runtime publishes a compatible peer
|
|
71
71
|
contract; the independent 0.27 line is not a compatible substitution.
|
|
72
|
-
- `typescript` is **
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
- `typescript` is **6.0.3**, selected to match the complete published
|
|
73
|
+
`@st1ggy/linter-config` **10.0.0** preset. SonarJS and typescript-eslint JS
|
|
74
|
+
plugins remain enabled without the former TS7 projection or override.
|
|
75
|
+
[Lint coverage](LINT_COVERAGE.md) records the current setup and historical exclusions.
|
|
76
|
+
- Oxlint **1.90.0**, Oxfmt **0.75.0** and oxlint-tsgolint **7.0.2005** match the
|
|
77
|
+
preset's exact peer versions. Advance them when the preset supports newer engines.
|
|
78
|
+
- OpenTUI's transitive `bun-ffi-structs` **0.3.1** declares the outdated compiler
|
|
79
|
+
peer `typescript: ^5`. A root-only Bun metadata patch expands it to `^5 || ^6`;
|
|
80
|
+
no runtime bytes or declarations change. Strict declaration compilation with
|
|
81
|
+
library checks enabled, packing regressions and the resolved compiler graph
|
|
82
|
+
verify the selected TS6 use. Remove the patch when upstream accepts TS6.
|
|
83
|
+
Bun patches apply only in this repository, not transitively in consumer projects
|
|
84
|
+
or the separately generated snapshot runtime manifest. Those installations may
|
|
85
|
+
still report the upstream peer warning; this is not an upstream fix.
|
|
77
86
|
- Bun remains pinned at **1.4.4**, the current stable release. Direct dependencies
|
|
78
87
|
otherwise use their latest compatible stable releases; transitive updates stay
|
|
79
88
|
within upstream ranges. Runtime peers remain host-owned and are not bundled.
|
package/LINT_COVERAGE.md
CHANGED
|
@@ -1,39 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Lint Coverage
|
|
2
2
|
|
|
3
|
-
Project type checking uses stable TypeScript
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Project type checking uses stable TypeScript 6.0.3, matching the compiler API
|
|
4
|
+
used by the published shared preset. The user selected this compatibility-first
|
|
5
|
+
setup instead of extending the previous TypeScript 7 coverage exclusions.
|
|
6
6
|
|
|
7
7
|
Oxlint uses `@st1ggy/linter-config/solid-ox` with type-aware analysis. Oxfmt uses
|
|
8
|
-
`@st1ggy/linter-config/oxfmt-common`.
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
`@st1ggy/linter-config/oxfmt-common`. The version 10 preset is extended directly,
|
|
9
|
+
including its SonarJS and typescript-eslint JS plugins. No compiler-compatibility
|
|
10
|
+
projection filters its rules. Deliberate project exceptions remain documented
|
|
11
|
+
beside their individual settings in `oxlint.config.ts`.
|
|
11
12
|
|
|
12
13
|
## Preserved Checks
|
|
13
14
|
|
|
14
15
|
- Native ESLint, TypeScript, import and Unicorn rules remain enabled.
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
- All published Solid, ESLint-core, import-x, stylistic, Unicorn, SonarJS and
|
|
17
|
+
typescript-eslint JS plugins remain enabled.
|
|
18
|
+
- Promise handling and strict equality follow the version 10 preset.
|
|
19
|
+
- Bun 1.4.4 can return undefined from `rejects`/`resolves` matchers for already
|
|
20
|
+
settled promises. Tests normalize matcher results through `Promise.resolve`
|
|
21
|
+
before awaiting, preserving pending assertions and satisfying both the native
|
|
22
|
+
thenable rule and SonarJS assertion handling without disabling either rule.
|
|
22
23
|
- Oxfmt still checks formatting separately. This migration does not configure
|
|
23
24
|
Stylelint for the CSS-free TUI project.
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## Historical TypeScript 7 Coverage Exclusions
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
checks for frameworks and services this project does not use; it describes the
|
|
32
|
-
preset, not 155 distinct bugs or applicable findings in Navigator.
|
|
28
|
+
Navigator 0.25.0 used native substitutions for six SonarJS rules and excluded
|
|
29
|
+
the following 155 rule names from preset 8 for TS7 compatibility. This list is
|
|
30
|
+
historical, not the current configuration. Preset 10 now supplies its complete
|
|
31
|
+
rule set, subject only to the documented project-specific exceptions.
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
cognitive complexity.
|
|
36
|
-
checks and SonarJS-specific test heuristics lose their dedicated coverage.
|
|
33
|
+
Native cyclomatic complexity was not considered a replacement for SonarJS
|
|
34
|
+
cognitive complexity. The compiler-driven exclusions are no longer applied.
|
|
37
35
|
|
|
38
36
|
```text
|
|
39
37
|
sonarjs/assertions-in-test-cases
|
|
@@ -193,9 +191,9 @@ sonarjs/x-powered-by
|
|
|
193
191
|
sonarjs/xml-parser-xxe
|
|
194
192
|
```
|
|
195
193
|
|
|
196
|
-
##
|
|
194
|
+
## Future Compiler Upgrades
|
|
197
195
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
The compatibility projection has been removed. Reconsider TypeScript 7 only when
|
|
197
|
+
the complete published lint stack supports its compiler API. Keep coverage
|
|
198
|
+
explicit; do not label a removed check as preserved merely because a similarly
|
|
199
|
+
named rule exists.
|
package/README.md
CHANGED
|
@@ -936,9 +936,11 @@ tasks before pending tasks. Finished contains separate Completed and Cancelled
|
|
|
936
936
|
groups. The selected view is temporary and resets to All when changing sessions.
|
|
937
937
|
The header always reports completed tasks against the full task count.
|
|
938
938
|
|
|
939
|
-
Subagents show
|
|
940
|
-
|
|
941
|
-
|
|
939
|
+
Subagents show run duration, retry countdowns, and execution errors. OpenCode 2
|
|
940
|
+
uses its public execution-start timestamp for exact active durations, including
|
|
941
|
+
children already running when Navigator opens. Missing or invalid native timing
|
|
942
|
+
and OpenCode 1 retain observed durations. An already-running child whose exact
|
|
943
|
+
start is unknown has a clock icon (`~` in Text fallback). Recent keeps the last 10 observed
|
|
942
944
|
finished runs per parent session in memory across navigation, until OpenCode exits.
|
|
943
945
|
An idle transition is labelled Finished, not a guarantee of successful task
|
|
944
946
|
completion; errors and cancellations retain their own labels. A worker timeout
|
|
@@ -974,7 +976,7 @@ session or workspace dismisses the entire search dialog chain.
|
|
|
974
976
|
|
|
975
977
|
## Scripts
|
|
976
978
|
|
|
977
|
-
Development uses Bun 1.4.4 and stable TypeScript
|
|
979
|
+
Development uses Bun 1.4.4 and stable TypeScript 6.0.3. Standalone Node/OpenTUI paths
|
|
978
980
|
require Node.js 26.4 or newer; CI pins Node 26.12.1. Install dependencies with
|
|
979
981
|
`bun install --frozen-lockfile`.
|
|
980
982
|
|
|
@@ -984,9 +986,11 @@ Oxlint uses the `solid-ox` preset from
|
|
|
984
986
|
OpenTUI callbacks, SDK compatibility, and test fixtures. Type-aware analysis uses
|
|
985
987
|
`oxlint-tsgolint`; `tsconfig.lint.json` covers application code, tests, build scripts,
|
|
986
988
|
and configuration files. Formatter exclusions are maintained in `oxfmt.config.ts`.
|
|
987
|
-
The
|
|
988
|
-
|
|
989
|
-
|
|
989
|
+
The complete version 10 preset includes SonarJS and typescript-eslint checks;
|
|
990
|
+
the former TS7 compatibility projection is removed. See [Lint coverage](LINT_COVERAGE.md)
|
|
991
|
+
for current exceptions and historical exclusions. A tested root-only Bun metadata
|
|
992
|
+
patch corrects the legacy TypeScript 5 peer in OpenTUI's FFI helper for this repo.
|
|
993
|
+
Consumer installations retain upstream metadata; see [Host APIs](HOST_API.md).
|
|
990
994
|
|
|
991
995
|
```sh
|
|
992
996
|
bun run test
|
package/dist/provider-limits.js
CHANGED
|
@@ -14,8 +14,9 @@ pending.delete(id)
|
|
|
14
14
|
}}
|
|
15
15
|
function write(message){if(!child?.stdin||typeof child.stdin==="number")
|
|
16
16
|
throw new Error("Codex app-server is unavailable")
|
|
17
|
-
child.stdin.write(`${JSON.stringify(message)}
|
|
18
|
-
`)
|
|
17
|
+
Promise.resolve(child.stdin.write(`${JSON.stringify(message)}
|
|
18
|
+
`)).catch((error)=>{failAll(error instanceof Error?error:new Error("Codex app-server write failed"))
|
|
19
|
+
})
|
|
19
20
|
}
|
|
20
21
|
function accept(line){let message
|
|
21
22
|
try{message=JSON.parse(line)
|
|
@@ -677,13 +678,13 @@ setRevision((value)=>value + 1)
|
|
|
677
678
|
}),context.data.on("server.connected",()=>{generation++
|
|
678
679
|
setRevision((value)=>value + 1)
|
|
679
680
|
})]
|
|
680
|
-
const adapter={id:"opencode-usage",name:"OpenCode workspace limits",supports:(model)=>typeof context.client.usage?.limits==="function"&&provider(model)?.integrationID==="opencode",async read(model,signal){signal.throwIfAborted()
|
|
681
|
+
const adapter={id:"opencode-usage",name:"OpenCode workspace limits",supports:(model)=>typeof context.client.experimental?.usage?.limits==="function"&&provider(model)?.integrationID==="opencode",async read(model,signal){signal.throwIfAborted()
|
|
681
682
|
const epoch=generation
|
|
682
683
|
const target=key()
|
|
683
684
|
const activeProvider=provider(model)
|
|
684
685
|
if(!activeProvider||activeProvider.integrationID!=="opencode")
|
|
685
686
|
throw new Error("Native usage provider changed")
|
|
686
|
-
try{const result=await context.client.usage.limits({location:{directory:location().directory}},{signal})
|
|
687
|
+
try{const result=await context.client.experimental.usage.limits({location:{directory:location().directory}},{signal})
|
|
687
688
|
if(epoch!==generation||target!==key()||signal.aborted||result.location.directory!==location().directory)
|
|
688
689
|
throw new DOMException("Workspace usage target changed","AbortError")
|
|
689
690
|
if(!result.data)
|
|
@@ -1062,7 +1063,7 @@ return _$createComponent13(Section,{get api(){return props.api
|
|
|
1062
1063
|
},get navigationSection(){return props.navigationSection
|
|
1063
1064
|
},get credits(){return(snapshot()?.bankedResets?.availableCount??0)>0||Boolean(props.preferences.pendingResetAttempt())
|
|
1064
1065
|
},get refreshing(){return ["loading","refreshing"].includes(props.controller.state().status)
|
|
1065
|
-
},get canRefresh(){return Boolean(model()&&(props.controller.current().adapter
|
|
1066
|
+
},get canRefresh(){return Boolean(model()&&(props.controller.current().adapter??model()?.hostConnection?.status==="unavailable"))
|
|
1066
1067
|
},onCredits:openCredits,onRefresh:()=>void props.controller.refresh(true)
|
|
1067
1068
|
})
|
|
1068
1069
|
},get open(){return props.preferences.expanded().limits
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 1,
|
|
3
3
|
"dependencies": {
|
|
4
4
|
"@opencode/plugin": "2.2.5",
|
|
5
|
-
"@opentui/core": "0.8.
|
|
6
|
-
"@opentui/keymap": "0.8.
|
|
7
|
-
"@opentui/solid": "0.8.
|
|
5
|
+
"@opentui/core": "0.8.2",
|
|
6
|
+
"@opentui/keymap": "0.8.2",
|
|
7
|
+
"@opentui/solid": "0.8.2",
|
|
8
8
|
"solid-js": "1.9.18"
|
|
9
9
|
}
|
|
10
10
|
}
|
package/dist/sidebar-settings.js
CHANGED
|
@@ -49,8 +49,6 @@ let child
|
|
|
49
49
|
try{child=Bun.spawn([...command],{stdin:"pipe",stdout:"pipe",stderr:"ignore",env:environment?{...process.env,...environment}:undefined
|
|
50
50
|
})
|
|
51
51
|
} catch{return{code:-1,stdout:""}}
|
|
52
|
-
child.stdin.write(input)
|
|
53
|
-
child.stdin.end()
|
|
54
52
|
let timer
|
|
55
53
|
const chunks=[]
|
|
56
54
|
const output=()=>new TextDecoder().decode(Buffer.concat(chunks))
|
|
@@ -77,7 +75,11 @@ chunks.push(part.value)
|
|
|
77
75
|
}
|
|
78
76
|
return{code:await child.exited,stdout:output()}} finally{reader.releaseLock()
|
|
79
77
|
}}
|
|
80
|
-
|
|
78
|
+
const run=async ()=>{await child.stdin.write(input)
|
|
79
|
+
await child.stdin.end()
|
|
80
|
+
return read()
|
|
81
|
+
}
|
|
82
|
+
try{return await Promise.race([run(),cancelled])
|
|
81
83
|
} catch{return{code:-1,stdout:""}} finally{clearTimeout(timer)
|
|
82
84
|
signal?.removeEventListener("abort",cancel)
|
|
83
85
|
}}
|
package/dist/tui.js
CHANGED
|
@@ -179,10 +179,14 @@ setStates((values)=>({...values,[target]:{status:"error",error:requestError(caus
|
|
|
179
179
|
return{state,start,abort,abortAll}}
|
|
180
180
|
function wait(delay,signal){return new Promise((resolve,reject)=>{if(signal?.aborted)
|
|
181
181
|
return reject(signal.reason??new DOMException("Aborted","AbortError"))
|
|
182
|
-
const
|
|
183
|
-
signal?.
|
|
184
|
-
reject(signal
|
|
185
|
-
}
|
|
182
|
+
const abort=()=>{clearTimeout(timer)
|
|
183
|
+
signal?.removeEventListener("abort",abort)
|
|
184
|
+
reject(signal?.reason??new DOMException("Aborted","AbortError"))
|
|
185
|
+
}
|
|
186
|
+
const timer=setTimeout(()=>{signal?.removeEventListener("abort",abort)
|
|
187
|
+
resolve()
|
|
188
|
+
},delay)
|
|
189
|
+
signal?.addEventListener("abort",abort,{once:true})
|
|
186
190
|
})
|
|
187
191
|
}
|
|
188
192
|
async function retryBackgroundRefresh(refresh,options={}){const delays=options.delays??[250,1000]
|
|
@@ -1604,7 +1608,7 @@ behavior.quickActionVisibility=quickActionVisibility
|
|
|
1604
1608
|
const mcpUpdate={...update.mcp?.states,...update.mcp?.name&&update.mcp.state&&{[update.mcp.name]:update.mcp.state}}
|
|
1605
1609
|
const mcp=parseDesiredMcpStates({...!update.clearMcp&&existing.mcp,...mcpUpdate
|
|
1606
1610
|
})
|
|
1607
|
-
const scope={...Object.keys(behavior).length>0&&{behavior},...(update.layout
|
|
1611
|
+
const scope={...Object.keys(behavior).length>0&&{behavior},...(update.layout??(!update.clearLayout&&existing.layout))&&{layout:parseSectionLayout(update.layout??existing.layout)
|
|
1608
1612
|
},...Object.keys(mcp).length>0&&{mcp}}
|
|
1609
1613
|
const worktrees={...current.worktrees}
|
|
1610
1614
|
if(target.kind==="worktree"){if(isEmptyScope(scope))
|
|
@@ -1786,10 +1790,13 @@ await unlink(recovery).catch((error)=>{if(!errno(error,"ENOENT"))
|
|
|
1786
1790
|
throw error
|
|
1787
1791
|
})
|
|
1788
1792
|
}}
|
|
1789
|
-
async function tryAcquireLock(){const token=randomUUID()
|
|
1793
|
+
async function tryAcquireLock(deadline){const token=randomUUID()
|
|
1790
1794
|
const candidate=`${lock}.${token}.candidate`
|
|
1795
|
+
let acquired=false
|
|
1796
|
+
let handedOff=false
|
|
1791
1797
|
await writeFile(candidate,JSON.stringify({token,pid:process.pid}),{flag:"wx",mode:384})
|
|
1792
1798
|
try{try{await link(candidate,lock)
|
|
1799
|
+
acquired=true
|
|
1793
1800
|
} catch(error){if(!errno(error,"EEXIST"))
|
|
1794
1801
|
throw error
|
|
1795
1802
|
const owner=await readLockOwner()
|
|
@@ -1801,22 +1808,29 @@ return
|
|
|
1801
1808
|
while(true){const markers=await liveRecoveryMarkers()
|
|
1802
1809
|
if(markers.length===0)
|
|
1803
1810
|
break
|
|
1811
|
+
if(Date.now()>=deadline)
|
|
1812
|
+
return
|
|
1804
1813
|
await delay(10)
|
|
1805
1814
|
}
|
|
1806
1815
|
const currentOwner=await readLockOwner()
|
|
1807
1816
|
if(currentOwner?.token!==token)
|
|
1808
1817
|
return
|
|
1818
|
+
handedOff=true
|
|
1809
1819
|
return async ()=>{const current=await readLockOwner()
|
|
1810
1820
|
if(current?.token!==token)
|
|
1811
1821
|
throw new Error("Refusing to release a preferences lock owned by another process")
|
|
1812
1822
|
await moveLockToTombstone("released")
|
|
1813
|
-
}} finally{
|
|
1823
|
+
}} finally{if(acquired&&!handedOff){const current=await readLockOwner()
|
|
1824
|
+
if(current?.token===token)
|
|
1825
|
+
await moveLockToTombstone("released")
|
|
1826
|
+
}
|
|
1827
|
+
await unlink(candidate).catch((error)=>{if(!errno(error,"ENOENT"))
|
|
1814
1828
|
throw error
|
|
1815
1829
|
})
|
|
1816
1830
|
}}
|
|
1817
1831
|
async function acquireLock(){await mkdir(directory,{recursive:true,mode:448})
|
|
1818
1832
|
const deadline=Date.now() + LOCK_TIMEOUT_MS
|
|
1819
|
-
while(true){const release=await tryAcquireLock()
|
|
1833
|
+
while(true){const release=await tryAcquireLock(deadline)
|
|
1820
1834
|
if(release)
|
|
1821
1835
|
return release
|
|
1822
1836
|
if(Date.now()>=deadline)
|
|
@@ -2775,7 +2789,7 @@ return value
|
|
|
2775
2789
|
}
|
|
2776
2790
|
function changed(){setRevision((value)=>value + 1)
|
|
2777
2791
|
}
|
|
2778
|
-
return{observeStatus(key,sessionID,status,at=now()){const value=state(key)
|
|
2792
|
+
return{observeStatus(key,sessionID,status,at=now(),nativeStart){const value=state(key)
|
|
2779
2793
|
const run=value.active.get(sessionID)
|
|
2780
2794
|
const isKnown=value.known.has(sessionID)
|
|
2781
2795
|
value.known.add(sessionID)
|
|
@@ -2783,10 +2797,17 @@ if(status.type==="idle"){if(!run)
|
|
|
2783
2797
|
return
|
|
2784
2798
|
value.active.delete(sessionID)
|
|
2785
2799
|
value.recent=[{...run,finishedAt:Math.max(at,run.startedAt),outcome:run.outcome??"finished"},...value.recent].sort((a,b)=>b.finishedAt-a.finishedAt||a.sessionID.localeCompare(b.sessionID)).slice(0,10)
|
|
2786
|
-
} else{
|
|
2800
|
+
} else{const exact=typeof nativeStart==="number"&&Number.isFinite(nativeStart)&&nativeStart>0&&nativeStart<=at?nativeStart:undefined
|
|
2801
|
+
if(run){if(exact===undefined||run.nativeStartedAt!==undefined&&exact<=run.nativeStartedAt)
|
|
2802
|
+
return
|
|
2803
|
+
const next=exact>run.startedAt?{sessionID}:run
|
|
2804
|
+
value.active.set(sessionID,{...next,startedAt:exact,nativeStartedAt:exact,startedBeforeObservation:false
|
|
2805
|
+
})
|
|
2806
|
+
changed()
|
|
2787
2807
|
return
|
|
2808
|
+
}
|
|
2788
2809
|
value.recent=value.recent.filter((item)=>item.sessionID!==sessionID)
|
|
2789
|
-
value.active.set(sessionID,{sessionID,startedAt:at,startedBeforeObservation
|
|
2810
|
+
value.active.set(sessionID,{sessionID,startedAt:exact??at,startedBeforeObservation:exact===undefined&&!isKnown,...exact!==undefined&&{nativeStartedAt:exact}})
|
|
2790
2811
|
}
|
|
2791
2812
|
changed()
|
|
2792
2813
|
},observeError(key,sessionID,error,at=now()){if(!sessionID)
|
|
@@ -2857,12 +2878,13 @@ journal.sessions.push(mutation)
|
|
|
2857
2878
|
if(!source)
|
|
2858
2879
|
setChildren((current)=>Object.fromEntries(Object.entries(current).map(([key,items])=>[key,applySession(items,targets.get(key).parentID,mutation)])))
|
|
2859
2880
|
}
|
|
2860
|
-
function recordStatus(input){const mutation={...input,at:now(),observed:new Set
|
|
2881
|
+
function recordStatus(input){const mutation={...input,at:now(),startedAt:source?.startedAt?.(input.sessionID),observed:new Set
|
|
2882
|
+
}
|
|
2861
2883
|
for(const journal of journals)
|
|
2862
2884
|
journal.statuses.push(mutation)
|
|
2863
2885
|
batch(()=>{for(const [key,items] of Object.entries(snapshots())){if(items.every((item)=>item.id!==mutation.sessionID))
|
|
2864
2886
|
continue
|
|
2865
|
-
history.observeStatus(key,mutation.sessionID,mutation.status,mutation.at)
|
|
2887
|
+
history.observeStatus(key,mutation.sessionID,mutation.status,mutation.at,mutation.startedAt)
|
|
2866
2888
|
mutation.observed.add(key)
|
|
2867
2889
|
}
|
|
2868
2890
|
if(!source)
|
|
@@ -2897,7 +2919,7 @@ for(const mutation of journal.sessions)
|
|
|
2897
2919
|
nextChildren=applySession(nextChildren,current.parentID,mutation)
|
|
2898
2920
|
let nextStatuses={...statusResult.data}
|
|
2899
2921
|
const missing={}
|
|
2900
|
-
const remoteStatuses=source?[]:await Promise.all(nextChildren.map((session)=>{const key=JSON.stringify([current.key,session.id])
|
|
2922
|
+
const remoteStatuses=source?[]:await Promise.all(nextChildren.map(async (session)=>{const key=JSON.stringify([current.key,session.id])
|
|
2901
2923
|
return(remoteRetryAt.get(key)??0)<=now()?fetchDevTeamStatus(session,requestState.signal):{sessionID:session.id,failed:true,cooldown:true,status:undefined}}))
|
|
2902
2924
|
if(!requestState.isCurrent())
|
|
2903
2925
|
return
|
|
@@ -2926,10 +2948,10 @@ for(const mutation of journal.statuses)
|
|
|
2926
2948
|
nextStatuses=applyStatus(nextStatuses,mutation)
|
|
2927
2949
|
if(requestState.isCurrent()){batch(()=>{for(const session of nextChildren){const mutations=journal.statuses.filter((mutation)=>mutation.sessionID===session.id)
|
|
2928
2950
|
if(mutations.length>0){for(const mutation of mutations){if(!mutation.observed.has(current.key))
|
|
2929
|
-
history.observeStatus(current.key,session.id,mutation.status,mutation.at)
|
|
2951
|
+
history.observeStatus(current.key,session.id,mutation.status,mutation.at,mutation.startedAt)
|
|
2930
2952
|
}} else if(!missing[session.id]){const status=nextStatuses[session.id]??{type:"idle"}
|
|
2931
2953
|
nextStatuses[session.id]=status
|
|
2932
|
-
history.observeStatus(current.key,session.id,status)
|
|
2954
|
+
history.observeStatus(current.key,session.id,status,now(),source?.startedAt?.(session.id))
|
|
2933
2955
|
}
|
|
2934
2956
|
for(const mutation of journal.errors){if(mutation.sessionID===session.id&&!mutation.observed.has(current.key))
|
|
2935
2957
|
history.observeError(current.key,session.id,mutation.error,mutation.at)
|
|
@@ -4375,7 +4397,7 @@ return _$createElement("box")
|
|
|
4375
4397
|
|
|
4376
4398
|
function UpgradeNotesBinding(props){let pending
|
|
4377
4399
|
let disposed=false
|
|
4378
|
-
|
|
4400
|
+
async function load(){const previous=await props.preferences.claimNavigatorUpgrade(props.version)
|
|
4379
4401
|
if(!previous||disposed)
|
|
4380
4402
|
return
|
|
4381
4403
|
try{let show=function(){if(disposed||props.api.lifecycle.signal?.aborted)
|
|
@@ -4395,7 +4417,8 @@ const entries=changesSince(await (props.read??readBundledChangelog)(),previous,p
|
|
|
4395
4417
|
if(entries.length===0||disposed)
|
|
4396
4418
|
return
|
|
4397
4419
|
show()
|
|
4398
|
-
} catch{}}
|
|
4420
|
+
} catch{}}
|
|
4421
|
+
onMount6(()=>void load().catch(()=>{}))
|
|
4399
4422
|
onCleanup16(()=>{disposed=true
|
|
4400
4423
|
clearTimeout(pending)
|
|
4401
4424
|
})
|
|
@@ -6990,7 +7013,7 @@ onCleanup29(()=>{disposed=true
|
|
|
6990
7013
|
function LimitsPersistence(props){createLimitsRefresh(props)
|
|
6991
7014
|
return _$createElement("box")
|
|
6992
7015
|
}
|
|
6993
|
-
function bindNavigatorAbout(api,status,updates,notes){const dispose=registerNavigatorAboutServices(api,{navigatorVersion:"0.
|
|
7016
|
+
function bindNavigatorAbout(api,status,updates,notes){const dispose=registerNavigatorAboutServices(api,{navigatorVersion:"0.26.0",openCodeVersion:api.app.version,checkState:()=>status.navigatorCheckState?.()??{status:"idle"},checking:()=>status.navigatorCheckState?.().status==="checking",updating:updates.navigatorUpdating,installed:updates.navigatorInstalled,check:()=>status.refreshNavigator?.()??Promise.resolve("unavailable"),update(dialogs){const target=status.navigatorUpdate()
|
|
6994
7017
|
if(target)
|
|
6995
7018
|
updates.navigator(target,dialogs)
|
|
6996
7019
|
},changelog:async ()=>notes.parseChangelog(await notes.readBundledChangelog())
|
|
@@ -7013,11 +7036,11 @@ const candidates=context.data.location.skill.list({directory})?.filter((skill)=>
|
|
|
7013
7036
|
const id=candidates.length===1?candidates[0].id:undefined
|
|
7014
7037
|
if(route.type!=="session"||session?.location.directory!==directory||!id)
|
|
7015
7038
|
return{data:false}
|
|
7016
|
-
await context.client.session.skill({sessionID:route.sessionID,id},{signal:options.signal})
|
|
7039
|
+
await context.client.experimental.session.skill({sessionID:route.sessionID,id},{signal:options.signal})
|
|
7017
7040
|
return{data:true}}},mcp:{async status(input,options={}){const response=await context.client.mcp.list(location(input),{signal:options.signal})
|
|
7018
7041
|
const data=Object.fromEntries(response.data.map((server)=>[server.name,server.status]))
|
|
7019
|
-
return{data}},async connect(input,options={}){await context.client.mcp.connect({server:input.name,...location(input)},{signal:options.signal})
|
|
7020
|
-
return{data:undefined}},async disconnect(input,options={}){await context.client.mcp.disconnect({server:input.name,...location(input)},{signal:options.signal})
|
|
7042
|
+
return{data}},async connect(input,options={}){await context.client.experimental.mcp.connect({server:input.name,...location(input)},{signal:options.signal})
|
|
7043
|
+
return{data:undefined}},async disconnect(input,options={}){await context.client.experimental.mcp.disconnect({server:input.name,...location(input)},{signal:options.signal})
|
|
7021
7044
|
return{data:undefined}}}}}}
|
|
7022
7045
|
var TERMINAL_EVENTS=new Set(["session.execution.succeeded","session.execution.failed","session.execution.interrupted"])
|
|
7023
7046
|
function executionStatus(name,event){const sessionID=event.data.sessionID
|
|
@@ -7037,7 +7060,7 @@ return ["session.status","session.retry.scheduled",...executions]
|
|
|
7037
7060
|
if(name==="session.idle")
|
|
7038
7061
|
return ["session.idle",...executions.slice(1)]
|
|
7039
7062
|
if(name==="session.error")
|
|
7040
|
-
return ["session.execution.failed"]
|
|
7063
|
+
return ["session.execution.failed","session.execution.interrupted"]
|
|
7041
7064
|
if(name==="mcp.tools.changed")
|
|
7042
7065
|
return ["mcp.status.changed","mcp.resources.changed"]
|
|
7043
7066
|
if(["session.created","session.deleted","server.connected","installation.update-available"].includes(name))
|
|
@@ -7082,7 +7105,7 @@ if(name==="session.deleted"){emit({sessionID})
|
|
|
7082
7105
|
return
|
|
7083
7106
|
}
|
|
7084
7107
|
if(name==="session.error"){const error=data.error
|
|
7085
|
-
emit({sessionID,error:error&&{name:error.type??"Error",data:{message:error.message??"Session error"}}})
|
|
7108
|
+
emit({sessionID,error:event.type==="session.execution.interrupted"?{name:"MessageAbortedError",data:{message:"Session aborted"}}:error&&{name:error.type??"Error",data:{message:error.message??"Session error"}}})
|
|
7086
7109
|
return
|
|
7087
7110
|
}
|
|
7088
7111
|
const info=context.data.session.get(sessionID)
|
|
@@ -7243,7 +7266,7 @@ function DialogPrompt(props){return _$createComponent(SingleLinePrompt,_$mergePr
|
|
|
7243
7266
|
function DialogConfirm(props){let active=true
|
|
7244
7267
|
onCleanup30(()=>{active=false
|
|
7245
7268
|
})
|
|
7246
|
-
|
|
7269
|
+
async function confirm(){const confirmed=await context.ui.dialog.confirm({title:props.title,message:props.message
|
|
7247
7270
|
})
|
|
7248
7271
|
if(!active)
|
|
7249
7272
|
return
|
|
@@ -7251,6 +7274,10 @@ if(confirmed)
|
|
|
7251
7274
|
props.onConfirm?.()
|
|
7252
7275
|
else
|
|
7253
7276
|
props.onCancel?.()
|
|
7277
|
+
}
|
|
7278
|
+
onMount7(()=>{confirm().catch(()=>{if(active)
|
|
7279
|
+
props.onCancel?.()
|
|
7280
|
+
})
|
|
7254
7281
|
})
|
|
7255
7282
|
return _$createElement("box")
|
|
7256
7283
|
}
|
|
@@ -7420,12 +7447,18 @@ const session=route.type==="session"&&context.data.session.get(route.sessionID)
|
|
|
7420
7447
|
const actual=list(target).find((item)=>item.id===skill.id&&item.location===skill.location)
|
|
7421
7448
|
if(route.type!=="session"||!session||session.location.directory!==target.routing.directory||!actual?.id)
|
|
7422
7449
|
throw new Error("Skill target changed; select the source again")
|
|
7423
|
-
await context.client.session.skill({sessionID:route.sessionID,id:actual.id},{signal})
|
|
7450
|
+
await context.client.experimental.session.skill({sessionID:route.sessionID,id:actual.id},{signal})
|
|
7424
7451
|
return !signal.aborted
|
|
7425
7452
|
}}}
|
|
7426
7453
|
function createV2SubagentSource(context,api){return{list:(parentID)=>context.data.session.list().filter((item)=>item.parentID===parentID).flatMap((item)=>{const value=api.state.session.get(item.id)
|
|
7427
7454
|
return value?[value]:[]
|
|
7428
|
-
}),status:(id)=>api.state.session.status(id)??{type:"idle"},
|
|
7455
|
+
}),status:(id)=>api.state.session.status(id)??{type:"idle"},startedAt(id){if(context.data.session.status(id)!=="running")
|
|
7456
|
+
return
|
|
7457
|
+
const time=context.data.session.get(id)?.time
|
|
7458
|
+
if(!time?.busy||time.idle!==undefined&&time.idle>=time.busy)
|
|
7459
|
+
return
|
|
7460
|
+
return time.busy
|
|
7461
|
+
},async refresh(parentID,signal){signal.throwIfAborted()
|
|
7429
7462
|
let cursor
|
|
7430
7463
|
do{const page=await context.client.session.list(cursor?{cursor,limit:100}:{parentID,limit:100},{signal
|
|
7431
7464
|
})
|
|
@@ -7455,7 +7488,7 @@ const limitsPath=import.meta.url.includes("/dist/tui.js")?"./provider-limits.js"
|
|
|
7455
7488
|
const limitsModule=await import(limitsPath)
|
|
7456
7489
|
const LimitsSection=limitsModule.ProviderLimitsSection
|
|
7457
7490
|
const{controller:limits,codex,accountSource,selectModel,modelSelection
|
|
7458
|
-
}=limitsModule.createProviderQuotaIntegration(api,preferences,"0.
|
|
7491
|
+
}=limitsModule.createProviderQuotaIntegration(api,preferences,"0.26.0",hostContext)
|
|
7459
7492
|
const mcp=createMcpController(api,preferences.persistMcp,preferences,nativeSources?.mcp)
|
|
7460
7493
|
const interaction=createSidebarInteraction(api,()=>openKeyboardHelp(api,preferences.lspIconStyle,preferences.cornerFont,sidebarShortcutActions(api)))
|
|
7461
7494
|
const startup=createStartupSessionController(api,preferences)
|
|
@@ -7484,7 +7517,7 @@ api.slots.register({order:100,slots:{app(){return _$createComponent(IconProvider
|
|
|
7484
7517
|
},interaction,skills,subagents,mcp
|
|
7485
7518
|
}),_$createComponent(FirstRunWizardPersistence,{api,preferences
|
|
7486
7519
|
}),_$createComponent(StartupSessionBinding,{api,controller:startup
|
|
7487
|
-
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.
|
|
7520
|
+
}),_$createComponent(UpgradeNotesBinding,{api,preferences,version:"0.26.0"
|
|
7488
7521
|
}),_$createComponent(McpPersistence,{api,controller:mcp
|
|
7489
7522
|
})]
|
|
7490
7523
|
}})
|
|
@@ -7518,13 +7551,13 @@ return result.data?.type==="text"?result.data.content:undefined
|
|
|
7518
7551
|
const updateServices=await loadNavigatorUpdates()
|
|
7519
7552
|
const{createVersionStatus,createVersionUpdateActions,createOpenCodeV1VersionUpdater
|
|
7520
7553
|
}=updateServices
|
|
7521
|
-
const versionStatus=createVersionStatus(api,"0.
|
|
7522
|
-
const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.
|
|
7554
|
+
const versionStatus=createVersionStatus(api,"0.26.0")
|
|
7555
|
+
const versionUpdates=createVersionUpdateActions(api,versionStatus,createOpenCodeV1VersionUpdater(api,meta),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.26.0"))
|
|
7523
7556
|
bindNavigatorAbout(api,versionStatus,versionUpdates,updateServices)
|
|
7524
7557
|
api.slots.register({order:90,slots:{sidebar_footer(_context,props){return _$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7525
7558
|
},get multilineCorners(){return preferences.cornerFont
|
|
7526
7559
|
},get children(){return _$createComponent(VersionFooter,{api,get sessionID(){return props.session_id
|
|
7527
|
-
},navigatorVersion:"0.
|
|
7560
|
+
},navigatorVersion:"0.26.0",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7528
7561
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7529
7562
|
}})
|
|
7530
7563
|
}})
|
|
@@ -7541,8 +7574,8 @@ return new TextDecoder().decode(await context.client.file.read({location:context
|
|
|
7541
7574
|
const updateServices=await loadNavigatorUpdates()
|
|
7542
7575
|
const{createVersionStatus,createVersionUpdateActions,createOpenCodeV2VersionUpdater
|
|
7543
7576
|
}=updateServices
|
|
7544
|
-
const versionStatus=createVersionStatus(adapter.api,"0.
|
|
7545
|
-
const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.
|
|
7577
|
+
const versionStatus=createVersionStatus(adapter.api,"0.26.0")
|
|
7578
|
+
const versionUpdates=createVersionUpdateActions(adapter.api,versionStatus,createOpenCodeV2VersionUpdater(context),()=>preferences.rememberNavigatorVersionBeforeUpdate("0.26.0"))
|
|
7546
7579
|
bindNavigatorAbout(adapter.api,versionStatus,versionUpdates,updateServices)
|
|
7547
7580
|
const disposeFooter=context.ui.slot({append:"sidebar.footer",render:()=>_$createComponent(IconProvider,{get style(){return preferences.lspIconStyle
|
|
7548
7581
|
},get multilineCorners(){return preferences.cornerFont
|
|
@@ -7550,7 +7583,7 @@ const disposeFooter=context.ui.slot({append:"sidebar.footer",render:()=>_$create
|
|
|
7550
7583
|
_$setProp(_el$,"flexDirection","row")
|
|
7551
7584
|
_$setProp(_el$,"justifyContent","space-between")
|
|
7552
7585
|
_$insert(_el$,_$createComponent(VersionSummary,{get api(){return adapter.api
|
|
7553
|
-
},navigatorVersion:"0.
|
|
7586
|
+
},navigatorVersion:"0.26.0",status:versionStatus,get onOpenCodeUpdate(){return versionUpdates.openCode
|
|
7554
7587
|
},get onNavigatorUpdate(){return versionUpdates.navigator
|
|
7555
7588
|
}}),null)
|
|
7556
7589
|
_$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.
|
|
4
|
+
"version": "0.26.0",
|
|
5
5
|
"description": "Search, navigate, and manage OpenCode sessions from the TUI",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.4.4",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"server.js",
|
|
31
31
|
"rpc.js",
|
|
32
32
|
"assets",
|
|
33
|
+
"patches",
|
|
33
34
|
"scripts/install-font.mjs",
|
|
34
35
|
"scripts/update-local-snapshot.mjs",
|
|
35
36
|
"scripts/snapshot-runtime.mjs",
|
|
@@ -80,7 +81,7 @@
|
|
|
80
81
|
"test:e2e": "bun run build && bash scripts/smoke-opencode.sh && bash scripts/smoke-opencode-v2.sh",
|
|
81
82
|
"test:e2e:v1": "bun run build && bash scripts/smoke-opencode.sh",
|
|
82
83
|
"test:e2e:v2": "bun run build && bash scripts/smoke-opencode-v2.sh",
|
|
83
|
-
"typecheck": "tsc --noEmit",
|
|
84
|
+
"typecheck": "tsc --noEmit && tsc --project tsconfig.ffi.json",
|
|
84
85
|
"check": "bun run test && bun run typecheck && bun run lint && bun run bundle:size && bun run format:check"
|
|
85
86
|
},
|
|
86
87
|
"peerDependencies": {
|
|
@@ -111,10 +112,10 @@
|
|
|
111
112
|
"@opencode-ai/plugin": "1.19.5",
|
|
112
113
|
"@opencode-ai/sdk": "1.19.5",
|
|
113
114
|
"@opencode/plugin": "2.2.5",
|
|
114
|
-
"@opentui/core": "0.8.
|
|
115
|
-
"@opentui/keymap": "0.8.
|
|
116
|
-
"@opentui/solid": "0.8.
|
|
117
|
-
"@st1ggy/linter-config": "
|
|
115
|
+
"@opentui/core": "0.8.2",
|
|
116
|
+
"@opentui/keymap": "0.8.2",
|
|
117
|
+
"@opentui/solid": "0.8.2",
|
|
118
|
+
"@st1ggy/linter-config": "10.0.0",
|
|
118
119
|
"@types/bun": "1.4.4",
|
|
119
120
|
"eslint-plugin-solid": "0.18.1",
|
|
120
121
|
"jsonc-parser": "3.3.1",
|
|
@@ -122,13 +123,10 @@
|
|
|
122
123
|
"oxlint": "1.90.0",
|
|
123
124
|
"oxlint-tsgolint": "7.0.2005",
|
|
124
125
|
"solid-js": "1.9.18",
|
|
125
|
-
"typescript": "
|
|
126
|
+
"typescript": "6.0.3",
|
|
126
127
|
"web-tree-sitter": "0.25.10"
|
|
127
128
|
},
|
|
128
129
|
"optionalDependencies": {
|
|
129
130
|
"@github/copilot-sdk": "1.0.28"
|
|
130
|
-
},
|
|
131
|
-
"overrides": {
|
|
132
|
-
"typescript": "7.0.2"
|
|
133
131
|
}
|
|
134
132
|
}
|