@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/core",
3
- "version": "0.1.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 tui/build.mjs && bare tui/index.mjs",
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