opencode-navigator 0.22.0 → 0.24.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.
@@ -0,0 +1,87 @@
1
+ import {changesSince2,readBundledChangelog2
2
+ } from "./chunk-pwa1wzer.js";
3
+ import {createElement as _$createElement} from "@opentui/solid"
4
+ import {createComponent as _$createComponent} from "@opentui/solid"
5
+ import {onCleanup,onMount} from "solid-js"
6
+ import {createDialogStack} from "./tui.js"
7
+ import {createComponent as _$createComponent2} from "@opentui/solid"
8
+ import {setProp as _$setProp} from "@opentui/solid"
9
+ import {effect as _$effect} from "@opentui/solid"
10
+ import {createTextNode as _$createTextNode} from "@opentui/solid"
11
+ import {insertNode as _$insertNode} from "@opentui/solid"
12
+ import {insert as _$insert} from "@opentui/solid"
13
+ import {createElement as _$createElement2} from "@opentui/solid"
14
+ import {TextAttributes} from "@opentui/core"
15
+ import {useTerminalDimensions} from "@opentui/solid"
16
+ import {For} from "solid-js"
17
+ import {DialogSurface,SelectionBox,useDialogs,useIcons} from "./tui.js"
18
+ function UpgradeNotesDialog(props){const dimensions=useTerminalDimensions()
19
+ const dialogs=useDialogs(props.api)
20
+ const icons=useIcons()
21
+ const theme=()=>props.api.theme.current
22
+ return _$createComponent2(DialogSurface,{get api(){return props.api
23
+ },lift:true,get children(){return [(()=>{var _el$=_$createElement2("text"),_el$2=_$createTextNode(` Navigator updated`)
24
+ _$insertNode(_el$,_el$2)
25
+ _$insert(_el$,()=>icons.icon("update"),_el$2)
26
+ _$effect((_p$)=>{var _v$=theme().text,_v$2=TextAttributes.BOLD
27
+ _v$!==_p$.e&&(_p$.e=_$setProp(_el$,"fg",_v$,_p$.e))
28
+ _v$2!==_p$.t&&(_p$.t=_$setProp(_el$,"attributes",_v$2,_p$.t))
29
+ return _p$
30
+ },{e:undefined,t:undefined
31
+ })
32
+ return _el$
33
+ })(),(()=>{var _el$3=_$createElement2("text"),_el$4=_$createTextNode(`Changes from `),_el$5=_$createTextNode(` to `)
34
+ _$insertNode(_el$3,_el$4)
35
+ _$insertNode(_el$3,_el$5)
36
+ _$insert(_el$3,()=>props.previous,_el$5)
37
+ _$insert(_el$3,()=>props.current,null)
38
+ _$effect((_$p)=>_$setProp(_el$3,"fg",theme().textMuted,_$p))
39
+ return _el$3
40
+ })(),(()=>{var _el$6=_$createElement2("scrollbox"),_el$7=_$createElement2("box")
41
+ _$insertNode(_el$6,_el$7)
42
+ _$setProp(_el$6,"scrollX",false)
43
+ _$setProp(_el$6,"horizontalScrollbarOptions",{visible:false
44
+ })
45
+ _$setProp(_el$6,"verticalScrollbarOptions",{visible:true
46
+ })
47
+ _$setProp(_el$7,"gap",1)
48
+ _$setProp(_el$7,"paddingRight",1)
49
+ _$insert(_el$7,_$createComponent2(For,{get each(){return props.entries
50
+ },children:(entry)=>(()=>{var _el$0=_$createElement2("box"),_el$1=_$createElement2("text"),_el$10=_$createTextNode(`Navigator `)
51
+ _$insertNode(_el$0,_el$1)
52
+ _$setProp(_el$0,"gap",1)
53
+ _$insertNode(_el$1,_el$10)
54
+ _$insert(_el$1,()=>entry.version,null)
55
+ _$insert(_el$0,_$createComponent2(For,{get each(){return entry.changes
56
+ },children:(change)=>(()=>{var _el$11=_$createElement2("text"),_el$12=_$createTextNode(` `)
57
+ _$insertNode(_el$11,_el$12)
58
+ _$setProp(_el$11,"wrapMode","word")
59
+ _$insert(_el$11,()=>icons.icon("selected"),_el$12)
60
+ _$insert(_el$11,change,null)
61
+ _$effect((_$p)=>_$setProp(_el$11,"fg",theme().text,_$p))
62
+ return _el$11
63
+ })()
64
+ }),null)
65
+ _$effect((_p$)=>{var _v$3=theme().accent,_v$4=TextAttributes.BOLD
66
+ _v$3!==_p$.e&&(_p$.e=_$setProp(_el$1,"fg",_v$3,_p$.e))
67
+ _v$4!==_p$.t&&(_p$.t=_$setProp(_el$1,"attributes",_v$4,_p$.t))
68
+ return _p$
69
+ },{e:undefined,t:undefined
70
+ })
71
+ return _el$0
72
+ })()
73
+ }))
74
+ _$effect((_$p)=>_$setProp(_el$6,"height",Math.max(4,Math.min(16,Math.floor(dimensions().height / 2))),_$p))
75
+ return _el$6
76
+ })(),_$createComponent2(SelectionBox,{get backgroundColor(){return theme().primary
77
+ },paddingLeft:1,paddingRight:1,onMouseDown:(event)=>event.stopPropagation(),onMouseUp:(event)=>{event.stopPropagation()
78
+ dialogs.back()
79
+ },get children(){var _el$8=_$createElement2("text")
80
+ _$insertNode(_el$8,_$createTextNode(`Continue`))
81
+ _$effect((_$p)=>_$setProp(_el$8,"fg",theme().selectedListItemText,_$p))
82
+ return _el$8
83
+ }})]
84
+ }})
85
+ }
86
+ export{UpgradeNotesDialog,changesSince2 as changesSince,readBundledChangelog2 as readBundledChangelog
87
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "opencode-navigator",
4
- "version": "0.22.0",
4
+ "version": "0.24.0",
5
5
  "description": "Search, navigate, and manage OpenCode sessions from the TUI",
6
6
  "type": "module",
7
- "packageManager": "bun@1.4.2",
7
+ "packageManager": "bun@1.4.4",
8
8
  "license": "MIT",
9
9
  "author": "St1ggy",
10
10
  "repository": {
@@ -33,9 +33,11 @@
33
33
  "scripts/install-font.mjs",
34
34
  "scripts/update-local-snapshot.mjs",
35
35
  "scripts/snapshot-runtime.mjs",
36
+ "scripts/snapshot-verifier.mjs",
36
37
  "scripts/save-project-profile.mjs",
37
38
  "README.md",
38
39
  "PROVIDERS.md",
40
+ "HOST_API.md",
39
41
  "CHANGELOG.md",
40
42
  "LICENSE"
41
43
  ],
@@ -58,7 +60,7 @@
58
60
  "access": "public"
59
61
  },
60
62
  "engines": {
61
- "opencode": ">=1.18.30"
63
+ "opencode": "1.19.5 || 2.2.5"
62
64
  },
63
65
  "scripts": {
64
66
  "build": "bun run build.ts",
@@ -81,8 +83,8 @@
81
83
  "check": "bun run test && bun run typecheck && bun run lint && bun run bundle:size && bun run format:check"
82
84
  },
83
85
  "peerDependencies": {
84
- "@opencode-ai/plugin": ">=1.18.30",
85
- "@opencode/plugin": ">=2.0.11",
86
+ "@opencode-ai/plugin": "1.19.5",
87
+ "@opencode/plugin": "2.2.5",
86
88
  "@opentui/core": ">=0.4.5",
87
89
  "@opentui/solid": ">=0.4.5",
88
90
  "solid-js": ">=1.9.12"
@@ -105,23 +107,23 @@
105
107
  }
106
108
  },
107
109
  "devDependencies": {
108
- "@opencode-ai/plugin": "1.19.3",
109
- "@opencode-ai/sdk": "1.19.3",
110
- "@opencode/plugin": "2.1.0",
111
- "@opentui/core": "0.6.6",
112
- "@opentui/keymap": "0.6.6",
113
- "@opentui/solid": "0.6.6",
110
+ "@opencode-ai/plugin": "1.19.5",
111
+ "@opencode-ai/sdk": "1.19.5",
112
+ "@opencode/plugin": "2.2.5",
113
+ "@opentui/core": "0.8.0",
114
+ "@opentui/keymap": "0.8.0",
115
+ "@opentui/solid": "0.8.0",
114
116
  "@st1ggy/linter-config": "8.0.0",
115
- "@types/bun": "1.4.2",
116
- "eslint-plugin-solid": "0.18.0",
117
- "oxfmt": "0.72.0",
118
- "oxlint": "1.87.0",
119
- "oxlint-tsgolint": "7.0.2003",
120
- "solid-js": "1.9.15",
117
+ "@types/bun": "1.4.4",
118
+ "eslint-plugin-solid": "0.18.1",
119
+ "oxfmt": "0.75.0",
120
+ "oxlint": "1.90.0",
121
+ "oxlint-tsgolint": "7.0.2005",
122
+ "solid-js": "1.9.18",
121
123
  "typescript": "6.0.3",
122
124
  "web-tree-sitter": "0.25.10"
123
125
  },
124
126
  "optionalDependencies": {
125
- "@github/copilot-sdk": "1.0.16"
127
+ "@github/copilot-sdk": "1.0.28"
126
128
  }
127
129
  }
@@ -0,0 +1,36 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+
4
+ function supports(version, minimum) {
5
+ const value = version.replace(/^v/, '').split('.').map(Number)
6
+ const required = minimum.split('.').map(Number)
7
+
8
+ for (let index = 0; index < 3; index++) {
9
+ if (value[index] !== required[index]) return value[index] > required[index]
10
+ }
11
+
12
+ return true
13
+ }
14
+
15
+ export async function snapshotVerifier(directory, probe) {
16
+ const source = await readFile(join(directory, 'dist', 'runtime-requirements.json'), 'utf8').catch((error) => {
17
+ if (error.code !== 'ENOENT') throw error
18
+ })
19
+
20
+ if (!source) return 'node'
21
+
22
+ const requirements = JSON.parse(source)
23
+
24
+ if (requirements.version !== 1 || ['bun', 'node'].some((name) => !/^\d+\.\d+\.\d+$/.test(requirements[name])))
25
+ throw new Error('Navigator package has invalid runtime requirements')
26
+
27
+ for (const runtime of ['bun', 'node']) {
28
+ const version = await probe(runtime).catch(() => '')
29
+
30
+ if (/^v?\d+\.\d+\.\d+$/.test(version.trim()) && supports(version.trim(), requirements[runtime])) return runtime
31
+ }
32
+
33
+ throw new Error(
34
+ `Snapshot verification requires Bun >=${requirements.bun} or Node >=${requirements.node}; the installed snapshot was preserved`,
35
+ )
36
+ }
@@ -6,17 +6,22 @@ import { basename, dirname, join, resolve } from 'node:path'
6
6
  import { pathToFileURL } from 'node:url'
7
7
 
8
8
  import { snapshotRuntime } from './snapshot-runtime.mjs'
9
+ import { snapshotVerifier } from './snapshot-verifier.mjs'
9
10
 
10
- function command(program, args) {
11
+ function command(program, args, capture = false) {
11
12
  return new Promise((resolveCommand, reject) => {
12
- const child = spawn(program, args, { stdio: ['ignore', 'ignore', 'pipe'] })
13
+ const child = spawn(program, args, { stdio: ['ignore', capture ? 'pipe' : 'ignore', 'pipe'] })
13
14
  let error = ''
15
+ let output = ''
16
+
17
+ child.stdout?.setEncoding('utf8')
18
+ child.stdout?.on('data', (chunk) => (output += chunk))
14
19
 
15
20
  child.stderr.setEncoding('utf8')
16
21
  child.stderr.on('data', (chunk) => (error += chunk))
17
22
  child.on('error', reject)
18
23
  child.on('close', (code) => {
19
- if (code === 0) resolveCommand()
24
+ if (code === 0) resolveCommand(output.trim())
20
25
  else reject(new Error(error.trim() || `${program} exited with code ${code}`))
21
26
  })
22
27
  })
@@ -61,6 +66,17 @@ async function validate(directory, version, { checkRuntime = true } = {}) {
61
66
  throw new Error(`Snapshot ${version} has mismatched runtime dependencies`)
62
67
  }
63
68
 
69
+ async function verifySnapshot(directory, runtime) {
70
+ const verifier = runtime ?? (await snapshotVerifier(directory, (program) => command(program, ['--version'], true)))
71
+ const importURL = JSON.stringify(pathToFileURL(join(directory, 'dist', 'tui.js')).href)
72
+
73
+ await command(verifier, [
74
+ '--input-type=module',
75
+ '--eval',
76
+ `const plugin=(await import(${importURL})).default;if(plugin?.id!=='opencode-navigator')throw Error('Invalid Navigator plugin bundle')`,
77
+ ])
78
+ }
79
+
64
80
  export async function updateLocalSnapshot(wrapper, target, operations = {}) {
65
81
  if (!/^\d+\.\d+\.\d+$/.test(target)) throw new Error('Invalid Navigator update version')
66
82
 
@@ -81,8 +97,11 @@ export async function updateLocalSnapshot(wrapper, target, operations = {}) {
81
97
  const replacement = join(root, `.tui-${randomUUID()}.tmp`)
82
98
 
83
99
  try {
84
- if (existsSync(next)) await validate(next, target)
85
- else {
100
+ if (existsSync(next)) {
101
+ await validate(next, target)
102
+
103
+ await (operations.verify ? operations.verify(next) : verifySnapshot(next))
104
+ } else {
86
105
  await mkdir(staging)
87
106
 
88
107
  if (operations.stage) await operations.stage(staging, target)
@@ -103,6 +122,10 @@ export async function updateLocalSnapshot(wrapper, target, operations = {}) {
103
122
  if (metadata.name !== 'opencode-navigator' || metadata.version !== target)
104
123
  throw new Error('Downloaded Navigator package does not match the requested version')
105
124
 
125
+ const verifier = operations.verify
126
+ ? undefined
127
+ : await snapshotVerifier(staging, (runtime) => command(runtime, ['--version'], true))
128
+
106
129
  await writeFile(
107
130
  join(staging, 'package.json'),
108
131
  JSON.stringify({
@@ -129,17 +152,7 @@ export async function updateLocalSnapshot(wrapper, target, operations = {}) {
129
152
 
130
153
  await validate(staging, target)
131
154
 
132
- if (operations.verify) await operations.verify(staging)
133
- else {
134
- const bundleURL = pathToFileURL(join(staging, 'dist', 'tui.js')).href
135
- const importURL = JSON.stringify(bundleURL)
136
-
137
- await command('node', [
138
- '--input-type=module',
139
- '--eval',
140
- `const plugin=(await import(${importURL})).default;if(plugin?.id!=='opencode-navigator')throw Error('Invalid Navigator plugin bundle')`,
141
- ])
142
- }
155
+ await (operations.verify ? operations.verify(staging) : verifySnapshot(staging, verifier))
143
156
 
144
157
  await rename(staging, next)
145
158
  }