@turmind/halo 0.2.0 → 0.2.1-bc7cf2b
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/admin-out/404.html +1 -1
- package/admin-out/_next/static/chunks/{298-4fac7d44a7949eec.js → 212-170855bed19f67f3.js} +1 -1
- package/admin-out/_next/static/chunks/525.2c10a4fd329d0d24.js +1 -0
- package/admin-out/_next/static/chunks/app/layout-c2fa8035998e48d5.js +1 -0
- package/admin-out/_next/static/chunks/app/page-31317ef1fb0ba31f.js +1 -0
- package/admin-out/_next/static/chunks/{webpack-8bd7ef88a6527feb.js → webpack-47520cdc55be63e7.js} +1 -1
- package/admin-out/_next/static/css/66df341f99220f5c.css +3 -0
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +21 -20
- package/bundled-docs/design/agent.md +1 -1
- package/bundled-docs/design/evolution.md +11 -2
- package/bundled-docs/design/halo-city.md +31 -0
- package/bundled-docs/design/prompt-system.md +3 -3
- package/bundled-docs/design/session.md +26 -1
- package/bundled-docs/design/storage.md +13 -0
- package/bundled-docs/dev/acp-adapter.md +26 -0
- package/bundled-docs/dev/api.md +6 -4
- package/bundled-docs/dev/desktop-packaging.md +4 -0
- package/bundled-docs/dev/env.md +4 -2
- package/bundled-docs/dev/previews.md +3 -0
- package/bundled-docs/dev/tools.md +3 -1
- package/bundled-docs/guide/cli.md +40 -16
- package/bundled-docs/requirements/editor.md +1 -1
- package/dist/index.js +1632 -906
- package/package.json +1 -2
- package/templates/INSTRUCTIONS.md +0 -4
- package/templates/agents/__apply_agent__/AGENT.md +41 -19
- package/templates/agents/__evo_agent__/AGENT.md +73 -45
- package/templates/agents/__evo_agent__/agent.yaml +9 -6
- package/templates/agents/__score__/AGENT.md +65 -33
- package/templates/agents/deep-executor/AGENT.md +23 -6
- package/templates/agents/deep-executor/agent.yaml +4 -1
- package/templates/agents/default/AGENT.md +32 -8
- package/templates/agents/executor/AGENT.md +19 -1
- package/templates/agents/executor/agent.yaml +4 -1
- package/templates/models/aws-bedrock-claude-invoke.yaml +27 -0
- package/templates/prompts/all/WORKSPACE_CONVENTIONS.md +5 -0
- package/templates/prompts/bootstrap/BOOTSTRAP.md +4 -0
- package/templates/prompts/root/WORKSPACE_MEMORY.md +2 -0
- package/admin-out/_next/static/chunks/661.a4fe93f3f2a5e871.js +0 -1
- package/admin-out/_next/static/chunks/app/layout-58f773336e6fce61.js +0 -1
- package/admin-out/_next/static/chunks/app/page-b12a2e8e48fe4ea0.js +0 -1
- package/admin-out/_next/static/css/372e3dbd4a0d1c25.css +0 -3
- /package/admin-out/_next/static/{ep7BWneNhTuIPwJfFFh72 → iSrc6429pyTB0lK-EE5oH}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{ep7BWneNhTuIPwJfFFh72 → iSrc6429pyTB0lK-EE5oH}/_ssgManifest.js +0 -0
|
@@ -81,9 +81,35 @@ To remove a binding: `/acp remove` (deletes the skill directory and points out t
|
|
|
81
81
|
| `--token` | yes | Web-channel token from admin UI. `full` access required for multi-workspace use. |
|
|
82
82
|
| `--workspace` | yes | Absolute server-side path for the workspace this adapter drives. |
|
|
83
83
|
| `--agent-id` | no | Halo agent profile to use when ACP `session/new` creates a new halo session. Default: `default`. |
|
|
84
|
+
| `--header` | no | Extra HTTP header on every upstream request, `"Name: value"` (like `curl -H`). Repeatable. For auth that sits **in front of** the halo server — see "Upstream auth" below. |
|
|
84
85
|
|
|
85
86
|
One adapter process binds to one workspace. To drive multiple workspaces concurrently from the same token, run multiple adapter processes — see "Multi-workspace" below.
|
|
86
87
|
|
|
88
|
+
## Upstream auth (`--header`)
|
|
89
|
+
|
|
90
|
+
`--token` authenticates the adapter to *halo itself* (it becomes the `x-token` header on every web-channel call). It does **not** cover a proxy sitting in front of the server — an SSO/session-cookie gateway, Cloudflare Access, ALB OIDC, nginx basic-auth. Those reject the request before halo ever sees the token.
|
|
91
|
+
|
|
92
|
+
`--header` is the generic escape hatch: it forwards arbitrary headers on every request the adapter makes (`/api/web/chat`, `/history`, `/stop`), exactly like `curl -H`. The adapter deliberately knows nothing about any specific gateway — you supply whatever that layer wants:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
# session-cookie gateway
|
|
96
|
+
halo acp --host h --port 9527 --scheme https --token <t> --workspace /ws \
|
|
97
|
+
--header "Cookie: <the gateway's session cookie, verbatim>"
|
|
98
|
+
|
|
99
|
+
# Cloudflare Access (two headers — --header is repeatable)
|
|
100
|
+
halo acp … --header "CF-Access-Client-Id: <id>" --header "CF-Access-Client-Secret: <secret>"
|
|
101
|
+
|
|
102
|
+
# HTTP basic auth
|
|
103
|
+
halo acp … --header "Authorization: Basic <base64 user:pass>"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Notes:
|
|
107
|
+
|
|
108
|
+
- **Repeatable** — pass `--header` as many times as the gateway needs.
|
|
109
|
+
- **Colon-safe** — the value is split on the *first* `:` only, so header values that themselves contain colons (`Cookie: a=b:c`) survive intact.
|
|
110
|
+
- **`x-token` always wins** — `--header` cannot override the adapter's own `x-token` / `content-type`; it only adds headers for the layer in front of halo.
|
|
111
|
+
- The generated `ask-<label>` bindings (halo→halo, via `ask.py`) do **not** yet expose `--header`; upstream auth through a binding isn't wired. `halo acp` direct is the path when a gateway is in play.
|
|
112
|
+
|
|
87
113
|
## ACP method coverage
|
|
88
114
|
|
|
89
115
|
| Method | Implemented? | Notes |
|
package/bundled-docs/dev/api.md
CHANGED
|
@@ -235,10 +235,12 @@ runtime so the frontend can render rooms (workspaces) + characters (sessions).
|
|
|
235
235
|
|
|
236
236
|
| Method | Path | Purpose |
|
|
237
237
|
|---|---|---|
|
|
238
|
-
| GET | `/api/show/state` |
|
|
239
|
-
| GET | `/api/show/session?ws=&id=` | Inspector-panel detail for a single session. Trimmed message log (last 40, content/tool I/O capped) plus `contextTokens` / `outputTokens` / `maxContextTokens` / `isRunning`. Non
|
|
238
|
+
| GET | `/api/show/state` | `full` or `observer` token → every known workspace; otherwise the account's own. Returns `{ serverTime, uptime, accessLevel, skills[], workspaces[] }` |
|
|
239
|
+
| GET | `/api/show/session?ws=&id=` | Inspector-panel detail for a single session. Trimmed message log (last 40, content/tool I/O capped) plus `contextTokens` / `outputTokens` / `maxContextTokens` / `isRunning`. Non-`full`/`observer` tokens may only read their own workspace. |
|
|
240
240
|
|
|
241
|
-
Each `workspace` = `{ path, key, label, counts{running,idle,stopped}, totalSessions, skills[], sessions[] }`; each `session` = `{ id, parentId, depth, agentName, description, status, lastTool, activeSkill, contextTokens, outputTokens, updatedAt }`. `lastTool` / `activeSkill` come from the live in-memory UI log (empty when the session isn't loaded). Sessions per room are capped (`totalSessions` reports the true total). Frontend: `halo-city/` at repo root.
|
|
241
|
+
Each `workspace` = `{ path, key, label, counts{running,idle,stopped}, totalSessions, skills[], sessions[] }`; each `session` = `{ id, parentId, depth, agentName, description, status, lastTool, activeSkill, contextTokens, outputTokens, messageCount, updatedAt }`. `lastTool` / `activeSkill` come from the live in-memory UI log (empty when the session isn't loaded). Sessions per room are capped (`totalSessions` reports the true total). Frontend: `halo-city/` at repo root.
|
|
242
|
+
|
|
243
|
+
**Read-only by construction — degraded snapshots.** Both endpoints resolve a workspace's runtime via `registry.peek()` — in-memory lookup only, **never** `getOrCreate`: constructing a SessionManager has write side effects (boot orphan-reconciliation batch-stops live sub-session rows; `.halo/` scaffolding), so a pure visualization poll must not trigger it. When no live SessionManager exists in this process, the handler opens that workspace's `.halo/halo.db` **read-only** (cached connection; missing db/tables silently degrade to an empty room) and projects rows / the persisted session file into the same wire shape. Sessions not in memory therefore return a **persisted snapshot**: `status` / token counts / `messageCount` may lag behind the last persistence point, and the live-only signals (`lastTool` / `activeSkill`) are empty by definition. The degraded `/api/show/session` path reports `maxContextTokens: 0` (the real cap needs a live agent config; the city inspector hides the meter when the cap is unknown).
|
|
242
244
|
|
|
243
245
|
## Agent Configs
|
|
244
246
|
|
|
@@ -312,7 +314,7 @@ File: `packages/server/src/routes/evolution.ts`. Surfaces the global `evolution_
|
|
|
312
314
|
| Method | Path | Purpose |
|
|
313
315
|
|---|---|---|
|
|
314
316
|
| GET | `/api/evolution/runs` | List all evolution runs across workspaces. Carries the latest `apply_id`/`apply_status` per run. (Score isn't surfaced in the list — it's read from `score.json` on the detail fetch only.) |
|
|
315
|
-
| GET | `/api/evolution/runs/:id` | Detail: db row + `patch.md` + `score.json` +
|
|
317
|
+
| GET | `/api/evolution/runs/:id` | Detail: db row + `patch.md` + `score.json` + `.skip.md` (when `status='skipped'`) + wrapper/sub-cli logs + a snapshot summary (first user message + first assistant reply + message count). Row carries `failureReason` (and `applyFailureReason` from the latest apply) — apply-side values include `phase A': apply cli exited <code>`, `phase A': apply agent aborted: <first line of ABORT.md>`, and `phase A': apply agent didn't produce apply.log`. |
|
|
316
318
|
| POST | `/api/evolution/runs/:id/approve` `{reviewerHint?}` | Move run from `awaiting_review` → `approved`, insert a pending `evolution_applies` row that the ticker will pick up. |
|
|
317
319
|
| POST | `/api/evolution/runs/:id/reject` | Move run from `awaiting_review` → `rejected`. |
|
|
318
320
|
| POST | `/api/evolution/runs/:id/retry` `{hint}` | Reset a finished run back to `pending` with the supplied (required) hint so the wrapper picks it up again. Rejected with 409 when the run is already `running` / `pending`. |
|
|
@@ -56,6 +56,10 @@ done # all five must read the same x.y.z, and match the tag you're about to cu
|
|
|
56
56
|
pnpm --filter @turmind/halo-core build
|
|
57
57
|
pnpm --filter @turmind/halo-server build
|
|
58
58
|
pnpm --filter @turmind/halo-admin build
|
|
59
|
+
# NOTE: acp-adapter is NOT listed here on purpose — build-bundle.mjs now
|
|
60
|
+
# builds every workspace:* dep (core / server / acp-adapter) itself before
|
|
61
|
+
# esbuild inlines them, so its dist can't go stale. This block only covers
|
|
62
|
+
# artifacts the stage script consumes directly (server dist, admin-out).
|
|
59
63
|
|
|
60
64
|
# 2. stage + package (arm64)
|
|
61
65
|
cd packages/desktop
|
package/bundled-docs/dev/env.md
CHANGED
|
@@ -87,7 +87,7 @@ Source: `packages/server/src/config.ts`
|
|
|
87
87
|
| Variable | Default | Config path | Description |
|
|
88
88
|
|---|---|---|---|
|
|
89
89
|
| `HALO_PORT` | `9527` | `config.yaml server.port` | Hono listen port |
|
|
90
|
-
| `HALO_PASSWORD` | (none) | `config.yaml server.password` (scrypt hash) | Plaintext login password. When set, takes precedence over the stored hash and bypasses scrypt entirely — intended for Docker / systemd / CI. The hash is set by `halo setup` for interactive installs. |
|
|
90
|
+
| `HALO_PASSWORD` | (none) | `config.yaml server.password` (scrypt hash) | Plaintext login password. When set, takes precedence over the stored hash and bypasses scrypt entirely — intended for Docker / systemd / CI. It also satisfies the **startup gate**: the server refuses to boot with no password configured, and env plaintext counts as a first-class credential there, so an env-only deployment (`halo setup -y && HALO_PASSWORD=... halo server start`, no stored hash) boots fine. The hash is set by `halo setup` for interactive installs. |
|
|
91
91
|
| `HALO_CORS_ORIGINS` | empty (reflect any origin) | `config.yaml server.cors_origins` | CORS allowlist (comma-separated). Empty = reflect any incoming Origin so credentials work cross-origin. Set explicit list to enforce strict CORS. |
|
|
92
92
|
| `HALO_FRONTEND_DIR` | `packages/admin/out` | — | Static frontend dir (resolved as absolute path from project root) |
|
|
93
93
|
| `HALO_MAX_CONTEXT_TOKENS` | `200000` | — | Model max context |
|
|
@@ -117,6 +117,8 @@ settings.yaml only (no env override):
|
|
|
117
117
|
- `kimi.secrets.api_key` — Kimi (Moonshot AI)
|
|
118
118
|
- `deepseek.secrets.api_key` — DeepSeek
|
|
119
119
|
|
|
120
|
+
When a provider manifest declares a `default: <<NAME>>` for a secret, `halo setup` offers a "Use env $NAME" action. Picking it **writes the literal `<<NAME>>` placeholder into settings.yaml**, which the standard env-var interpolation ([storage.md](../design/storage.md#env-var-interpolation-env_name)) expands against `process.env` at read time. There is no separate runtime env fallback — the placeholder in the file is the only mechanism (an unset env var leaves the literal `<<NAME>>` visible in the request, failing loudly).
|
|
121
|
+
|
|
120
122
|
`<skill-id>.params.*` (referenceable from skills via `{{<skill-id>.params.<key>}}`, or short form `{{params.<key>}}` inside SKILL.md; declared in `skills/<id>/config.yaml`):
|
|
121
123
|
- `tavily-search.params.api_key` — example only; declared by whichever skill needs it
|
|
122
124
|
|
|
@@ -136,7 +138,7 @@ settings.yaml-driven `general.limits.*` (no env override):
|
|
|
136
138
|
Two ways to authenticate:
|
|
137
139
|
|
|
138
140
|
1. **Interactive** — run `halo setup`, pick "Set / change password". The value is scrypt-hashed and written to `~/.halo/secrets/config.yaml server.password`. Best for personal installs.
|
|
139
|
-
2. **Env** — export `HALO_PASSWORD=...` before launching the server. The plaintext value is compared directly (no hashing) and takes precedence over any stored hash. Best for Docker / systemd / CI where a secrets manager already protects the env.
|
|
141
|
+
2. **Env** — export `HALO_PASSWORD=...` before launching the server. The plaintext value is compared directly (no hashing) and takes precedence over any stored hash. A stored hash isn't required at all — env plaintext alone satisfies the startup gate, so env-only deployments are legal. Best for Docker / systemd / CI where a secrets manager already protects the env.
|
|
140
142
|
|
|
141
143
|
## Verify
|
|
142
144
|
|
|
@@ -27,6 +27,9 @@ previews/
|
|
|
27
27
|
├── docx.tsx / docx-view.tsx
|
|
28
28
|
├── xlsx.tsx / xlsx-view.tsx
|
|
29
29
|
├── pptx.tsx / pptx-view.tsx
|
|
30
|
+
├── pptx-notes.ts pptx zip helpers: speaker-notes extraction (jszip +
|
|
31
|
+
│ DOMParser, play order via sldIdLst) + Content_Types
|
|
32
|
+
│ repair for decks with dangling Override parts
|
|
30
33
|
└── media.tsx / media-view.tsx
|
|
31
34
|
```
|
|
32
35
|
|
|
@@ -181,6 +181,8 @@ Start a sub-agent session asynchronously. When the sub-agent finishes, its **wra
|
|
|
181
181
|
- Depth exceeded: `{"code": 1, "error": "Maximum nesting depth (N) reached..."}`
|
|
182
182
|
- Working dir invalid: `{"code": 1, "error": "working_dir \"...\" is outside the workspace"}` (or does-not-exist / not-a-directory)
|
|
183
183
|
|
|
184
|
+
UI note: the `agent_start` event this emits carries both a 200-char `text` preview (parent-side rendering) and the full un-truncated brief as `fullText`, which seeds the sub-session log's opening user message — so viewing the child session shows the complete task brief (`system_prompt_context` + `message`), not a cut-off preview. See [session.md → Event routing](../design/session.md#event-routing).
|
|
185
|
+
|
|
184
186
|
### session_list
|
|
185
187
|
|
|
186
188
|
List direct child sessions of the current session and their status.
|
|
@@ -293,7 +295,7 @@ Returns: full SKILL.md content (body + resource files list). For progressive dis
|
|
|
293
295
|
|---|---|---|---|
|
|
294
296
|
| `content` | string | yes | The complete draft answer. Required and must be non-empty |
|
|
295
297
|
|
|
296
|
-
The tool **description is deliberately plain** — "Submit a draft answer for self-review; returns a checklist that critiques the draft." It does NOT say *when* to call it (no "call this for complex questions / when unsure"). An earlier version that did embed such self-referential guidance made some models (notably GPT-5.x) thrash. Steering toward *using* draft belongs in the agent's
|
|
298
|
+
The tool **description is deliberately plain** — "Submit a draft answer for self-review; returns a checklist that critiques the draft." It does NOT say *when* to call it (no "call this for complex questions / when unsure"). An earlier version that did embed such self-referential guidance made some models (notably GPT-5.x) thrash. Steering toward *using* draft belongs in the agent's prompt files (the bundled `default` agent's AGENT.md says "hold your answers to a high standard… don't reply off the cuff" — it lives in AGENT.md because the yaml `system_prompt` is only a fallback when the MD layer is empty), not in the tool description. Empty `content` is rejected with an error **without consuming a draft round**.
|
|
297
299
|
|
|
298
300
|
**Why it exists:** the agent loop only makes another model call when the model emits a `tool_use` block. A plain-text answer (`end_turn`) is single-pass — `thinking` runs *before* the answer in the same call, so the model never gets to look at its *finished* answer and revise it. `draft` closes that gap without touching the loop: the model writes its answer into `content` (materialised into the conversation as a `tool_use` block — uncapped, never echoed back), and the tool_result hands back an adversarial review checklist (framed as a hostile reviewer: list every factual claim and tag its source, verify the unverified ones with tools *now*, check directness/tone, flag gaps). The next model call then critiques that now-concrete draft and either revises (calls `draft` again) or writes the final answer.
|
|
299
301
|
|
|
@@ -46,12 +46,14 @@ End users then install with `npm install -g @turmind/halo`.
|
|
|
46
46
|
Run a one-shot prompt and exit:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
halo "review this PR"
|
|
50
|
-
halo -w /path/to/workspace "analyze code"
|
|
51
|
-
echo "review the changes" | halo
|
|
52
|
-
cat prompt.txt | halo -w /path/to/review-ws
|
|
49
|
+
halo cli "review this PR"
|
|
50
|
+
halo cli -w /path/to/workspace "analyze code"
|
|
51
|
+
echo "review the changes" | halo cli
|
|
52
|
+
cat prompt.txt | halo cli -w /path/to/review-ws
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
To list agents or sessions without running a prompt, use the dedicated subcommands `halo agents` / `halo sessions` (same `-w` flag).
|
|
56
|
+
|
|
55
57
|
### Options
|
|
56
58
|
|
|
57
59
|
| Flag | Short | Default | Description |
|
|
@@ -59,11 +61,10 @@ cat prompt.txt | halo -w /path/to/review-ws
|
|
|
59
61
|
| `--workspace` | `-w` | cwd | Workspace path |
|
|
60
62
|
| `--agent` | `-a` | `default` | Agent ID |
|
|
61
63
|
| `--session` | `-s` | auto | Resume session by ID |
|
|
64
|
+
| `--new` | `-n` | off | Always start a new session |
|
|
62
65
|
| `--format` | `-f` | `text` | Output format: `text` or `json` |
|
|
63
66
|
| `--verbose` | `-v` | off | Show thinking, tool calls, usage on stderr |
|
|
64
67
|
| `--access` | | `full` | Access level: `full`, `workspace`, `readonly` |
|
|
65
|
-
| `--agents` | | | List available agents and exit |
|
|
66
|
-
| `--sessions` | | | List recent sessions and exit |
|
|
67
68
|
| `--lang` | | `en` | Language: `en` or `zh` |
|
|
68
69
|
|
|
69
70
|
### Output
|
|
@@ -91,21 +92,22 @@ cat prompt.txt | halo -w /path/to/review-ws
|
|
|
91
92
|
|
|
92
93
|
```bash
|
|
93
94
|
# Code review in CI
|
|
94
|
-
halo -w /path/to/review-ws "review the diff" --format json | jq '.text'
|
|
95
|
+
halo cli -w /path/to/review-ws "review the diff" --format json | jq '.text'
|
|
95
96
|
|
|
96
97
|
# Pipe content in
|
|
97
|
-
git diff HEAD~1 | halo -w /path/to/review-ws "review this diff"
|
|
98
|
+
git diff HEAD~1 | halo cli -w /path/to/review-ws "review this diff"
|
|
98
99
|
|
|
99
100
|
# Exit code: 0 = success, 1 = error, 130 = SIGINT
|
|
100
|
-
halo "check for issues" && echo "OK" || echo "FAILED"
|
|
101
|
+
halo cli "check for issues" && echo "OK" || echo "FAILED"
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
## TUI Mode (interactive)
|
|
104
105
|
|
|
105
106
|
```bash
|
|
106
|
-
halo
|
|
107
|
-
halo
|
|
108
|
-
halo
|
|
107
|
+
halo tui
|
|
108
|
+
halo tui -w /path/to/workspace
|
|
109
|
+
halo tui -s sid_abc123 # resume session
|
|
110
|
+
halo tui -n # always start a new session
|
|
109
111
|
```
|
|
110
112
|
|
|
111
113
|
Multi-turn conversation. Supports all standard Halo slash commands:
|
|
@@ -130,6 +132,16 @@ Multi-turn conversation. Supports all standard Halo slash commands:
|
|
|
130
132
|
| `/evo [hint]` | Queue a self-evolution run on this session (full access only) |
|
|
131
133
|
| `/quit` | Exit |
|
|
132
134
|
|
|
135
|
+
TUI-only client commands (handled locally, also visible in the completion popup):
|
|
136
|
+
|
|
137
|
+
| Command | Description |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `/clear` | Start a new session (alias for `/session new`) |
|
|
140
|
+
| `/retry` | Resend the last user message |
|
|
141
|
+
| `/verbose` | Toggle verbose tool output (args + truncated results) at runtime — same as launching with `-v`; the status bar shows a `v` badge while on |
|
|
142
|
+
| `/log` | Browse the session tree and view a session log (same as `Ctrl+O`) |
|
|
143
|
+
| `/exit` | Alias for `/quit` |
|
|
144
|
+
|
|
133
145
|
Bare `/<obj>` (or `/<obj> help`) lists the verbs you may run. Verbs gated above your access level are hidden.
|
|
134
146
|
|
|
135
147
|
### Keybindings
|
|
@@ -139,9 +151,15 @@ Bare `/<obj>` (or `/<obj> help`) lists the verbs you may run. Verbs gated above
|
|
|
139
151
|
| `Esc` (while running) | Interrupt the current turn immediately — aborts a command mid-execution, then any messages typed while it was running are folded into one follow-up turn. Same as `/session interrupt`. |
|
|
140
152
|
| `Ctrl+C` | Graceful exit; press twice to force |
|
|
141
153
|
| `Ctrl+O` | Toggle the sub-agent navigator — lists every sub-agent spawned this session, each showing its agent name, task title (same as the session list), and status (`●` running green / `○` idle grey / `✕` stopped red, plus a `▢ archived` marker when the session is archived); `↑↓` to move, `Enter` to view that sub-agent's log, `Esc`/`q` to close. (Was `Shift+Tab`, but Windows terminals consume that as backtab.) The log viewer auto-refreshes while the viewed session is still running (a `● live` hint shows in the header) and follows the bottom as new output lands — unless you've scrolled up to read, in which case it stays put (`G` jumps back to the bottom and resumes following). |
|
|
142
|
-
| `↑` / `↓` | Walk input history (when no popup is open) |
|
|
154
|
+
| `↑` / `↓` | Walk input history (when no popup is open). History persists across restarts in `~/.halo/global/tui-history.json` (last 100 entries, shared across workspaces) |
|
|
155
|
+
| `←` / `→`, `Home` / `End` | Move the cursor within the input; text is inserted/deleted at the cursor (CJK and emoji safe) |
|
|
156
|
+
| `Ctrl+A` / `Ctrl+E` | Jump to start / end of input |
|
|
157
|
+
| `Ctrl+W` / `Alt+Backspace` | Delete the word before the cursor |
|
|
158
|
+
| `Ctrl+U` / `Ctrl+K` | Delete to start / to end of input |
|
|
159
|
+
|
|
160
|
+
On resume (`-s <id>`, or the default latest session), the TUI replays the session's prior conversation on screen so you see where you left off. `shell_exec` output is shown inline by default (other tools' output needs `-v`). Tool lines show a short argument summary and duration, e.g. `⚙ file_read hello.txt 4ms`.
|
|
143
161
|
|
|
144
|
-
|
|
162
|
+
**Multi-line paste**: pasting text with newlines (or >800 chars) collapses into a compact placeholder like `[#1 pasted 3 lines]` in the input; you can keep typing around it, and the original text is expanded back in full on submit. Pasted content is inserted at the cursor position.
|
|
145
163
|
|
|
146
164
|
## File, Image, and Scope References
|
|
147
165
|
|
|
@@ -174,10 +192,16 @@ Attach files or images to your message with `@file` and `@image`, or pull a dire
|
|
|
174
192
|
```
|
|
175
193
|
packages/cli/
|
|
176
194
|
src/
|
|
177
|
-
index.ts — Entry:
|
|
195
|
+
index.ts — Entry: subcommand dispatch (tui/cli/agents/sessions/server/setup/acp), SIGINT handling
|
|
178
196
|
harness.ts — Shared agent harness wrapping SessionManager
|
|
179
197
|
cli.ts — Non-interactive: stdin/args → agent → stdout → exit
|
|
180
|
-
tui.
|
|
198
|
+
tui.tsx — Interactive entry: mounts the ink app
|
|
199
|
+
tui/
|
|
200
|
+
app.tsx — Root component: event reducer, blocks, submit/command handling
|
|
201
|
+
line-editor.ts — Grapheme-aware pure line-editing functions (cursor, insert, delete)
|
|
202
|
+
history.ts — Persistent input history (~/.halo/global/tui-history.json)
|
|
203
|
+
components/ — input-box, text-input, messages, streaming, status-bar,
|
|
204
|
+
slash-suggest, path-suggest, log-navigator, log-viewer, banner
|
|
181
205
|
format-usage.ts — Usage-line formatter (mirrors admin UsageLine badge order)
|
|
182
206
|
resolve-refs.ts — @file / @image reference resolution with size limits
|
|
183
207
|
render-md.ts — Terminal markdown rendering (marked + marked-terminal)
|
|
@@ -42,7 +42,7 @@ Non-text files go through `FilePreview`, which looks up a **plugin** in the prev
|
|
|
42
42
|
- **PDF** — browser-native iframe
|
|
43
43
|
- **DOCX / DOC** — `mammoth` → HTML (parsed in a Web Worker so the UI stays responsive)
|
|
44
44
|
- **XLSX / XLS / CSV** — `xlsx` (SheetJS) → table (parsed in a Web Worker; CSV decoded as UTF-8 with BOM strip)
|
|
45
|
-
- **PPTX / PPT** — `pptx-preview` list mode. Fidelity is approximate — complex animations / SmartArt / embedded fonts may not render perfectly; users can download for the exact source. Flagged `heavy: true` so only the *active* pptx mounts (canvas-based rendering needs the main thread)
|
|
45
|
+
- **PPTX / PPT** — `pptx-preview` list mode. Fidelity is approximate — complex animations / SmartArt / embedded fonts may not render perfectly; users can download for the exact source. Flagged `heavy: true` so only the *active* pptx mounts (canvas-based rendering needs the main thread). **Speaker-notes sidebar**: notes are extracted from the pptx zip in presentation (play) order and listed on the left; clicking a note scrolls to the corresponding slide (a domIndex mapping bridges play order to pptx-preview's part-filename render order, so reordered decks still land on the right slide). Collapsible with the state remembered in localStorage (`halo.pptxNotesHidden`); the sidebar doesn't appear at all when no slide has notes. Decks with dangling `[Content_Types].xml` overrides (e.g. some WPS exports) are repaired before rendering; if zero slides render anyway, a real error UI is shown instead of a silent black wrapper
|
|
46
46
|
- **Images / video / audio** — native `<img>` / `<video>` / `<audio>`, supports HTTP Range for seek-without-full-download
|
|
47
47
|
|
|
48
48
|
All previews share a **standard header** (`PreviewShell`) with filename, Download, Open-as-Text, and an `extraToolbar` slot for plugin-specific buttons (e.g. DOCX Print, XLSX sheet tabs).
|