@qvac/core 0.1.1 → 0.1.2
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/README.md +2 -2
- package/dist/assistant.bundle +5 -5
- package/package.json +7 -4
- package/tui/README.md +133 -0
- package/tui/app.mjs +4179 -0
- package/tui/index.mjs +650 -0
- package/tui/lib/boot-timing.mjs +41 -0
- package/tui/lib/busy-words.mjs +64 -0
- package/tui/lib/export.mjs +125 -0
- package/tui/lib/knowledge-command.mjs +144 -0
- package/tui/lib/knowledge-import.mjs +135 -0
- package/tui/lib/prebuilds.mjs +81 -0
- package/tui/lib/projection-env.mjs +24 -0
- package/tui/lib/render.mjs +136 -0
- package/tui/lib/save-file.mjs +71 -0
- package/tui/lib/select.mjs +63 -0
- package/tui/lib/setup.mjs +109 -0
- package/tui/lib/sidebar.mjs +52 -0
- package/tui/lib/splash-art.mjs +107 -0
- package/tui/lib/splash.mjs +19 -0
- package/tui/lib/upload-frames.mjs +10 -0
- package/tui/lib/wrap.mjs +114 -0
- package/ducks.png +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qvac/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Peer-to-peer AI across your devices",
|
|
6
6
|
"exports": {
|
|
@@ -137,11 +137,13 @@
|
|
|
137
137
|
},
|
|
138
138
|
"./dist/assistant.cjs": "./dist/assistant.cjs"
|
|
139
139
|
},
|
|
140
|
+
"bin": {
|
|
141
|
+
"duck": "./tui/index.mjs"
|
|
142
|
+
},
|
|
140
143
|
"scripts": {
|
|
141
|
-
"build:tui": "node tui/build.mjs",
|
|
142
144
|
"build:splash": "node tui/build-splash.mjs",
|
|
143
145
|
"build:schema": "bare schema/build.ts",
|
|
144
|
-
"duck": "node
|
|
146
|
+
"duck": "node scripts/build-bundle.mjs && bare tui/index.mjs",
|
|
145
147
|
"duck:warm": "bare tui/index.mjs",
|
|
146
148
|
"mesh-peer": "bare examples/mesh-peer.mjs",
|
|
147
149
|
"mesh-lab": "bare examples/mesh-lab.mjs",
|
|
@@ -217,6 +219,7 @@
|
|
|
217
219
|
},
|
|
218
220
|
"dependencies": {
|
|
219
221
|
"@qvac/harness": "^0.2.1",
|
|
222
|
+
"@qvac/skills": "^0.1.3",
|
|
220
223
|
"asenion": "^0.1.0",
|
|
221
224
|
"autobee": "2.6.0",
|
|
222
225
|
"b4a": "^1.8.1",
|
|
@@ -243,6 +246,7 @@
|
|
|
243
246
|
"bare-subprocess": "^6.1.0",
|
|
244
247
|
"bare-supervisor": "^0.1.1",
|
|
245
248
|
"bare-system-logger": "^1.0.3",
|
|
249
|
+
"bare-tui": "^0.0.3",
|
|
246
250
|
"bare-url": "^2.4.5",
|
|
247
251
|
"blind-peer": "^3.10.2",
|
|
248
252
|
"blind-peering": "^2.7.0",
|
|
@@ -284,7 +288,6 @@
|
|
|
284
288
|
"bare-runtime": "^1.30.0",
|
|
285
289
|
"bare-sidecar": "^0.5.2",
|
|
286
290
|
"bare-stow": "^0.1.4",
|
|
287
|
-
"bare-tui": "^0.0.3",
|
|
288
291
|
"brittle": "^4.0.2",
|
|
289
292
|
"holepunch-types": "^0.2.1",
|
|
290
293
|
"hyperdht": "^6.32.0",
|
package/tui/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# duck
|
|
2
|
+
|
|
3
|
+
The interactive chat TUI over `@qvac/core` — the real llama.cpp harness (via
|
|
4
|
+
`@qvac/sdk`), the real chunk stream, a real mesh.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
`duck` ships in the `@qvac/core` package, so an install puts it on PATH:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm i -g @qvac/core # duck
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
In the repo:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
bun run duck # build the assistant bundle, then run
|
|
18
|
+
bun run duck:warm # reuse the last-built bundle
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`duck` runs the SAME `dist/assistant.bundle` the desktop app ships — the stow of
|
|
22
|
+
`worker/assistant-sidecar.mjs` that `scripts/build-bundle.mjs` builds. `bun run
|
|
23
|
+
duck` rebuilds it first, because a stale bundle decodes with the old wire format
|
|
24
|
+
and dies on the first call whose encoding changed; a freshly written bundle also
|
|
25
|
+
pays a one-time cold start on its first spawn (OS page-cache miss + the
|
|
26
|
+
platform's security assessment of the new binary and its native addons). The TUI
|
|
27
|
+
host (`index.mjs`, `app.mjs`) is not in that bundle, so while iterating on the
|
|
28
|
+
TUI use `duck:warm`. Rebuild after changing any `worker/`, wire, or `lib/`
|
|
29
|
+
source.
|
|
30
|
+
|
|
31
|
+
The bundle carries its JS but not its native addons: `build-bundle.mjs` offloads
|
|
32
|
+
those beside the bundle and leaves the forest out of the tarball, shipping
|
|
33
|
+
`dist/prebuilds-manifest.json` instead. `lib/prebuilds.mjs` links this host's
|
|
34
|
+
addons back into place from the installed `node_modules` on first run — which is
|
|
35
|
+
why an installed `duck` needs no postinstall step.
|
|
36
|
+
|
|
37
|
+
`index.mjs` is the `duck` bin — a `#!/usr/bin/env bare` script, so `bare` has to
|
|
38
|
+
be on PATH (`bare-runtime` puts it in `node_modules/.bin`). `bare-tui` needs
|
|
39
|
+
Bare's native TTY; the TUI will not run under node.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
duck [--storage <dir>] [--temp] [--headless]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Flags may appear in any order. Joining a mesh is `/join qvac://mesh/…` inside
|
|
48
|
+
the app, not a boot argument.
|
|
49
|
+
|
|
50
|
+
- `--storage <dir>` — a self-contained root (its own corestore and SDK home
|
|
51
|
+
under `<dir>`). `QVAC_STORAGE` is the env fallback.
|
|
52
|
+
- `--temp` — the same, in a throwaway dir. `QVAC_TEMP=1` is the env fallback.
|
|
53
|
+
- `--headless` — brings the same stack up with no TUI: prints the mesh invite,
|
|
54
|
+
then streams logs (including the sidecar child's own output) to stdout until
|
|
55
|
+
ctrl+C. A mesh peer to point other instances at, and the only live view of
|
|
56
|
+
the boot the TUI hides.
|
|
57
|
+
|
|
58
|
+
Storage defaults to the desktop app's release root (`resolveStorage`, i.e.
|
|
59
|
+
`<platform-persistent>/qvac/dev`), so the TUI resumes the same mesh and chats
|
|
60
|
+
the desktop persists there — one at a time (the corestore is single-writer, so
|
|
61
|
+
quit the desktop first) and only across matching Core/schema versions. Models
|
|
62
|
+
stay in the shared global `~/.qvac/models`; `QVAC_ENV` picks another channel.
|
|
63
|
+
|
|
64
|
+
To run alongside another qvac app that already holds the SDK registry lock, use
|
|
65
|
+
an explicit root — it puts the SDK home and its lock on a scratch
|
|
66
|
+
`<dir>/sdk-home`. Models are still shared; `QVAC_MODEL_CACHE_PATH` isolates
|
|
67
|
+
those too.
|
|
68
|
+
|
|
69
|
+
The TUI copies its mesh invite to the clipboard on ctrl+y; a running TUI moves
|
|
70
|
+
mesh with `/join qvac://mesh/…`. See [../docs/tui-commands.md](../docs/tui-commands.md)
|
|
71
|
+
for the full command set.
|
|
72
|
+
|
|
73
|
+
## Environment
|
|
74
|
+
|
|
75
|
+
| Variable | Effect |
|
|
76
|
+
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `QVAC_MODEL` | Overrides the demo agent's model — a registry name, or a local path/URL |
|
|
78
|
+
| `QVAC_MMPROJ` | Pairs models with their mmproj projections so ctrl+V'd images reach the model natively. One value applies to every model; `model=mmproj,model2=mmproj2` pairs are per-model. `QVAC_INPROCESS=1` only |
|
|
79
|
+
| `QVAC_IMAGE_MODEL` | Enables the `generate_image`/`edit_image` tools — a catalog choice (`sd2` \| `sdxl` \| `flux2-klein`), or a local diffusion model |
|
|
80
|
+
| `QVAC_IMAGE_LLM`, `QVAC_IMAGE_VAE`, `QVAC_IMAGE_PREDICTION` | FLUX.2 is a companion set: the Qwen3 text encoder, the VAE, and `flux2_flow` (required for img2img) |
|
|
81
|
+
| `QVAC_LOG_FILE`, `QVAC_LOG_LEVEL` | Move the log file / pick the level (`debug` \| `info` \| `warn` \| `error`, default `info`) |
|
|
82
|
+
| `QVAC_BOOT_TIMING=1` | Prints the total connect time after the TUI exits. Per-stage stamps exist only under `QVAC_INPROCESS=1` — the shared assistant sidecar carries no boot timer |
|
|
83
|
+
| `QVAC_INPROCESS=1` | Runs Core and Client in this process, no sidecar — the only topology that can inject a live harness object |
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
QVAC_MODEL=~/.qvac/models/3a65a2a3c6a30a47_Qwen3.5-4B-Q4_K_M.gguf \
|
|
87
|
+
QVAC_MMPROJ=~/.qvac/models/0e037fa9ec5dddcf_Qwen3.5-4B.mmproj-Q8_0.gguf \
|
|
88
|
+
duck
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Logs (Core's own lines, and the sidecar child's piped stdout/stderr — the
|
|
92
|
+
llama.cpp and SDK output) go to `<storage.root>/assistant.log`, as they do on
|
|
93
|
+
desktop. Nothing is printed: the TUI owns the tty.
|
|
94
|
+
|
|
95
|
+
## Layout
|
|
96
|
+
|
|
97
|
+
| Path | Responsibility |
|
|
98
|
+
| ----------- | ------------------------------------------------------------------------------------------ |
|
|
99
|
+
| `index.mjs` | The `duck` bin — CLI, storage resolution, and the two topologies (sidecar, in-process) |
|
|
100
|
+
| `app.mjs` | The TUI itself — state, keys, commands, rendering |
|
|
101
|
+
| `lib/` | Leaf helpers: wrapping, selection, rendering, export, knowledge import, uploads, prebuilds |
|
|
102
|
+
|
|
103
|
+
## Splash
|
|
104
|
+
|
|
105
|
+
An empty transcript — first boot, and a fresh chat — shows `../ducks.png` as
|
|
106
|
+
half-block truecolor art, centered, with that state's own caption beneath it
|
|
107
|
+
(`starting up…`, `connecting to the mesh…`, `(say hello)`).
|
|
108
|
+
|
|
109
|
+
`lib/splash-art.mjs` is generated and committed; regenerate it when the image
|
|
110
|
+
changes:
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
bun run build:splash
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
It carries four cuts — 64x32, 48x24, 32x16 and 24x12 cells. `splash()` takes
|
|
117
|
+
the widest that fits the body and falls back to the bare caption when none
|
|
118
|
+
does, so a roomy window gets more of the illustration and a 24-row terminal
|
|
119
|
+
still gets a duck. The ladder tops out well short of a full-screen window: this
|
|
120
|
+
is a splash above the prompt, not a wallpaper.
|
|
121
|
+
|
|
122
|
+
## Busy words
|
|
123
|
+
|
|
124
|
+
A run with no model progress to report shows a duck-themed gerund instead of
|
|
125
|
+
`thinking…` — `Dabbling…`, `Pondering…`, `Quackompiling…`. The word is a pure
|
|
126
|
+
function of the run id (`lib/busy-words.mjs`), so it holds for that whole run
|
|
127
|
+
rather than flickering on every repaint, and two runs rarely land on the same
|
|
128
|
+
one. States that _do_ have something to report keep saying it (`loading X…`,
|
|
129
|
+
`downloading X: 40%`).
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
Apache-2.0
|