@pellux/goodvibes-tui 1.14.0 → 1.15.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 +8 -0
- package/README.md +1 -1
- package/package.json +5 -5
- package/src/input/commands/update-runtime.ts +54 -5
- package/src/runtime/release-artifacts.ts +30 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to GoodVibes TUI.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.15.0] — 2026-07-11
|
|
8
|
+
|
|
9
|
+
### Changes
|
|
10
|
+
- e95c369d fix(install): treat a release without a sqlite-vec manifest entry as pre-addon
|
|
11
|
+
- 86c1cd9c feat(install): ship the sqlite-vec native addon to pure-binary installs
|
|
12
|
+
- b5590ef3 install.sh: install goodvibes-agent as a checksum-verified compiled binary; restart a running agent post-install
|
|
13
|
+
- f0860827 install.sh: restart a running daemon after the binary swap so the curl one-liner works as an upgrade
|
|
14
|
+
|
|
7
15
|
## [1.14.0] — 2026-07-11
|
|
8
16
|
|
|
9
17
|
### Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/mgd34msu/goodvibes-tui/actions/workflows/ci.yml)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/mgd34msu/goodvibes-tui)
|
|
6
6
|
|
|
7
7
|
A terminal-native AI coding, operations, automation, knowledge, and integration console with a typed runtime, omnichannel surfaces, structured memory/knowledge, and a raw ANSI renderer.
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-tui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Terminal-native GoodVibes product for coding, operations, automation, knowledge, channels, and daemon-backed control-plane workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.ts",
|
|
@@ -131,10 +131,10 @@
|
|
|
131
131
|
"typescript": "^5.9.3"
|
|
132
132
|
},
|
|
133
133
|
"optionalDependencies": {
|
|
134
|
-
"@pellux/goodvibes-tui-linux-x64": "1.
|
|
135
|
-
"@pellux/goodvibes-tui-linux-arm64": "1.
|
|
136
|
-
"@pellux/goodvibes-tui-darwin-x64": "1.
|
|
137
|
-
"@pellux/goodvibes-tui-darwin-arm64": "1.
|
|
134
|
+
"@pellux/goodvibes-tui-linux-x64": "1.15.0",
|
|
135
|
+
"@pellux/goodvibes-tui-linux-arm64": "1.15.0",
|
|
136
|
+
"@pellux/goodvibes-tui-darwin-x64": "1.15.0",
|
|
137
|
+
"@pellux/goodvibes-tui-darwin-arm64": "1.15.0"
|
|
138
138
|
},
|
|
139
139
|
"trustedDependencies": [],
|
|
140
140
|
"overrides": {
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* whether this build is already current.
|
|
10
10
|
* /update apply — for a binary install (scripts/install.sh),
|
|
11
11
|
* download + verify + atomically swap the
|
|
12
|
-
* app and daemon binaries
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* app and daemon binaries, and refresh the
|
|
13
|
+
* sqlite-vec native addon in lockstep so the
|
|
14
|
+
* vector index never goes stale beside a new
|
|
15
|
+
* binary. For any other install kind, prints the
|
|
16
|
+
* exact command to run instead — it never
|
|
17
|
+
* attempts a swap it can't do safely.
|
|
16
18
|
* /update review — install/subscription/sandbox posture,
|
|
17
19
|
* unrelated to the update mechanics above.
|
|
18
20
|
* /update bundle export|inspect <path> — portable posture bundle, as before.
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
CHECKSUM_MANIFEST_NAME,
|
|
35
37
|
parseChecksumFile,
|
|
36
38
|
resolveArtifactNames,
|
|
39
|
+
resolveSqliteVecAsset,
|
|
37
40
|
sha256,
|
|
38
41
|
verifyChecksum,
|
|
39
42
|
} from '../../runtime/release-artifacts.ts';
|
|
@@ -87,6 +90,24 @@ function swapBinaryAtomically(targetPath: string, buffer: Buffer): void {
|
|
|
87
90
|
renameSync(tempPath, targetPath);
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Writes the sqlite-vec native addon into place with the same temp-write +
|
|
95
|
+
* atomic-rename discipline as the binaries, so a running process never
|
|
96
|
+
* dlopen()s a half-written extension. The addon's parent directory
|
|
97
|
+
* (`<execDir>/lib/sqlite-vec-<os>-<arch>/`) is created first because a fresh
|
|
98
|
+
* install may not have a `lib/` tree yet. A shared library needs no execute
|
|
99
|
+
* bit, so this uses 0o644 rather than the binaries' 0o755.
|
|
100
|
+
*/
|
|
101
|
+
function writeAddonAtomically(targetPath: string, buffer: Buffer): void {
|
|
102
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
103
|
+
const tempPath = `${targetPath}.update-download`;
|
|
104
|
+
writeFileSync(tempPath, buffer);
|
|
105
|
+
if (process.platform !== 'win32') {
|
|
106
|
+
chmodSync(tempPath, 0o644);
|
|
107
|
+
}
|
|
108
|
+
renameSync(tempPath, targetPath);
|
|
109
|
+
}
|
|
110
|
+
|
|
90
111
|
export interface DaemonServiceRestartInfo {
|
|
91
112
|
readonly managed: boolean;
|
|
92
113
|
readonly unitName: string;
|
|
@@ -150,6 +171,8 @@ export interface ApplyUpdateOptions {
|
|
|
150
171
|
readonly runCommand?: RunCommand;
|
|
151
172
|
/** Injectable so tests can observe/skip the actual filesystem swap. */
|
|
152
173
|
readonly swap?: (targetPath: string, buffer: Buffer) => void;
|
|
174
|
+
/** Injectable so tests can observe/skip writing the sqlite-vec addon. */
|
|
175
|
+
readonly writeAddon?: (targetPath: string, buffer: Buffer) => void;
|
|
153
176
|
readonly fileExists?: (path: string) => boolean;
|
|
154
177
|
}
|
|
155
178
|
|
|
@@ -205,12 +228,37 @@ export async function applyUpdate(options: ApplyUpdateOptions): Promise<void> {
|
|
|
205
228
|
verifyChecksum(artifacts.daemon, sha256(daemonBuffer), checksums.get(artifacts.daemon));
|
|
206
229
|
}
|
|
207
230
|
|
|
208
|
-
//
|
|
231
|
+
// The sqlite-vec native addon travels with the binaries: refresh it in the
|
|
232
|
+
// same download-verify-swap pass so /update never leaves a new binary beside a
|
|
233
|
+
// stale addon. It lands at <execDir>/lib/sqlite-vec-<os>-<arch>/vec0.<suffix>,
|
|
234
|
+
// exactly where the SDK's loader resolves it. The manifest entry decides
|
|
235
|
+
// whether the target release ships it — an entry that IS present makes the
|
|
236
|
+
// download and checksum mandatory (a mismatch is fatal, verified before any
|
|
237
|
+
// swap), while an absent entry means the target predates the addon and is
|
|
238
|
+
// skipped rather than blocking an otherwise-valid binary update. On macOS the
|
|
239
|
+
// file is refreshed for consistency even though the platform blocks extension
|
|
240
|
+
// loading.
|
|
241
|
+
const addon = resolveSqliteVecAsset(options.platform, options.arch);
|
|
242
|
+
const addonExpected = addon ? checksums.get(addon.assetName) : undefined;
|
|
243
|
+
let addonBuffer: Buffer | null = null;
|
|
244
|
+
if (addon && addonExpected !== undefined) {
|
|
245
|
+
addonBuffer = await downloadBuffer(options.fetchImpl, `${baseUrl}/${addon.assetName}`);
|
|
246
|
+
verifyChecksum(addon.assetName, sha256(addonBuffer), addonExpected);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// All downloads verified before any write — an update must not apply partially.
|
|
209
250
|
const swap = options.swap ?? swapBinaryAtomically;
|
|
210
251
|
swap(appBinaryPath, appBuffer);
|
|
211
252
|
if (daemonBuffer) {
|
|
212
253
|
swap(daemonBinaryPath, daemonBuffer);
|
|
213
254
|
}
|
|
255
|
+
const addonTargetPath = addon && addonBuffer
|
|
256
|
+
? join(dirname(appBinaryPath), 'lib', addon.dirName, addon.fileName)
|
|
257
|
+
: null;
|
|
258
|
+
if (addonBuffer && addonTargetPath) {
|
|
259
|
+
const writeAddon = options.writeAddon ?? writeAddonAtomically;
|
|
260
|
+
writeAddon(addonTargetPath, addonBuffer);
|
|
261
|
+
}
|
|
214
262
|
|
|
215
263
|
const serviceInfo = detectDaemonServiceManaged(options.platform, options.configManager, options.runCommand);
|
|
216
264
|
|
|
@@ -221,6 +269,7 @@ export async function applyUpdate(options: ApplyUpdateOptions): Promise<void> {
|
|
|
221
269
|
daemonBinaryPresent
|
|
222
270
|
? ` daemon binary: ${daemonBinaryPath}`
|
|
223
271
|
: ` daemon binary: not found at ${daemonBinaryPath} — left untouched`,
|
|
272
|
+
...(addonTargetPath ? [` vector addon: ${addonTargetPath}`] : []),
|
|
224
273
|
'',
|
|
225
274
|
'Restart goodvibes to run the new version.',
|
|
226
275
|
serviceInfo.managed
|
|
@@ -42,6 +42,36 @@ export function resolveArtifactNames(platform: string, arch: string): ReleaseArt
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export interface SqliteVecAsset {
|
|
46
|
+
/** Release asset filename, e.g. `sqlite-vec-linux-x64.so`. */
|
|
47
|
+
readonly assetName: string;
|
|
48
|
+
/** Directory name the SDK loader resolves, e.g. `sqlite-vec-linux-x64`. */
|
|
49
|
+
readonly dirName: string;
|
|
50
|
+
/** File the loader opens inside that directory, e.g. `vec0.so`. */
|
|
51
|
+
readonly fileName: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Names the sqlite-vec native addon for a platform/arch. Unlike the binaries
|
|
56
|
+
* (whose release tag maps darwin→"macos"), the addon keeps the Node-style
|
|
57
|
+
* platform tag ("linux" | "darwin") because that is exactly what the SDK's
|
|
58
|
+
* loader resolves at `<execDir>/lib/sqlite-vec-<process.platform>-<process.arch>/vec0.<suffix>`.
|
|
59
|
+
* The scripts/install.sh installer and the release workflow name the asset the
|
|
60
|
+
* same way; all three must stay in lockstep.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveSqliteVecAsset(platform: string, arch: string): SqliteVecAsset | null {
|
|
63
|
+
if ((platform !== 'linux' && platform !== 'darwin') || (arch !== 'x64' && arch !== 'arm64')) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const suffix = platform === 'darwin' ? 'dylib' : 'so';
|
|
67
|
+
const dirName = `sqlite-vec-${platform}-${arch}`;
|
|
68
|
+
return {
|
|
69
|
+
assetName: `${dirName}.${suffix}`,
|
|
70
|
+
dirName,
|
|
71
|
+
fileName: `vec0.${suffix}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
45
75
|
export function sha256(buffer: Buffer | Uint8Array): string {
|
|
46
76
|
return createHash('sha256').update(buffer).digest('hex');
|
|
47
77
|
}
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.
|
|
9
|
+
let _version = '1.15.0';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
_version = pkg.version ?? _version;
|