opencode-navigator 0.17.1 → 0.17.3
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 +10 -5
- package/README.md +18 -1
- package/dist/tui.js +1367 -1327
- package/package.json +2 -1
- package/scripts/update-local-snapshot.mjs +152 -0
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.17.
|
|
4
|
+
"version": "0.17.3",
|
|
5
5
|
"description": "Search, navigate, and manage OpenCode sessions from the TUI",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"packageManager": "bun@1.4.2",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"dist",
|
|
30
30
|
"assets",
|
|
31
31
|
"scripts/install-font.mjs",
|
|
32
|
+
"scripts/update-local-snapshot.mjs",
|
|
32
33
|
"README.md",
|
|
33
34
|
"CHANGELOG.md",
|
|
34
35
|
"LICENSE"
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { randomUUID } from 'node:crypto'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
|
|
5
|
+
import { basename, dirname, join, resolve } from 'node:path'
|
|
6
|
+
import { pathToFileURL } from 'node:url'
|
|
7
|
+
|
|
8
|
+
function command(program, args) {
|
|
9
|
+
return new Promise((resolveCommand, reject) => {
|
|
10
|
+
const child = spawn(program, args, { stdio: ['ignore', 'ignore', 'pipe'] })
|
|
11
|
+
let error = ''
|
|
12
|
+
|
|
13
|
+
child.stderr.setEncoding('utf8')
|
|
14
|
+
child.stderr.on('data', (chunk) => (error += chunk))
|
|
15
|
+
child.on('error', reject)
|
|
16
|
+
child.on('close', (code) => {
|
|
17
|
+
if (code === 0) resolveCommand()
|
|
18
|
+
else reject(new Error(error.trim() || `${program} exited with code ${code}`))
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function pinnedSnapshot(wrapper, read = readFile) {
|
|
24
|
+
if (basename(wrapper) !== 'tui.js' || basename(dirname(wrapper)) !== 'opencode-navigator')
|
|
25
|
+
throw new Error('This local Navigator source is not a recognized pinned snapshot')
|
|
26
|
+
|
|
27
|
+
return read(wrapper, 'utf8').then((source) => {
|
|
28
|
+
const match = /^export \{ default \} from "\.\/releases\/v(\d+\.\d+\.\d+)\/dist\/tui\.js";\s*$/.exec(source)
|
|
29
|
+
|
|
30
|
+
if (!match) throw new Error('This local Navigator source is not a recognized pinned snapshot')
|
|
31
|
+
|
|
32
|
+
return { root: dirname(wrapper), version: match[1], source }
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function validate(directory, version) {
|
|
37
|
+
const metadata = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8'))
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
metadata.version !== version ||
|
|
41
|
+
!existsSync(join(directory, 'dist', 'tui.js')) ||
|
|
42
|
+
!existsSync(join(directory, 'node_modules', '@opentui', 'core')) ||
|
|
43
|
+
!existsSync(join(directory, 'node_modules', '@opentui', 'solid')) ||
|
|
44
|
+
!existsSync(join(directory, 'node_modules', 'solid-js'))
|
|
45
|
+
)
|
|
46
|
+
throw new Error(`Snapshot ${version} is incomplete`)
|
|
47
|
+
|
|
48
|
+
const changelog = await readFile(join(directory, 'CHANGELOG.md'), 'utf8')
|
|
49
|
+
|
|
50
|
+
if (!changelog.includes(`## [${version}]`)) throw new Error(`Snapshot ${version} has no bundled changelog entry`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function updateLocalSnapshot(wrapper, target, operations = {}) {
|
|
54
|
+
if (!/^\d+\.\d+\.\d+$/.test(target)) throw new Error('Invalid Navigator update version')
|
|
55
|
+
|
|
56
|
+
const { root, version, source } = await pinnedSnapshot(resolve(wrapper))
|
|
57
|
+
const previous = join(root, 'releases', `v${version}`)
|
|
58
|
+
const next = join(root, 'releases', `v${target}`)
|
|
59
|
+
|
|
60
|
+
if (target === version) return
|
|
61
|
+
|
|
62
|
+
await validate(previous, version)
|
|
63
|
+
const dependencies = JSON.parse(await readFile(join(previous, 'package.json'), 'utf8')).dependencies
|
|
64
|
+
|
|
65
|
+
if (!dependencies?.['@opentui/core'] || !dependencies['@opentui/solid'] || !dependencies['solid-js'])
|
|
66
|
+
throw new Error('Pinned Navigator runtime dependencies are missing')
|
|
67
|
+
|
|
68
|
+
const staging = join(root, 'releases', `.v${target}-${randomUUID()}.tmp`)
|
|
69
|
+
const replacement = join(root, `.tui-${randomUUID()}.tmp`)
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
if (existsSync(next)) await validate(next, target)
|
|
73
|
+
else {
|
|
74
|
+
await mkdir(staging)
|
|
75
|
+
|
|
76
|
+
if (operations.stage) await operations.stage(staging, target)
|
|
77
|
+
else {
|
|
78
|
+
await command('npm', ['pack', `opencode-navigator@${target}`, '--pack-destination', staging, '--silent'])
|
|
79
|
+
await command('tar', [
|
|
80
|
+
'-xzf',
|
|
81
|
+
join(staging, `opencode-navigator-${target}.tgz`),
|
|
82
|
+
'-C',
|
|
83
|
+
staging,
|
|
84
|
+
'--strip-components=1',
|
|
85
|
+
])
|
|
86
|
+
await rm(join(staging, `opencode-navigator-${target}.tgz`))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const metadata = JSON.parse(await readFile(join(staging, 'package.json'), 'utf8'))
|
|
90
|
+
|
|
91
|
+
if (metadata.name !== 'opencode-navigator' || metadata.version !== target)
|
|
92
|
+
throw new Error('Downloaded Navigator package does not match the requested version')
|
|
93
|
+
|
|
94
|
+
await writeFile(
|
|
95
|
+
join(staging, 'package.json'),
|
|
96
|
+
JSON.stringify({
|
|
97
|
+
name: 'opencode-navigator-local-snapshot',
|
|
98
|
+
version: target,
|
|
99
|
+
private: true,
|
|
100
|
+
type: 'module',
|
|
101
|
+
dependencies,
|
|
102
|
+
}),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if (operations.install) await operations.install(staging)
|
|
106
|
+
else
|
|
107
|
+
await command('npm', [
|
|
108
|
+
'install',
|
|
109
|
+
'--prefix',
|
|
110
|
+
staging,
|
|
111
|
+
'--omit=dev',
|
|
112
|
+
'--ignore-scripts',
|
|
113
|
+
'--no-package-lock',
|
|
114
|
+
'--legacy-peer-deps',
|
|
115
|
+
])
|
|
116
|
+
|
|
117
|
+
await validate(staging, target)
|
|
118
|
+
|
|
119
|
+
if (operations.verify) await operations.verify(staging)
|
|
120
|
+
else {
|
|
121
|
+
const bundleURL = pathToFileURL(join(staging, 'dist', 'tui.js')).href
|
|
122
|
+
const importURL = JSON.stringify(bundleURL)
|
|
123
|
+
|
|
124
|
+
await command('node', [
|
|
125
|
+
'--input-type=module',
|
|
126
|
+
'--eval',
|
|
127
|
+
`const plugin=(await import(${importURL})).default;if(plugin?.id!=='opencode-navigator')throw Error('Invalid Navigator plugin bundle')`,
|
|
128
|
+
])
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await rename(staging, next)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if ((await readFile(wrapper, 'utf8')) !== source)
|
|
135
|
+
throw new Error('Navigator source changed during the update; restart OpenCode and retry')
|
|
136
|
+
|
|
137
|
+
await writeFile(replacement, `export { default } from "./releases/v${target}/dist/tui.js";\n`)
|
|
138
|
+
await rename(replacement, wrapper)
|
|
139
|
+
} finally {
|
|
140
|
+
await rm(staging, { recursive: true, force: true })
|
|
141
|
+
await rm(replacement, { force: true })
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
|
146
|
+
try {
|
|
147
|
+
await updateLocalSnapshot(process.argv[2], process.argv[3])
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
150
|
+
process.exitCode = 1
|
|
151
|
+
}
|
|
152
|
+
}
|