@turmind/halo 0.1.9 → 0.2.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/README.md +1 -5
- package/admin-out/404.html +1 -1
- package/admin-out/_next/static/chunks/298-4fac7d44a7949eec.js +1 -0
- package/admin-out/_next/static/chunks/{503-7c6d9935df6e0cea.js → 307-d7a99f9a4a436ec3.js} +1 -1
- package/admin-out/_next/static/chunks/app/page-b12a2e8e48fe4ea0.js +1 -0
- package/admin-out/_next/static/css/{8fce4e1a54dac12a.css → 372e3dbd4a0d1c25.css} +1 -1
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +4 -4
- package/bundled-docs/dev/acp-adapter.md +5 -4
- package/bundled-docs/dev/desktop-packaging.md +94 -8
- package/bundled-docs/guide/getting-started.md +3 -2
- package/bundled-docs/requirements/explorer.md +11 -0
- package/dist/index.js +13373 -13246
- package/package.json +1 -1
- package/templates/agents/executor/agent.yaml +2 -2
- package/templates/models/aws-bedrock-claude-invoke.yaml +26 -0
- package/templates/skills/acp/SKILL.md +8 -1
- package/templates/skills/acp/templates/SKILL.md.tmpl +2 -1
- package/templates/skills/acp/templates/ask.py +2 -1
- package/templates/skills/acp/templates/config.yaml.tmpl +5 -0
- package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +0 -1
- package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +0 -1
- package/bundled-docs/plans/cron-tasks.md +0 -362
- package/bundled-docs/plans/design-suggestions.md +0 -203
- package/bundled-docs/plans/issue-session-deep-nesting.md +0 -208
- package/bundled-docs/plans/launch-plan.md +0 -111
- package/bundled-docs/plans/md-and-agent-refactor.md +0 -197
- package/bundled-docs/plans/remote-mac-worker.md +0 -196
- package/bundled-docs/plans/roadmap.md +0 -40
- package/bundled-docs/plans/self-evolution.md +0 -1379
- package/bundled-docs/plans/todo.md +0 -32
- package/bundled-docs/plans/weixin-channel.md +0 -255
- package/bundled-docs/test/docs-seeding.md +0 -101
- package/bundled-docs/test/session.md +0 -374
- /package/admin-out/_next/static/{IBP_mwBDf-cPwZSZZGpi8 → ep7BWneNhTuIPwJfFFh72}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{IBP_mwBDf-cPwZSZZGpi8 → ep7BWneNhTuIPwJfFFh72}/_ssgManifest.js +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# Desktop Packaging (Electron / DMG)
|
|
2
2
|
|
|
3
|
-
How to build the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
How to build the desktop app. We ship two artifacts: **Windows x64**
|
|
4
|
+
(`Halo Setup <ver>.exe`, built on a Linux host) and **macOS arm64**
|
|
5
|
+
(`Halo-<ver>-arm64.dmg`, built on Apple Silicon) — see the target matrix
|
|
6
|
+
below. The desktop build is a thin Electron shell (`packages/desktop`) that
|
|
7
|
+
bundles a self-contained server runtime + a private `node` binary + the admin
|
|
8
|
+
static export, then spawns the server as a child process and points a
|
|
9
|
+
`BrowserWindow` at it.
|
|
7
10
|
|
|
8
11
|
See [design](../design/) for the server itself; this doc is only about the
|
|
9
12
|
packaging pipeline.
|
|
@@ -36,6 +39,13 @@ one.
|
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
41
|
cd packages/halo # repo root
|
|
42
|
+
# 0. VERSION GATE — confirm every package is on the release version BEFORE
|
|
43
|
+
# building or tagging. The five packages must move in lockstep; a single
|
|
44
|
+
# lagging one ships a mismatched build and a wrong `halo --version`.
|
|
45
|
+
for f in packages/{core,server,admin,cli,desktop}/package.json; do
|
|
46
|
+
printf "%-32s " "$f:"; grep -m1 '"version"' "$f"
|
|
47
|
+
done # all five must read the same x.y.z, and match the tag you're about to cut
|
|
48
|
+
|
|
39
49
|
# 1. build the upstream artifacts the stage script consumes, IN ORDER.
|
|
40
50
|
# - core MUST build before server: server imports @turmind/halo-core
|
|
41
51
|
# (e.g. GitManager in routes/git.ts). A stale/missing core/dist makes
|
|
@@ -58,8 +68,47 @@ Output: `packages/desktop/dist/Halo-0.1.5-arm64.dmg` (~143 MB).
|
|
|
58
68
|
`gen-icon` → `prepack-dmg` (`scripts/stage-runtime.mjs`) → `electron-builder
|
|
59
69
|
--mac --arm64`.
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
## Release target matrix (current policy)
|
|
72
|
+
|
|
73
|
+
Two shipped artifacts per release, each built on its native-ish host:
|
|
74
|
+
|
|
75
|
+
| Target | Host we build on | Command | Notes |
|
|
76
|
+
|--------|------------------|---------|-------|
|
|
77
|
+
| **Windows x64** (`Halo Setup <ver>.exe`, nsis) | **Linux x86_64** | `HALO_STAGE_FULL=1 CI=true pnpm dist:win` | host arch == target arch (x64), so native fixups are low-risk. This is now the standard path — *not* cross-staged from mac. |
|
|
78
|
+
| **macOS arm64** (`Halo-<ver>-arm64.dmg`) | macOS (Apple Silicon) | `CI=true pnpm dist:arm64` | Apple Silicon only. |
|
|
79
|
+
|
|
80
|
+
**`pnpm dist:x64` (Intel mac) is retired — we no longer ship an Intel build.**
|
|
81
|
+
The `dist:x64` script still exists in `package.json` but is not part of any
|
|
82
|
+
release; don't cut one.
|
|
83
|
+
|
|
84
|
+
### Building the Windows exe on Linux (the standard path)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# from repo root — build upstream artifacts in order (see step 1 below), then:
|
|
88
|
+
cd packages/desktop
|
|
89
|
+
HALO_STAGE_FULL=1 CI=true pnpm dist:win
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`HALO_STAGE_FULL=1` is **mandatory** here: a cross-stage must re-run the
|
|
93
|
+
per-target native fixups (`@parcel/watcher-win32-x64` swap, `better-sqlite3`
|
|
94
|
+
win prebuild), which the fast path skips. `wine` must be installed (electron-
|
|
95
|
+
builder runs the nsis maker through it).
|
|
96
|
+
|
|
97
|
+
Verified on the v0.1.9 build (Linux x86_64 host → win-x64):
|
|
98
|
+
- **No poisoned arm64 dmg to discard.** Unlike a mac host, a Linux `--win` run
|
|
99
|
+
never triggers the yml's mac target — `dist/` contains only `Halo Setup
|
|
100
|
+
<ver>.exe` + `.exe.blockmap` + `win-unpacked/`. The "discard the stray
|
|
101
|
+
arm64 dmg" gotcha below is mac-host-only.
|
|
102
|
+
- **Native arch check** — every staged `.node` must be PE32+ x86-64, no ELF:
|
|
103
|
+
`find dist/win-unpacked -path '*watcher-*' -name '*.node' | xargs file` and
|
|
104
|
+
`file dist/win-unpacked/resources/node.exe` (should read `PE32+ ... x86-64`).
|
|
105
|
+
- **Two benign warnings**, both expected: `file source doesn't exist
|
|
106
|
+
from=.../resources/node` (win bundles `node.exe`, not the Unix `node` — the
|
|
107
|
+
yml lists both, electron-builder skips the absent one) and `signing is
|
|
108
|
+
skipped` (no Windows code-sign cert). Neither fails the build.
|
|
109
|
+
|
|
110
|
+
> A `desktop-packaging.local.md` (gitignored, per-host) may carry extra
|
|
111
|
+
> machine-specific setup — read it first if present.
|
|
63
112
|
|
|
64
113
|
## Faster rebuilds
|
|
65
114
|
|
|
@@ -138,8 +187,10 @@ Still good practice: build server + admin **before** `pnpm dist:arm64`.
|
|
|
138
187
|
2. **Copy `templates/`** — `pnpm deploy` doesn't pick these up; copied
|
|
139
188
|
explicitly. This is what carries the built-in skills (incl. `send-file`),
|
|
140
189
|
agents, prompts, models into the dmg.
|
|
141
|
-
3. **
|
|
142
|
-
`
|
|
190
|
+
3. **Native fixup** — re-fetch `better-sqlite3` prebuilds via `prebuild-install
|
|
191
|
+
--target=22.11.0` **unconditionally** (pins the ABI to the bundled node
|
|
192
|
+
regardless of the build host's node — see the ABI gotcha below);
|
|
193
|
+
`@parcel/watcher`'s per-platform binary is swapped only when cross-staging.
|
|
143
194
|
4. **Trim bloat** — drop non-target `node-pty` prebuilds, `better-sqlite3`'s
|
|
144
195
|
C source, and the server's `src/`/`tests/`.
|
|
145
196
|
5. **Copy `admin-out/`** — the Next.js static export.
|
|
@@ -147,6 +198,9 @@ Still good practice: build server + admin **before** `pnpm dist:arm64`.
|
|
|
147
198
|
nodejs.org, extract the `node` binary into `resources/`.
|
|
148
199
|
7. **codesign (ad-hoc)** — `codesign --force --sign -` on the node binary for
|
|
149
200
|
Gatekeeper. **We deliberately do NOT `strip`** — see gotcha below.
|
|
201
|
+
8. **Native-addon smoke test** — load the staged better-sqlite3 with the
|
|
202
|
+
bundled node binary; abort the build if it can't `dlopen` (the ABI backstop,
|
|
203
|
+
runs on full and fast paths). See the ABI gotcha below.
|
|
150
204
|
|
|
151
205
|
## Gotchas (learned the hard way)
|
|
152
206
|
|
|
@@ -178,6 +232,28 @@ Still good practice: build server + admin **before** `pnpm dist:arm64`.
|
|
|
178
232
|
looks fine but won't boot. Keep the full ~114 MB binary; the ~30 MB saved
|
|
179
233
|
isn't worth a dead app. (`stage-runtime.mjs` has the strip step removed.)
|
|
180
234
|
|
|
235
|
+
- **better-sqlite3's ABI must match the BUNDLED node (22.11.0 / ABI 127), not
|
|
236
|
+
the build host's node.** `pnpm deploy` / `npm install` hard-link whatever
|
|
237
|
+
`.node` the build host's *active* node produced. If a homebrew/nvm node 23
|
|
238
|
+
(ABI 131) shadows the pinned 22 on the build machine, the staged
|
|
239
|
+
`better_sqlite3.node` is ABI 131 — but the app runs it on the bundled node 22,
|
|
240
|
+
so it dies at launch with `NODE_MODULE_VERSION 131 ... requires 127`
|
|
241
|
+
(`ERR_DLOPEN_FAILED`, server `code=1`). The dmg packages fine and runs on the
|
|
242
|
+
builder's own machine (whose node happens to match), so it ships broken to
|
|
243
|
+
everyone else. Three guards now prevent this, all in `stage-runtime.mjs`:
|
|
244
|
+
1. `fetchTargetArchNatives()` runs `prebuild-install --target=22.11.0` for
|
|
245
|
+
better-sqlite3 **unconditionally** (not just when cross-staging), so the
|
|
246
|
+
ABI is always re-pinned to the bundled node regardless of the host node.
|
|
247
|
+
2. An early gate aborts if the build host's node major ≠ the bundled major
|
|
248
|
+
(`nvm use 22` then rebuild; override with `HALO_SKIP_NODE_CHECK=1`).
|
|
249
|
+
3. `smokeTestNativeAddons()` loads the staged better-sqlite3 with the bundled
|
|
250
|
+
node binary at the end of every stage (full AND fast) and aborts the build
|
|
251
|
+
if it can't `dlopen` — the final backstop no matter how a bad ABI crept in
|
|
252
|
+
(wrong host node, a fast path reusing a stale tree, a future native dep).
|
|
253
|
+
Verify a built dmg manually: `"<app>/Contents/Resources/node" -e
|
|
254
|
+
"new (require('<app>/Contents/Resources/server-runtime/node_modules/better-sqlite3'))(':memory:')"`
|
|
255
|
+
should exit 0.
|
|
256
|
+
|
|
181
257
|
- **Desktop port is sequential from 9527 (NOT random), and that's load-bearing
|
|
182
258
|
for persistence.** `main.cjs` `findFreePort()` tries 9527 first, then scans
|
|
183
259
|
upward for the first free one, and passes it to the server child. It used to
|
|
@@ -236,6 +312,16 @@ Still good practice: build server + admin **before** `pnpm dist:arm64`.
|
|
|
236
312
|
with `&& node scripts/copy-monaco.mjs`. If you must run `next build`
|
|
237
313
|
directly, append the copy step yourself.
|
|
238
314
|
|
|
315
|
+
- **All five package versions must move in lockstep — check before building or
|
|
316
|
+
tagging.** `core` / `server` / `admin` / `cli` / `desktop` each carry their own
|
|
317
|
+
`version` in `package.json`, and nothing auto-syncs them. When cutting 0.1.9,
|
|
318
|
+
`cli` + `desktop` were already bumped by hand but `server` sat at 0.1.8 and
|
|
319
|
+
`core` / `admin` at 0.1.0 — a `git tag` then would have shipped a build whose
|
|
320
|
+
`halo --version` (stamped from `package.json`) disagreed with the tag. The
|
|
321
|
+
step-0 version gate in "One-shot build" loops over all five so a lagging one is
|
|
322
|
+
caught before the tag is cut. (npm only publishes `cli` as `@turmind/halo`, but
|
|
323
|
+
the others feed `halo --version` / the admin sidebar, so they still matter.)
|
|
324
|
+
|
|
239
325
|
- **Changing anything under `templates/` requires bumping `TEMPLATE_VERSION`
|
|
240
326
|
(`packages/server/src/init.ts`) — otherwise the change never reaches existing
|
|
241
327
|
installs.** Server startup only re-runs `ensureHaloHome` (the template
|
|
@@ -6,8 +6,9 @@ What to do the first time you open Halo.
|
|
|
6
6
|
|
|
7
7
|
Open `http://localhost:9527` (or your deployment URL) in a browser and enter the password.
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
9
|
+
- Set the password during `halo setup` (interactive) — it's stored as a scrypt hash in `~/.halo/secrets/config.yaml`
|
|
10
|
+
- Or supply it via the `HALO_PASSWORD` env var (handy for CI / Docker), which takes precedence over the stored hash
|
|
11
|
+
- If neither is set, the server refuses to start (it prints `admin password not configured` and exits)
|
|
11
12
|
|
|
12
13
|
## Open a workspace
|
|
13
14
|
|
|
@@ -12,6 +12,16 @@ VS Code-style file tree sidebar with multi-select, drag-drop, right-click menu.
|
|
|
12
12
|
### Path input
|
|
13
13
|
- Explorer top bar has a path input + 📁🔍 picker button
|
|
14
14
|
- Pressing Enter calls `GET /api/fs/exists?path=...` first — a miss shows an alert, no switch
|
|
15
|
+
- **Recent-workspaces dropdown**: focusing the input shows the most-recently-used list; typing filters it by substring. Each row shows the folder name + full path; clicking one switches to it; a hover "×" removes a single entry. Entries are recorded only after a switch validates the path (so invalid paths never land), in canonical resolved form, MRU-ordered and deduped, capped at 8. Persisted in localStorage (`halo_recent_workspaces`)
|
|
16
|
+
|
|
17
|
+
### Desktop windows (multi-window)
|
|
18
|
+
Desktop app only — the browser has one tab per window natively.
|
|
19
|
+
- **New window**: `Cmd+N` (macOS, via the File menu) / `Ctrl+N` (Windows/Linux, bound at the webContents level since those platforms have no app menu). Each window is a fresh view onto the **one shared local server** — no second server process spawns.
|
|
20
|
+
- **Per-window workspace**: windows share the server origin, hence one localStorage, so a window tracks its own workspace via its URL `?folder=` (not localStorage, which would clobber across windows). Different windows can sit on different workspaces; the same workspace can be open in two windows.
|
|
21
|
+
- **Quit semantics** (platform split): on macOS, closing every window keeps the app in the Dock (only `Cmd+Q` truly exits) and clicking the Dock icon reopens a window; on Windows/Linux there's no Dock to resummon from, so closing the last window quits.
|
|
22
|
+
- **Pin (always-on-top)** acts per-window — each window pins independently.
|
|
23
|
+
- **Activity awareness**: while the agent streams a reply the sidebar's workspace name carries an amber pulsing dot (emerald when idle) and the window title gains a `●` prefix (`● Halo — <name>` busy vs `Halo — <name>` idle) — both are plain web behaviour that Electron mirrors to the native title bar.
|
|
24
|
+
- **Finish notification** (works in both the desktop app and a plain browser): an opt-in bell toggle sits in the activity bar next to the pin, **off by default**, persisted per-machine in localStorage (`halo_notify_on_finish`). It's shown whenever a notification can be raised — the desktop shell (`window.haloNotify` bridge) or a browser with the Web Notification API; turning it on in a browser requests Notification permission from within the toggle click (the required user gesture). When on, the busy→idle edge of the *same* still-open session triggers two decoupled cues: a **self-synthesized WebAudio chime** that always plays (regardless of focus — an audible "it's done" even while you're watching the tab, and not subject to the OS per-site notification-sound setting), plus — **only when the window is unfocused** — a banner (desktop: native notification + Dock bounce / taskbar flash; browser: a Web Notification whose click refocuses the tab). Focused → chime only, no banner.
|
|
15
25
|
|
|
16
26
|
### Directory picker (FolderPicker modal)
|
|
17
27
|
Visual directory browser opened by the 📁🔍 button:
|
|
@@ -54,6 +64,7 @@ Items shown depend on the click target:
|
|
|
54
64
|
|---|---|---|
|
|
55
65
|
| New File / New Folder | Always | `POST /api/files/new` · `mkdir`; auto-expands the parent folder so the inline input is visible |
|
|
56
66
|
| Open in Integrated Terminal | Always | Spawns a terminal at the target dir (or file's parent) |
|
|
67
|
+
| Reveal in File Manager | Desktop app only | Opens the OS file manager (Finder / Explorer / Linux FM) at the target — a folder opens itself, a file is highlighted in its parent dir. Hidden in a plain browser (gated on the `window.haloReveal` IPC bridge exposed by the desktop preload) |
|
|
57
68
|
| Open to the Side | File only | Splits the editor and opens the file in the right pane |
|
|
58
69
|
| Download | File only | `GET /api/files/download?path=...` |
|
|
59
70
|
| Rename | Single file/folder | `POST /api/files/rename` |
|