@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.
Files changed (36) hide show
  1. package/README.md +1 -5
  2. package/admin-out/404.html +1 -1
  3. package/admin-out/_next/static/chunks/298-4fac7d44a7949eec.js +1 -0
  4. package/admin-out/_next/static/chunks/{503-7c6d9935df6e0cea.js → 307-d7a99f9a4a436ec3.js} +1 -1
  5. package/admin-out/_next/static/chunks/app/page-b12a2e8e48fe4ea0.js +1 -0
  6. package/admin-out/_next/static/css/{8fce4e1a54dac12a.css → 372e3dbd4a0d1c25.css} +1 -1
  7. package/admin-out/index.html +1 -1
  8. package/admin-out/index.txt +4 -4
  9. package/bundled-docs/dev/acp-adapter.md +5 -4
  10. package/bundled-docs/dev/desktop-packaging.md +94 -8
  11. package/bundled-docs/guide/getting-started.md +3 -2
  12. package/bundled-docs/requirements/explorer.md +11 -0
  13. package/dist/index.js +13373 -13246
  14. package/package.json +1 -1
  15. package/templates/agents/executor/agent.yaml +2 -2
  16. package/templates/models/aws-bedrock-claude-invoke.yaml +26 -0
  17. package/templates/skills/acp/SKILL.md +8 -1
  18. package/templates/skills/acp/templates/SKILL.md.tmpl +2 -1
  19. package/templates/skills/acp/templates/ask.py +2 -1
  20. package/templates/skills/acp/templates/config.yaml.tmpl +5 -0
  21. package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +0 -1
  22. package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +0 -1
  23. package/bundled-docs/plans/cron-tasks.md +0 -362
  24. package/bundled-docs/plans/design-suggestions.md +0 -203
  25. package/bundled-docs/plans/issue-session-deep-nesting.md +0 -208
  26. package/bundled-docs/plans/launch-plan.md +0 -111
  27. package/bundled-docs/plans/md-and-agent-refactor.md +0 -197
  28. package/bundled-docs/plans/remote-mac-worker.md +0 -196
  29. package/bundled-docs/plans/roadmap.md +0 -40
  30. package/bundled-docs/plans/self-evolution.md +0 -1379
  31. package/bundled-docs/plans/todo.md +0 -32
  32. package/bundled-docs/plans/weixin-channel.md +0 -255
  33. package/bundled-docs/test/docs-seeding.md +0 -101
  34. package/bundled-docs/test/session.md +0 -374
  35. /package/admin-out/_next/static/{IBP_mwBDf-cPwZSZZGpi8 → ep7BWneNhTuIPwJfFFh72}/_buildManifest.js +0 -0
  36. /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 macOS desktop app (`Halo-0.1.5-arm64.dmg`). The desktop
4
- build is a thin Electron shell (`packages/desktop`) that bundles a self-
5
- contained server runtime + a private `node` binary + the admin static export,
6
- then spawns the server as a child process and points a `BrowserWindow` at it.
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
- Other targets: `pnpm dist:x64` (Intel mac), `pnpm dist:win` (Windows nsis,
62
- cross-staged from mac).
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. **Cross-arch native fixup** — when target arch/platform ≠ host, re-fetch
142
- `better-sqlite3` prebuilds via `prebuild-install`.
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
- - The default password is printed to the **server console** (auto-generated if you haven't set `HALO_PASSWORD`)
10
- - You can also pin a password via `server.password` in `~/.halo/secrets/config.yaml`
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` |