@turmind/halo 0.1.9
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/LICENSE +21 -0
- package/README.md +143 -0
- package/admin-out/404.html +1 -0
- package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_buildManifest.js +1 -0
- package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_ssgManifest.js +1 -0
- package/admin-out/_next/static/chunks/1d2d5650-810a3ca1ae20cab5.js +18 -0
- package/admin-out/_next/static/chunks/200.3b8f8a74f005a134.js +1 -0
- package/admin-out/_next/static/chunks/220.3dc41cd6269b88e6.js +1 -0
- package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +1 -0
- package/admin-out/_next/static/chunks/304eda7d.b1ee7f523653e027.js +1 -0
- package/admin-out/_next/static/chunks/330.3b784cf0dcd69163.js +1 -0
- package/admin-out/_next/static/chunks/442.f4302087bddb1ec1.js +1 -0
- package/admin-out/_next/static/chunks/443.d1b289781793f8de.js +25 -0
- package/admin-out/_next/static/chunks/503-7c6d9935df6e0cea.js +1 -0
- package/admin-out/_next/static/chunks/533.5f2d4bfe3d076095.js +1 -0
- package/admin-out/_next/static/chunks/579.a2718ddd395a2f3a.js +1 -0
- package/admin-out/_next/static/chunks/635-3dd0043ed0520b9d.js +1 -0
- package/admin-out/_next/static/chunks/65.859665ba6717967a.js +1 -0
- package/admin-out/_next/static/chunks/661.a4fe93f3f2a5e871.js +1 -0
- package/admin-out/_next/static/chunks/688.4e014ac6cfc7e152.js +1 -0
- package/admin-out/_next/static/chunks/868.0c95dfe283400a00.js +1 -0
- package/admin-out/_next/static/chunks/app/_not-found/page-8e35399c8fd5016d.js +1 -0
- package/admin-out/_next/static/chunks/app/layout-58f773336e6fce61.js +1 -0
- package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +1 -0
- package/admin-out/_next/static/chunks/db534642.09d3c650ff587175.js +1 -0
- package/admin-out/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js +1 -0
- package/admin-out/_next/static/chunks/framework-c3031ae54a63fe16.js +1 -0
- package/admin-out/_next/static/chunks/main-14b48e3c2588354f.js +1 -0
- package/admin-out/_next/static/chunks/main-app-483b436873410ddc.js +1 -0
- package/admin-out/_next/static/chunks/pages/_app-b2fc6e5f920d1b1a.js +1 -0
- package/admin-out/_next/static/chunks/pages/_error-f3696a8f3d67d150.js +1 -0
- package/admin-out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/admin-out/_next/static/chunks/webpack-8bd7ef88a6527feb.js +1 -0
- package/admin-out/_next/static/css/659eccb5db697b76.css +1 -0
- package/admin-out/_next/static/css/8fce4e1a54dac12a.css +3 -0
- package/admin-out/_next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
- package/admin-out/_next/static/media/21350d82a1f187e9-s.woff2 +0 -0
- package/admin-out/_next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/admin-out/_next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
- package/admin-out/_next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
- package/admin-out/_next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/admin-out/_next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/admin-out/favicon.ico +0 -0
- package/admin-out/icon.svg +18 -0
- package/admin-out/index.html +1 -0
- package/admin-out/index.txt +23 -0
- package/admin-out/monaco/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
- package/admin-out/monaco/vs/abap-D-t0cyap.js +1 -0
- package/admin-out/monaco/vs/apex-CcIm7xu6.js +1 -0
- package/admin-out/monaco/vs/assets/css.worker-HnVq6Ewq.js +93 -0
- package/admin-out/monaco/vs/assets/editor.worker-Be8ye1pW.js +26 -0
- package/admin-out/monaco/vs/assets/html.worker-B51mlPHg.js +470 -0
- package/admin-out/monaco/vs/assets/json.worker-DKiEKt88.js +58 -0
- package/admin-out/monaco/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
- package/admin-out/monaco/vs/azcli-BA0tQDCg.js +1 -0
- package/admin-out/monaco/vs/basic-languages/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/bat-C397hTD6.js +1 -0
- package/admin-out/monaco/vs/bicep-DF5aW17k.js +2 -0
- package/admin-out/monaco/vs/cameligo-plsz8qhj.js +1 -0
- package/admin-out/monaco/vs/clojure-Y2auQMzK.js +1 -0
- package/admin-out/monaco/vs/coffee-Bu45yuWE.js +1 -0
- package/admin-out/monaco/vs/cpp-CkKPQIni.js +1 -0
- package/admin-out/monaco/vs/csharp-CX28MZyh.js +1 -0
- package/admin-out/monaco/vs/csp-D8uWnyxW.js +1 -0
- package/admin-out/monaco/vs/css-CaeNmE3S.js +3 -0
- package/admin-out/monaco/vs/cssMode-CjiAH6dQ.js +1 -0
- package/admin-out/monaco/vs/cypher-DVThT8BS.js +1 -0
- package/admin-out/monaco/vs/dart-CmGfCvrO.js +1 -0
- package/admin-out/monaco/vs/dockerfile-CZqqYdch.js +1 -0
- package/admin-out/monaco/vs/ecl-30fUercY.js +1 -0
- package/admin-out/monaco/vs/editor/editor.main.css +1 -0
- package/admin-out/monaco/vs/editor/editor.main.js +5 -0
- package/admin-out/monaco/vs/editor.api-CalNCsUg.js +903 -0
- package/admin-out/monaco/vs/elixir-xjPaIfzF.js +1 -0
- package/admin-out/monaco/vs/flow9-DqtmStfK.js +1 -0
- package/admin-out/monaco/vs/freemarker2-Cz_sV6Md.js +3 -0
- package/admin-out/monaco/vs/fsharp-BOMdg4U1.js +1 -0
- package/admin-out/monaco/vs/go-D_hbi-Jt.js +1 -0
- package/admin-out/monaco/vs/graphql-CKUU4kLG.js +1 -0
- package/admin-out/monaco/vs/handlebars-OwglfO-1.js +1 -0
- package/admin-out/monaco/vs/hcl-DTaboeZW.js +1 -0
- package/admin-out/monaco/vs/html-Pa1xEWsY.js +1 -0
- package/admin-out/monaco/vs/htmlMode-Bz67EXwp.js +1 -0
- package/admin-out/monaco/vs/ini-CsNwO04R.js +1 -0
- package/admin-out/monaco/vs/java-CI4ZMsH9.js +1 -0
- package/admin-out/monaco/vs/javascript-PczUCGdz.js +1 -0
- package/admin-out/monaco/vs/jsonMode-DULH5oaX.js +7 -0
- package/admin-out/monaco/vs/julia-BwzEvaQw.js +1 -0
- package/admin-out/monaco/vs/kotlin-IUYPiTV8.js +1 -0
- package/admin-out/monaco/vs/language/css/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/html/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/json/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/typescript/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/less-C0eDYdqa.js +2 -0
- package/admin-out/monaco/vs/lexon-iON-Kj97.js +1 -0
- package/admin-out/monaco/vs/liquid-DqKjdPGy.js +1 -0
- package/admin-out/monaco/vs/loader.js +1368 -0
- package/admin-out/monaco/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
- package/admin-out/monaco/vs/lua-DtygF91M.js +1 -0
- package/admin-out/monaco/vs/m3-CsR4AuFi.js +1 -0
- package/admin-out/monaco/vs/markdown-C_rD0bIw.js +1 -0
- package/admin-out/monaco/vs/mdx-DEWtB1K5.js +1 -0
- package/admin-out/monaco/vs/mips-CiYP61RB.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-D2OdxNBt.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-DO3azKX8.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-EcChJV6a.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-qLAYrEOP.js +1 -0
- package/admin-out/monaco/vs/msdax-C38-sJlp.js +1 -0
- package/admin-out/monaco/vs/mysql-CdtbpvbG.js +1 -0
- package/admin-out/monaco/vs/nls.messages-loader.js +1 -0
- package/admin-out/monaco/vs/nls.messages.cs.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.de.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.es.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.fr.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.it.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.ja.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.js.js +10 -0
- package/admin-out/monaco/vs/nls.messages.ko.js.js +25 -0
- package/admin-out/monaco/vs/nls.messages.pl.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.pt-br.js.js +6 -0
- package/admin-out/monaco/vs/nls.messages.ru.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.tr.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.zh-cn.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.zh-tw.js.js +15 -0
- package/admin-out/monaco/vs/objective-c-CntZFaHX.js +1 -0
- package/admin-out/monaco/vs/pascal-r6kuqfl_.js +1 -0
- package/admin-out/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
- package/admin-out/monaco/vs/perl-DABw_TcH.js +1 -0
- package/admin-out/monaco/vs/pgsql-me_jFXeX.js +1 -0
- package/admin-out/monaco/vs/php-D_kh-9LK.js +1 -0
- package/admin-out/monaco/vs/pla-VfZjczW0.js +1 -0
- package/admin-out/monaco/vs/postiats-BBSzz8Pk.js +1 -0
- package/admin-out/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
- package/admin-out/monaco/vs/powershell-B-7ap1zc.js +1 -0
- package/admin-out/monaco/vs/protobuf-BmtuEB1A.js +2 -0
- package/admin-out/monaco/vs/pug-BRpRNeEb.js +1 -0
- package/admin-out/monaco/vs/python-Cr0UkIbn.js +1 -0
- package/admin-out/monaco/vs/qsharp-BzsFaUU9.js +1 -0
- package/admin-out/monaco/vs/r-f8dDdrp4.js +1 -0
- package/admin-out/monaco/vs/razor-BYAHOTkz.js +1 -0
- package/admin-out/monaco/vs/redis-fvZQY4PI.js +1 -0
- package/admin-out/monaco/vs/redshift-45Et0LQi.js +1 -0
- package/admin-out/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
- package/admin-out/monaco/vs/ruby-CZO8zYTz.js +1 -0
- package/admin-out/monaco/vs/rust-Bfetafyc.js +1 -0
- package/admin-out/monaco/vs/sb-3GYllVck.js +1 -0
- package/admin-out/monaco/vs/scala-foMgrKo1.js +1 -0
- package/admin-out/monaco/vs/scheme-CHdMtr7p.js +1 -0
- package/admin-out/monaco/vs/scss-C1cmLt9V.js +3 -0
- package/admin-out/monaco/vs/shell-ClXCKCEW.js +1 -0
- package/admin-out/monaco/vs/solidity-MZ6ExpPy.js +1 -0
- package/admin-out/monaco/vs/sophia-DWkuSsPQ.js +1 -0
- package/admin-out/monaco/vs/sparql-AUGFYSyk.js +1 -0
- package/admin-out/monaco/vs/sql-32GpJSV2.js +1 -0
- package/admin-out/monaco/vs/st-CuDFIVZ_.js +1 -0
- package/admin-out/monaco/vs/swift-n-2HociN.js +3 -0
- package/admin-out/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
- package/admin-out/monaco/vs/tcl-D74tq1nH.js +1 -0
- package/admin-out/monaco/vs/tsMode-CZz1Umrk.js +11 -0
- package/admin-out/monaco/vs/twig-C6taOxMV.js +1 -0
- package/admin-out/monaco/vs/typescript-DfOrAzoV.js +1 -0
- package/admin-out/monaco/vs/typespec-D-PIh9Xw.js +1 -0
- package/admin-out/monaco/vs/vb-Dyb2648j.js +1 -0
- package/admin-out/monaco/vs/wgsl-BhLXMOR0.js +298 -0
- package/admin-out/monaco/vs/workers-DcJshg-q.js +1 -0
- package/admin-out/monaco/vs/xml-CdsdnY8S.js +1 -0
- package/admin-out/monaco/vs/yaml-DYGvmE88.js +1 -0
- package/bin/halo.js +9 -0
- package/bundled-docs/design/agent.md +145 -0
- package/bundled-docs/design/architecture.md +270 -0
- package/bundled-docs/design/background-dispatch.md +151 -0
- package/bundled-docs/design/command.md +58 -0
- package/bundled-docs/design/cron.md +88 -0
- package/bundled-docs/design/evolution.md +383 -0
- package/bundled-docs/design/express-self.md +145 -0
- package/bundled-docs/design/feishu.md +224 -0
- package/bundled-docs/design/halo-city.md +112 -0
- package/bundled-docs/design/prompt-system.md +411 -0
- package/bundled-docs/design/session.md +321 -0
- package/bundled-docs/design/slack.md +212 -0
- package/bundled-docs/design/storage.md +578 -0
- package/bundled-docs/design/telegram.md +161 -0
- package/bundled-docs/design/web.md +222 -0
- package/bundled-docs/design/wechat.md +146 -0
- package/bundled-docs/design/ws.md +144 -0
- package/bundled-docs/dev/acp-adapter.md +337 -0
- package/bundled-docs/dev/add-channel.md +376 -0
- package/bundled-docs/dev/add-model-provider.md +386 -0
- package/bundled-docs/dev/api.md +686 -0
- package/bundled-docs/dev/deploy.md +198 -0
- package/bundled-docs/dev/desktop-packaging.md +327 -0
- package/bundled-docs/dev/env.md +158 -0
- package/bundled-docs/dev/logging.md +85 -0
- package/bundled-docs/dev/previews.md +225 -0
- package/bundled-docs/dev/tools.md +331 -0
- package/bundled-docs/guide/README.md +29 -0
- package/bundled-docs/guide/agents.md +264 -0
- package/bundled-docs/guide/channels/README.md +62 -0
- package/bundled-docs/guide/channels/acp.md +150 -0
- package/bundled-docs/guide/channels/feishu.md +154 -0
- package/bundled-docs/guide/channels/slack.md +156 -0
- package/bundled-docs/guide/channels/telegram.md +112 -0
- package/bundled-docs/guide/channels/web.md +149 -0
- package/bundled-docs/guide/channels/wechat.md +110 -0
- package/bundled-docs/guide/chat.md +112 -0
- package/bundled-docs/guide/cli.md +197 -0
- package/bundled-docs/guide/getting-started.md +93 -0
- package/bundled-docs/guide/secrets-and-credentials.md +161 -0
- package/bundled-docs/guide/sessions.md +104 -0
- package/bundled-docs/guide/skills.md +302 -0
- package/bundled-docs/guide/testing-agents-and-skills.md +136 -0
- package/bundled-docs/guide/workspace.md +131 -0
- package/bundled-docs/plans/cron-tasks.md +362 -0
- package/bundled-docs/plans/design-suggestions.md +203 -0
- package/bundled-docs/plans/issue-session-deep-nesting.md +208 -0
- package/bundled-docs/plans/launch-plan.md +111 -0
- package/bundled-docs/plans/md-and-agent-refactor.md +197 -0
- package/bundled-docs/plans/remote-mac-worker.md +196 -0
- package/bundled-docs/plans/roadmap.md +40 -0
- package/bundled-docs/plans/self-evolution.md +1379 -0
- package/bundled-docs/plans/todo.md +32 -0
- package/bundled-docs/plans/weixin-channel.md +255 -0
- package/bundled-docs/requirements/agent.md +92 -0
- package/bundled-docs/requirements/chat.md +81 -0
- package/bundled-docs/requirements/command.md +130 -0
- package/bundled-docs/requirements/editor.md +82 -0
- package/bundled-docs/requirements/explorer.md +89 -0
- package/bundled-docs/requirements/overview.md +62 -0
- package/bundled-docs/requirements/session.md +73 -0
- package/bundled-docs/requirements/settings.md +224 -0
- package/bundled-docs/requirements/skill.md +125 -0
- package/bundled-docs/requirements/source-control.md +82 -0
- package/bundled-docs/requirements/terminal.md +118 -0
- package/bundled-docs/requirements/workspace.md +80 -0
- package/bundled-docs/test/docs-seeding.md +101 -0
- package/bundled-docs/test/session.md +374 -0
- package/dist/index.js +26750 -0
- package/package.json +67 -0
- package/templates/INSTRUCTIONS.md +25 -0
- package/templates/agents/__apply_agent__/AGENT.md +229 -0
- package/templates/agents/__apply_agent__/agent.yaml +30 -0
- package/templates/agents/__evo_agent__/AGENT.md +323 -0
- package/templates/agents/__evo_agent__/agent.yaml +29 -0
- package/templates/agents/__score__/AGENT.md +177 -0
- package/templates/agents/__score__/agent.yaml +29 -0
- package/templates/agents/deep-executor/AGENT.md +60 -0
- package/templates/agents/deep-executor/agent.yaml +25 -0
- package/templates/agents/default/AGENT.md +38 -0
- package/templates/agents/default/agent.yaml +51 -0
- package/templates/agents/executor/AGENT.md +38 -0
- package/templates/agents/executor/agent.yaml +25 -0
- package/templates/aliases.yaml +26 -0
- package/templates/canvas/self.html +660 -0
- package/templates/config.yaml +69 -0
- package/templates/models/anthropic.yaml +47 -0
- package/templates/models/aws-bedrock-claude-invoke.yaml +156 -0
- package/templates/models/aws-bedrock-mantle.yaml +89 -0
- package/templates/models/deepseek.yaml +62 -0
- package/templates/models/doubao.yaml +137 -0
- package/templates/models/hunyuan.yaml +56 -0
- package/templates/models/kimi.yaml +41 -0
- package/templates/models/mimo-token-plan-china.yaml +61 -0
- package/templates/models/minimax.yaml +80 -0
- package/templates/models/openai.yaml +51 -0
- package/templates/models/qwen.yaml +78 -0
- package/templates/optional-skills/tavily-web-search/SKILL.md +91 -0
- package/templates/optional-skills/tavily-web-search/config.yaml +10 -0
- package/templates/prompts/all/TOOL_GUIDELINES.md +35 -0
- package/templates/prompts/all/TOOL_SHELL.md +4 -0
- package/templates/prompts/all/TOOL_SHELL.windows.md +7 -0
- package/templates/prompts/bootstrap/BOOTSTRAP.md +26 -0
- package/templates/prompts/root/WORKSPACE_MEMORY.md +11 -0
- package/templates/schema.sql +30 -0
- package/templates/skills/acp/SKILL.md +236 -0
- package/templates/skills/acp/templates/SKILL.md.tmpl +74 -0
- package/templates/skills/acp/templates/ask.py +176 -0
- package/templates/skills/acp/templates/config.yaml.tmpl +33 -0
- package/templates/skills/agent/SKILL.md +128 -0
- package/templates/skills/aws-knowledge/SKILL.md +82 -0
- package/templates/skills/aws-knowledge/scripts/aws_kb.py +61 -0
- package/templates/skills/cron/SKILL.md +217 -0
- package/templates/skills/cron/manage-cron.py +434 -0
- package/templates/skills/halo/SKILL.md +98 -0
- package/templates/skills/nova-web-search/SKILL.md +65 -0
- package/templates/skills/self/SKILL.md +139 -0
- package/templates/skills/send-file/SKILL.md +28 -0
- package/templates/skills/send-file/feishu.md +16 -0
- package/templates/skills/send-file/slack.md +7 -0
- package/templates/skills/send-file/telegram.md +9 -0
- package/templates/skills/send-file/web.md +6 -0
- package/templates/skills/send-file/wechat.md +8 -0
- package/templates/skills/skill/SKILL.md +131 -0
- package/templates/skills/workspace/SKILL.md +28 -0
- package/templates/skills/workspace/setup-tidy.md +265 -0
- package/templates/skills/workspace/share.md +187 -0
- package/templates/skills/workspace/stage.py +487 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Web
|
|
2
|
+
|
|
3
|
+
Talk to a halo agent over plain HTTP from any client you control — a browser, a curl script, a custom frontend, your own mobile app. The Web channel is the "build your own UI" channel: it gives you a token, you give the token to whatever client you wrote.
|
|
4
|
+
|
|
5
|
+
> If you want a ready-made browser frontend without writing code, halo ships `packages/web-demo` — a tiny Express app that wraps the Web channel with its own password gate. See "Standalone web-demo frontend" at the bottom.
|
|
6
|
+
|
|
7
|
+
## What you'll end up with
|
|
8
|
+
|
|
9
|
+
- A 24-byte random token (base64url-encoded) bound to one workspace
|
|
10
|
+
- A few public HTTP endpoints under `/api/web/*` that accept that token
|
|
11
|
+
|
|
12
|
+
The token is **the** credential — anyone holding it can talk to the agent at the bound workspace's access level. Treat it like a password.
|
|
13
|
+
|
|
14
|
+
## Step 1 — Create an account
|
|
15
|
+
|
|
16
|
+
Open halo admin → **Channels** → **Web** → **Add Account**:
|
|
17
|
+
|
|
18
|
+
| Field | Value |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Workspace path | absolute path, e.g. `/home/ubuntu/my-project` |
|
|
21
|
+
| Label | optional |
|
|
22
|
+
| Access level | `readonly` (default), `workspace`, or `full` |
|
|
23
|
+
| Language | `en` or `zh` |
|
|
24
|
+
|
|
25
|
+
Click **Create**. The success screen shows the auto-generated token **once** — copy it now, you can't retrieve it again. (You can always delete the account and create a new one if you lose the token.)
|
|
26
|
+
|
|
27
|
+
## Step 2 — Use the token
|
|
28
|
+
|
|
29
|
+
All public endpoints require an `x-token: <token>` header (or `?token=<token>` query for endpoints that can't easily set headers, like SSE in browsers).
|
|
30
|
+
|
|
31
|
+
### Send a message (SSE stream back)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
curl -N -H "x-token: $TOKEN" -H "Content-Type: application/json" \
|
|
35
|
+
-d '{"message":"hello"}' \
|
|
36
|
+
http://localhost:9527/api/web/chat
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Response is a stream of `data: {json}\n\n` SSE frames:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
data: {"type":"session","sessionId":"web_abc123_m1xyz"}
|
|
43
|
+
data: {"type":"thinking","text":"..."}
|
|
44
|
+
data: {"type":"tool_call","toolName":"file_read","toolInput":{...}}
|
|
45
|
+
data: {"type":"tool_result","toolName":"file_read","result":"..."}
|
|
46
|
+
data: {"type":"stream","text":"Hello! "}
|
|
47
|
+
data: {"type":"stream","text":"How can I help?"}
|
|
48
|
+
data: {"type":"complete"}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Parse the `type` field on each event to render text vs tool calls vs completion.
|
|
52
|
+
|
|
53
|
+
### Other endpoints
|
|
54
|
+
|
|
55
|
+
| Method | Path | Purpose |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `POST /api/web/chat` | Send a message; SSE response |
|
|
58
|
+
| `POST /api/web/stop` | Cancel the running task |
|
|
59
|
+
| `GET /api/web/history` | Fetch session message history |
|
|
60
|
+
| `GET /api/web/subscribe` | Reconnect to a running session's SSE stream |
|
|
61
|
+
|
|
62
|
+
All four accept the same auth header.
|
|
63
|
+
|
|
64
|
+
### Per-request overrides
|
|
65
|
+
|
|
66
|
+
By default each token is locked to the workspace and active session set by the admin. External integrations (notably the [ACP adapter](acp.md)) need finer control:
|
|
67
|
+
|
|
68
|
+
- `workspace` — server-side absolute path, **gated on `accessLevel === 'full'`** (readonly / workspace tokens can't escape their bound workspace; the override is rejected)
|
|
69
|
+
- `sessionId` — explicit halo session id; lets clients pre-mint stable ids and address them across reconnects
|
|
70
|
+
- `agentId` — only used when the request creates a new session
|
|
71
|
+
|
|
72
|
+
These can be passed as POST body fields, headers (`x-workspace`, `x-session-id`, `x-agent-id`), or query params (`?workspace=…&sessionId=…&agentId=…`). POST body wins on conflict.
|
|
73
|
+
|
|
74
|
+
For browser apps you almost never want these — leave them off and use the per-token defaults.
|
|
75
|
+
|
|
76
|
+
## Step 3 — Send images / files
|
|
77
|
+
|
|
78
|
+
`/api/web/chat` accepts an optional `images` array, base64-encoded:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"message": "what's in this picture?",
|
|
83
|
+
"images": [
|
|
84
|
+
{ "data": "<base64>", "mimeType": "image/png" }
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Images go to the LLM as multimodal content. Audio and other binary uploads aren't supported on this endpoint directly — for those, save the file to `<workspace>/.halo/assets/web/inbound/<accountId>/<date>/` first (out-of-band) and reference its path in your message text.
|
|
90
|
+
|
|
91
|
+
The standalone web-demo handles voice + arbitrary files for you; if you want that, use it as a reference implementation.
|
|
92
|
+
|
|
93
|
+
## Slash commands
|
|
94
|
+
|
|
95
|
+
Slash commands are intercepted before they reach the agent — same set as every other channel:
|
|
96
|
+
|
|
97
|
+
| Command | Effect |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `/session <verb>` | Session lifecycle: `new` / `list` / `switch <n>` / `stop` / `interrupt` / `compact` / `context` |
|
|
100
|
+
| `/agent <verb>` | Manage agents (`list` / `switch` / `desc` open to all; `delete` full; `create` / `update` via skill, full) |
|
|
101
|
+
| `/skill <verb>` | Manage skills (`list` / `desc` open; `disable` / `enable` workspace; `delete` full; `create` / `update` via skill, full) |
|
|
102
|
+
| `/workspace <verb>` | Workspace: `info` (all) / `switch <path>` (full) / `setup` / `tidy` (workspace) / `share` (full) |
|
|
103
|
+
| `/help` | List commands — object commands show only the verbs you can run |
|
|
104
|
+
|
|
105
|
+
Send a slash command exactly like a normal message — the server detects the leading `/`.
|
|
106
|
+
|
|
107
|
+
## Common problems
|
|
108
|
+
|
|
109
|
+
| Symptom | Cause / fix |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `401` on every call | Missing `x-token` header, or token is for a deleted account |
|
|
112
|
+
| `403` when passing `workspace=…` | Token is `readonly` / `workspace` access — only `full` can override |
|
|
113
|
+
| SSE stream hangs forever | Reverse proxy buffering. Disable buffering for `text/event-stream` (nginx: `proxy_buffering off`, Cloudflare: enable streaming) |
|
|
114
|
+
| Token leaked accidentally | Delete the account in admin, create a new one. The old token is invalidated immediately |
|
|
115
|
+
| Want to share one token across multiple users | Don't — every request would land on the same active session. Create one account per user / app |
|
|
116
|
+
|
|
117
|
+
## Standalone web-demo frontend
|
|
118
|
+
|
|
119
|
+
If you want a browser UI with login, image upload, voice recording, and multi-language support without writing it yourself:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cd packages/web-demo
|
|
123
|
+
node server.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Environment variables:
|
|
127
|
+
|
|
128
|
+
| Variable | Required | Description |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `HALO_API` | yes | Halo server URL, e.g. `http://localhost:9527` |
|
|
131
|
+
| `HALO_TOKEN` | yes | The web-channel token from Step 1 |
|
|
132
|
+
| `HALO_WEB_DEMO_PASSWORD` | no | Password gate; empty means open access |
|
|
133
|
+
| `PORT` | no | Listen port; default `9528` |
|
|
134
|
+
|
|
135
|
+
The demo holds your token server-side and exposes its own password-based session — the browser never sees the halo token. Open `http://localhost:9528` to use it.
|
|
136
|
+
|
|
137
|
+
## Security notes
|
|
138
|
+
|
|
139
|
+
- **Tokens are unhashed** in `~/.halo/secrets/channels/channels.db`. Restrict that file to the user that runs halo
|
|
140
|
+
- **No rate limit at the channel level** — if you expose the API on the public internet, put a reverse proxy with rate limits in front
|
|
141
|
+
- **Admin endpoints** (`POST /api/web/accounts`, `PATCH`, `DELETE`) require admin cookie auth, **not** the token. They're for the admin panel, not for the token holder
|
|
142
|
+
- A `full`-access token can call `/workspace <abs-path>` to switch the bound workspace database-side. If you don't want that, give out `workspace` or `readonly` tokens instead
|
|
143
|
+
|
|
144
|
+
## Reference
|
|
145
|
+
|
|
146
|
+
- Code: `packages/server/src/channels/web/`
|
|
147
|
+
- Routes: `packages/server/src/routes/web.ts`
|
|
148
|
+
- Admin UI: `packages/admin/src/features/web/web-settings.tsx`
|
|
149
|
+
- Design notes: [../../design/web.md](../../design/web.md)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# WeChat (微信)
|
|
2
|
+
|
|
3
|
+
Talk to a halo agent from WeChat on your phone. Halo registers an **iLink-style bot** with `ilinkai.weixin.qq.com` and you bind it by **scanning a QR code with WeChat** — no developer registration, no public webhook needed.
|
|
4
|
+
|
|
5
|
+
> The iLink bot is a personal-account bot, not a Public Account / Mini Program. The bot you scan-bind to is the account you'll DM in WeChat — there's no separate "follow this bot" step.
|
|
6
|
+
|
|
7
|
+
## What you'll end up with
|
|
8
|
+
|
|
9
|
+
- A bot account row keyed by your WeChat user id (the one that scanned the QR)
|
|
10
|
+
- An `ilinkai` long-poll loop pulling messages on behalf of that bot
|
|
11
|
+
- Bot owner = whoever scanned the QR. The same WeChat ID is used as the default cron-job recipient
|
|
12
|
+
|
|
13
|
+
## Step 1 — Create a workspace folder
|
|
14
|
+
|
|
15
|
+
You need an existing absolute path on the server before scanning. Either:
|
|
16
|
+
|
|
17
|
+
- Open the workspace in halo's web UI (the `.halo/` folder gets auto-created), then copy the absolute path
|
|
18
|
+
- Or `mkdir -p /home/ubuntu/my-project` from a terminal
|
|
19
|
+
|
|
20
|
+
Halo auto-creates `.halo/` inside the folder if it doesn't exist; the path itself must already exist.
|
|
21
|
+
|
|
22
|
+
## Step 2 — Open the admin scan flow
|
|
23
|
+
|
|
24
|
+
Open halo admin → **Channels** → **WeChat** → **Add Account**.
|
|
25
|
+
|
|
26
|
+
The form is **just the workspace + label + access level + language** — no bot token field, because the token comes from the scan:
|
|
27
|
+
|
|
28
|
+
| Field | Value |
|
|
29
|
+
|---|---|
|
|
30
|
+
| Workspace path | absolute path from Step 1, e.g. `/home/ubuntu/my-project` |
|
|
31
|
+
| Label | optional, shown in admin's account list |
|
|
32
|
+
| Access level | `readonly` (default), `workspace`, or `full` |
|
|
33
|
+
| Language | `en` or `zh` |
|
|
34
|
+
|
|
35
|
+
Click **Generate QR**. Halo hits `ilinkai.weixin.qq.com` to mint a fresh QR code and starts a poll loop waiting for the scan.
|
|
36
|
+
|
|
37
|
+
## Step 3 — Scan with WeChat
|
|
38
|
+
|
|
39
|
+
1. Open WeChat on your phone
|
|
40
|
+
2. Tap the `+` in the top right → **Scan / 扫一扫**
|
|
41
|
+
3. Aim at the QR shown in the admin UI
|
|
42
|
+
4. Tap **Confirm Login / 确认登录** on the phone
|
|
43
|
+
|
|
44
|
+
Within a few seconds the admin UI shows "登录成功" / "Logged in" and switches to the success page. Behind the scenes:
|
|
45
|
+
|
|
46
|
+
- iLink returns the bot's token, the IDC-specific `baseUrl`, and your WeChat-side `ilink_user_id`
|
|
47
|
+
- Halo writes those into the new account row
|
|
48
|
+
- The long-poll loop starts immediately — the bot is now live
|
|
49
|
+
|
|
50
|
+
The QR is valid for ~3 minutes; if it expires the admin UI auto-refreshes. If you cancel and come back later, just open the form again — a new QR is minted.
|
|
51
|
+
|
|
52
|
+
## Step 4 — Test it
|
|
53
|
+
|
|
54
|
+
The bot's name in your WeChat contacts is whatever the iLink platform set it to (typically a generic placeholder like `小助手`; you can rename it locally). Open the bot's chat in WeChat and send `hello` → expect a streamed reply.
|
|
55
|
+
|
|
56
|
+
If nothing happens, check halo server logs for `[weixin]` lines.
|
|
57
|
+
|
|
58
|
+
## How halo handles inbound
|
|
59
|
+
|
|
60
|
+
- **Text** — sent to the agent
|
|
61
|
+
- **Images** — passed to the LLM as multimodal content
|
|
62
|
+
- **Voice** — decrypted, saved under `<workspace>/.halo/assets/weixin/inbound/<accountId>/<date>/`, path included in the agent's input
|
|
63
|
+
- **Video / files** — same as voice
|
|
64
|
+
- **Group chats** — not supported in v1 (group messages are dropped)
|
|
65
|
+
- **Self-loop** — bot-authored messages are filtered out
|
|
66
|
+
|
|
67
|
+
## Slash commands
|
|
68
|
+
|
|
69
|
+
Same set as the other channels — type as plain text in your WeChat DM with the bot:
|
|
70
|
+
|
|
71
|
+
| Command | Effect |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `/session <verb>` | Session lifecycle: `new` / `list` / `switch <n>` / `stop` / `interrupt` / `compact` / `context` |
|
|
74
|
+
| `/agent <verb>` | Manage agents (`list` / `switch` / `desc` open to all; `delete` full; `create` / `update` via skill, full) |
|
|
75
|
+
| `/skill <verb>` | Manage skills (`list` / `desc` open; `disable` / `enable` workspace; `delete` full; `create` / `update` via skill, full) |
|
|
76
|
+
| `/workspace <verb>` | Workspace: `info` (all) / `switch <path>` (full) / `setup` / `tidy` (workspace) / `share` (full) |
|
|
77
|
+
| `/help` | List commands — object commands show only the verbs you can run |
|
|
78
|
+
| `/qr [level]` | Generate an invite QR (admin only) |
|
|
79
|
+
|
|
80
|
+
## Cron jobs targeting WeChat
|
|
81
|
+
|
|
82
|
+
WeChat is single-recipient — cron output goes to the QR-bind owner (the WeChat user who scanned in Step 3). The dispatcher resolves recipients in this order:
|
|
83
|
+
|
|
84
|
+
1. Explicit `chatId` on the cron target row (set when the cron is created from inside WeChat)
|
|
85
|
+
2. The QR-bind owner (`account.userId`) — the "report to me on a schedule" default
|
|
86
|
+
3. Most-recent inbound chat ID, as a fallback for shared bots
|
|
87
|
+
|
|
88
|
+
Fan-out across multiple WeChat users is not supported — one bot, one owner.
|
|
89
|
+
|
|
90
|
+
## Common problems
|
|
91
|
+
|
|
92
|
+
| Symptom | Cause / fix |
|
|
93
|
+
|---|---|
|
|
94
|
+
| QR shows but scan does nothing | iLink platform thinks the QR is for a different account. Cancel and regenerate |
|
|
95
|
+
| "二维码已过期" / QR expired | Admin UI should auto-refresh. If not, click Generate again |
|
|
96
|
+
| Bot stops responding after a few hours | Long-poll likely lost its `syncBuf`. Restart the server; reconnect is automatic |
|
|
97
|
+
| Two halo processes both poll the same bot | Each process gets a copy of every message, replied twice. Make sure only one server runs — see `~/.halo/global/server.pid` |
|
|
98
|
+
| Group chat doesn't trigger the bot | Expected — groups aren't supported in v1 |
|
|
99
|
+
| Sent voice message returns no reply | Check that the account has `workspace` or `full` access; readonly cannot save inbound media |
|
|
100
|
+
|
|
101
|
+
## Multi-workspace / multi-bot
|
|
102
|
+
|
|
103
|
+
Each scan = one account = one workspace binding. To use a second workspace, open the admin form again and scan a second time (with the same WeChat user or a different one). Each scan mints a fresh `ilink_bot_id` even from the same WeChat account, so the two are independent.
|
|
104
|
+
|
|
105
|
+
## Reference
|
|
106
|
+
|
|
107
|
+
- Code: `packages/server/src/channels/wechat/`
|
|
108
|
+
- Login flow: `packages/server/src/channels/wechat/login.ts`
|
|
109
|
+
- Admin UI: `packages/admin/src/features/weixin/weixin-settings.tsx`
|
|
110
|
+
- Design notes: [../../design/wechat.md](../../design/wechat.md)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Chat — User Guide
|
|
2
|
+
|
|
3
|
+
The Chat panel at the bottom is the main surface for talking to an agent.
|
|
4
|
+
|
|
5
|
+
## Picking an agent
|
|
6
|
+
|
|
7
|
+
The dropdown to the left of the input lists every agent (global + workspace).
|
|
8
|
+
|
|
9
|
+
- The agent with the highest `priority` is auto-selected for new sessions. The seed `Default` agent uses `priority: 99`, so it wins until you raise another agent above it.
|
|
10
|
+
- Once you manually pick an agent, that choice is remembered across `clear` / new sessions until you pick something else.
|
|
11
|
+
- **A conversation is locked to one agent**: once you start chatting, the dropdown locks. To change agent, start a new session (`/session new`).
|
|
12
|
+
|
|
13
|
+
## Sending messages
|
|
14
|
+
|
|
15
|
+
- Enter to send
|
|
16
|
+
- Shift+Enter for a newline
|
|
17
|
+
- The agent streams its reply; tool calls render inline as cards
|
|
18
|
+
|
|
19
|
+
## Context injection
|
|
20
|
+
|
|
21
|
+
Next to the chat is a `📎 Context` toggle (on by default). When on, Halo auto-injects:
|
|
22
|
+
- The currently open file path: `[Currently viewing: src/foo.ts]`
|
|
23
|
+
- The editor's current selection: `[Selected text in foo.ts:10-25]\n\`\`\`...\n\`\`\``
|
|
24
|
+
|
|
25
|
+
Turn it off if you don't want that context injected.
|
|
26
|
+
|
|
27
|
+
## `@` file mention
|
|
28
|
+
|
|
29
|
+
Typing `@` in the input opens a file search:
|
|
30
|
+
- Real-time fuzzy matching (150 ms debounce)
|
|
31
|
+
- Selecting inserts a path chip
|
|
32
|
+
- You can `@` multiple files back-to-back
|
|
33
|
+
|
|
34
|
+
The search scans the whole project on the server — independent of Explorer expansion state.
|
|
35
|
+
|
|
36
|
+
## Attachments
|
|
37
|
+
|
|
38
|
+
- **Drag**: drop files onto the input
|
|
39
|
+
- **Paste**: paste an image from the clipboard
|
|
40
|
+
- **Button**: click the 📎 on the left
|
|
41
|
+
|
|
42
|
+
Images are sent to the agent as base64, with multimodal support (Claude 4.6 can see images).
|
|
43
|
+
|
|
44
|
+
## Slash commands
|
|
45
|
+
|
|
46
|
+
Typing `/` opens autocomplete.
|
|
47
|
+
|
|
48
|
+
Most commands are noun-verb **object commands**: `/<obj> <verb> [args]`. Bare `/<obj>` (or `/<obj> help`) lists the verbs you're allowed to run.
|
|
49
|
+
|
|
50
|
+
| Command | Purpose |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `/session <verb>` | Manage sessions — `new` / `list` / `switch <n>` / `stop` / `interrupt` / `compact` / `context`. All built-in, available to everyone. `new` starts a fresh conversation (old session stays in the sidebar; running sub-agents keep going); `compact` keeps the most recent N messages intact (N defaults to 5, `general.compact.keep_messages`); `context` shows token usage, agent info, and available tools |
|
|
53
|
+
| `/clear` | Admin-UI alias for `/session new` |
|
|
54
|
+
| `/agent <verb>` | Manage agents — `list` / `switch <name\|index>` / `desc` (built-in, open to all) · `delete` (built-in, full access) · `create` / `update` (handled by the `agent` skill, full access) |
|
|
55
|
+
| `/skill <verb>` | Manage skills — `list` / `desc` (built-in, open to all) · `disable` / `enable` (built-in, workspace access) · `delete` (built-in, full access) · `create` / `update` (handled by the `skill` skill, full access) |
|
|
56
|
+
| `/workspace <verb>` | Manage the workspace — `info` (built-in, open to all) · `switch <path>` (built-in, full access) · `setup` / `tidy` (workspace skill, workspace access; init / reorganize `.halo/` INDEX.md / INSTRUCTIONS.md / memory/) · `share` (workspace skill, full access; export a shareable bundle) |
|
|
57
|
+
| `/cron <verb>` | Scheduled agent runs — `create` / `list` / `update` / `enable` / `disable` / `delete` (cron skill, full access) |
|
|
58
|
+
| `/acp <verb>` | Talk to other agents over ACP — `kiro <q>` / `claude <q>` ask a local agent directly; `add` / `list` / `remove` manage generated `ask-<label>` bindings (acp skill, full access) |
|
|
59
|
+
| `/evo [hint]` | Queue a self-evolution run on this session (full access only) |
|
|
60
|
+
| `/help` | List every command — object commands only show the verbs you can run |
|
|
61
|
+
|
|
62
|
+
Skills can also register slash commands (put `command: /xxx` in the SKILL.md frontmatter).
|
|
63
|
+
|
|
64
|
+
### WeChat channel commands
|
|
65
|
+
|
|
66
|
+
If you're chatting from WeChat, the same shared commands are available (routed through the common command dispatcher), plus one WeChat-specific extra:
|
|
67
|
+
|
|
68
|
+
| Command | Purpose |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `/session new` | Create a new session; old sessions stay accessible via `/session list` + `/session switch` (nothing is archived) |
|
|
71
|
+
| `/session list` | List recent sessions (newest first); the active one is marked `→` |
|
|
72
|
+
| `/session switch <index>` | Switch the active session to the indexed one (readonly bot 仅能切到自己的 [我] 会话) |
|
|
73
|
+
| `/workspace info` / `/workspace switch <path>` | Show or switch workspace (absolute path; 切换仅 full 权限 bot 可用) |
|
|
74
|
+
| `/qr [level]` | Generate an invite QR for a new bot account (full 权限 bot 专用) |
|
|
75
|
+
| `/help` | Show help |
|
|
76
|
+
|
|
77
|
+
If the session is currently compacting or busy when your message arrives, you'll see a hint — ("⏳ integrating context…" / "🔄 queued…") — and the message is queued (while compacting it's dropped; while busy it's kept).
|
|
78
|
+
|
|
79
|
+
## Interrupt vs Stop
|
|
80
|
+
|
|
81
|
+
Two ways to interrupt the agent:
|
|
82
|
+
|
|
83
|
+
**Graceful interrupt**: send another message during streaming. The message is queued on the server; at the next tool-call checkpoint, the agent wraps up the current turn and then runs the queued message. Multiple messages can queue in order.
|
|
84
|
+
|
|
85
|
+
**Hard stop**: click the red ⏹ button. Immediate abort, queue cleared, no checkpoint waiting.
|
|
86
|
+
|
|
87
|
+
## Token ring
|
|
88
|
+
|
|
89
|
+
The ring in the bottom-right of the input shows context window usage:
|
|
90
|
+
- Green: < 50%
|
|
91
|
+
- Yellow: 50–70%
|
|
92
|
+
- Orange: 70–90%
|
|
93
|
+
- Red: > 90%
|
|
94
|
+
|
|
95
|
+
Reaching `compressAt` (default 70%) auto-triggers compact. While the agent is running you can't click the TokenRing (guarded by `isStreaming`).
|
|
96
|
+
|
|
97
|
+
## Session history
|
|
98
|
+
|
|
99
|
+
Next to the header is the session-list dropdown:
|
|
100
|
+
- Lists every session in the current workspace
|
|
101
|
+
- Click to switch (the current one auto-saves + detaches)
|
|
102
|
+
- Sub-agent sessions show as indented entries
|
|
103
|
+
|
|
104
|
+
For full inspection, use the Activity Bar's "Sessions" tab — Debug mode lets you inspect tool calls, system prompts, usage, etc.
|
|
105
|
+
|
|
106
|
+
## Common situations
|
|
107
|
+
|
|
108
|
+
**"Queued" hint**: the previous turn hasn't finished; your message is queued and will run next turn.
|
|
109
|
+
|
|
110
|
+
**"Rate limited, retrying in Xs..."**: Bedrock throttled; automatic exponential backoff (up to 5 retries).
|
|
111
|
+
|
|
112
|
+
**A sudden `[Message from xxx]`**: a sub-agent finished and auto-reported back to the parent agent's conversation.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# CLI / TUI
|
|
2
|
+
|
|
3
|
+
Standalone terminal client for Halo. Runs the agent loop directly in the CLI process — no server required. Shares the same agent core, tools, session management, and command system as the admin panel and other channels.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm --filter @turmind/halo-cli build
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The binary is at `packages/cli/bin/halo.js`. For global access, link it:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm --filter @turmind/halo-cli link --global
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Publishing to npm (maintainers)
|
|
18
|
+
|
|
19
|
+
The published package is `@turmind/halo` — a self-contained esbuild bundle
|
|
20
|
+
(CLI + server + admin-out + templates), staged under `packages/cli/dist-pub/`
|
|
21
|
+
by `scripts/build-bundle.mjs`. The workspace `@turmind/halo-cli` can't be
|
|
22
|
+
published directly (it has `workspace:*` deps); the bundle flattens them.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 1. bump packages/cli/package.json "version" (e.g. 0.1.2)
|
|
26
|
+
# 2. build the upstream artifacts the bundle consumes
|
|
27
|
+
pnpm --filter @turmind/halo-core build
|
|
28
|
+
pnpm --filter @turmind/halo-server build
|
|
29
|
+
cd packages/admin && npx next build --no-lint && node scripts/copy-monaco.mjs && cd ../..
|
|
30
|
+
# 3. stage the release bundle — HALO_RELEASE=1 stamps the bare version
|
|
31
|
+
# (0.1.2), NOT the default <version>-<sha>: a `-<sha>` suffix is a semver
|
|
32
|
+
# prerelease that `npm install` skips and never tags as `latest`.
|
|
33
|
+
HALO_RELEASE=1 node packages/cli/scripts/build-bundle.mjs
|
|
34
|
+
# 4. preview + publish
|
|
35
|
+
cd packages/cli/dist-pub
|
|
36
|
+
npm pack --dry-run # inspect tarball contents
|
|
37
|
+
npm publish # @turmind/halo@<version>, tag latest, public
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
npm versions are immutable — a published version can never be overwritten,
|
|
41
|
+
so bump first and verify with `npm pack --dry-run` before `npm publish`.
|
|
42
|
+
End users then install with `npm install -g @turmind/halo`.
|
|
43
|
+
|
|
44
|
+
## CLI Mode (non-interactive)
|
|
45
|
+
|
|
46
|
+
Run a one-shot prompt and exit:
|
|
47
|
+
|
|
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
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Options
|
|
56
|
+
|
|
57
|
+
| Flag | Short | Default | Description |
|
|
58
|
+
|---|---|---|---|
|
|
59
|
+
| `--workspace` | `-w` | cwd | Workspace path |
|
|
60
|
+
| `--agent` | `-a` | `default` | Agent ID |
|
|
61
|
+
| `--session` | `-s` | auto | Resume session by ID |
|
|
62
|
+
| `--format` | `-f` | `text` | Output format: `text` or `json` |
|
|
63
|
+
| `--verbose` | `-v` | off | Show thinking, tool calls, usage on stderr |
|
|
64
|
+
| `--access` | | `full` | Access level: `full`, `workspace`, `readonly` |
|
|
65
|
+
| `--agents` | | | List available agents and exit |
|
|
66
|
+
| `--sessions` | | | List recent sessions and exit |
|
|
67
|
+
| `--lang` | | `en` | Language: `en` or `zh` |
|
|
68
|
+
|
|
69
|
+
### Output
|
|
70
|
+
|
|
71
|
+
- **text format**: Agent response is rendered as styled markdown (headings, bold, code blocks, tables) on stdout. Tool calls, thinking, usage go to stderr (visible with `-v`).
|
|
72
|
+
|
|
73
|
+
Usage line mirrors the admin chat-panel badge format (timestamp / in / out / ctx / read / write / cache% / ttft / e2e / think / model). `ctx` is the rolled-up context size — `inputTokens + cacheRead + cacheWrite + outputTokens` — so it doesn't look misleading next to a large cache hit:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
[ 17:23:02 in 0.0K out 0.1K ctx 5.8K read 5.3K write 0.3K cache 94% e2e 3.3s think medium claude-sonnet-4-6 ]
|
|
77
|
+
```
|
|
78
|
+
- **json format**: Single JSON object on stdout after completion:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"text": "...",
|
|
83
|
+
"sessionId": "cli_abc123",
|
|
84
|
+
"toolCalls": [{ "name": "file_list", "durationMs": 1 }],
|
|
85
|
+
"usage": { "inputTokens": 6, "outputTokens": 42, "cacheReadInputTokens": 10000, "modelId": "..." },
|
|
86
|
+
"error": null
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Pipeline integration
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Code review in CI
|
|
94
|
+
halo -w /path/to/review-ws "review the diff" --format json | jq '.text'
|
|
95
|
+
|
|
96
|
+
# Pipe content in
|
|
97
|
+
git diff HEAD~1 | halo -w /path/to/review-ws "review this diff"
|
|
98
|
+
|
|
99
|
+
# Exit code: 0 = success, 1 = error, 130 = SIGINT
|
|
100
|
+
halo "check for issues" && echo "OK" || echo "FAILED"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## TUI Mode (interactive)
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
halo -i
|
|
107
|
+
halo -i -w /path/to/workspace
|
|
108
|
+
halo -i -s sid_abc123 # resume session
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Multi-turn conversation. Supports all standard Halo slash commands:
|
|
112
|
+
|
|
113
|
+
| Command | Description |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `/help` | Show available commands |
|
|
116
|
+
| `/session new` | Start a new session |
|
|
117
|
+
| `/session list` | List recent sessions |
|
|
118
|
+
| `/session switch <n>` | Switch to session by number |
|
|
119
|
+
| `/session stop` | Stop current agent task (ends the turn, no re-run) |
|
|
120
|
+
| `/session interrupt` | Interrupt the running turn now (aborts a command mid-run); any messages queued while busy then run as one follow-up turn |
|
|
121
|
+
| `/session compact` | Compact session context |
|
|
122
|
+
| `/session context` | Show context window + agent info |
|
|
123
|
+
| `/agent <verb>` | Manage agents: `list` / `switch <name\|index>` / `desc` / `delete` / `create` / `update` |
|
|
124
|
+
| `/skill <verb>` | Manage skills: `list` / `desc` / `disable` / `enable` / `delete` / `create` / `update` |
|
|
125
|
+
| `/workspace info` | Show current workspace |
|
|
126
|
+
| `/workspace switch <path>` | Switch workspace (full access only) |
|
|
127
|
+
| `/workspace setup` / `/workspace tidy` / `/workspace share` | Set up / tidy the `.halo/` knowledge files, or export a shareable bundle (workspace skill) |
|
|
128
|
+
| `/cron <verb>` | Manage scheduled agent runs: `create` / `list` / `update` / `enable` / `disable` / `delete` |
|
|
129
|
+
| `/acp <verb>` | Ask other agents over ACP (`kiro <q>` / `claude <q>`) and manage `ask-*` bindings (`add` / `list` / `remove`) |
|
|
130
|
+
| `/evo [hint]` | Queue a self-evolution run on this session (full access only) |
|
|
131
|
+
| `/quit` | Exit |
|
|
132
|
+
|
|
133
|
+
Bare `/<obj>` (or `/<obj> help`) lists the verbs you may run. Verbs gated above your access level are hidden.
|
|
134
|
+
|
|
135
|
+
### Keybindings
|
|
136
|
+
|
|
137
|
+
| Key | Action |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `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
|
+
| `Ctrl+C` | Graceful exit; press twice to force |
|
|
141
|
+
| `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) |
|
|
143
|
+
|
|
144
|
+
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`).
|
|
145
|
+
|
|
146
|
+
## File, Image, and Scope References
|
|
147
|
+
|
|
148
|
+
Attach files or images to your message with `@file` and `@image`, or pull a directory's instructions into the turn with `@scope`:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
> summarize @file src/index.ts
|
|
152
|
+
> compare @file a.ts and @file b.ts
|
|
153
|
+
> describe @image screenshot.png
|
|
154
|
+
> review @file "path with spaces/readme.md"
|
|
155
|
+
> @scope packages/server refactor the session manager
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- `@file path` — reads the file and inlines its content in the message as `<file>` block
|
|
159
|
+
- `@image path` — reads the image as base64 and sends it via the model's vision input
|
|
160
|
+
- `@file photo.png` — image extensions (`.png`, `.jpg`, `.gif`, `.webp`, `.bmp`) are auto-detected as images
|
|
161
|
+
- `@scope dir` — injects the directory-scoped `.halo/INSTRUCTIONS.md` along the path from the workspace root down to `dir` (root level excluded — it's already in the system prompt) into **this turn only**. Use it to bring a sub-directory's conventions into scope for one request. It does not change where tools run.
|
|
162
|
+
- Paths are relative to the workspace; absolute paths also work
|
|
163
|
+
- Quoted paths supported for filenames with spaces: `@file "my file.txt"`
|
|
164
|
+
- **Tab completion** in TUI mode: type `@file ` (or `@scope `, which lists directories only) then press Tab to browse
|
|
165
|
+
|
|
166
|
+
### Limits
|
|
167
|
+
|
|
168
|
+
- **Text files**: truncated at 100KB with a `[truncated]` marker
|
|
169
|
+
- **Images**: skipped if larger than 5MB
|
|
170
|
+
- If the current model does not support vision, a warning is shown and images are ignored
|
|
171
|
+
|
|
172
|
+
## Architecture
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
packages/cli/
|
|
176
|
+
src/
|
|
177
|
+
index.ts — Entry: arg parsing, mode dispatch, SIGINT handling
|
|
178
|
+
harness.ts — Shared agent harness wrapping SessionManager
|
|
179
|
+
cli.ts — Non-interactive: stdin/args → agent → stdout → exit
|
|
180
|
+
tui.ts — Interactive: readline loop + event display + commands
|
|
181
|
+
format-usage.ts — Usage-line formatter (mirrors admin UsageLine badge order)
|
|
182
|
+
resolve-refs.ts — @file / @image reference resolution with size limits
|
|
183
|
+
render-md.ts — Terminal markdown rendering (marked + marked-terminal)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The CLI directly imports server agent-core modules (`SessionManager`, `dispatchCommand`, tools, config, DB) via `@turmind/halo-server/*` subpath exports. No HTTP/WS layer is involved.
|
|
187
|
+
|
|
188
|
+
Session prefix: `cli_`. Sessions are persisted to `<workspace>/.halo/sessions/` and visible in the admin panel.
|
|
189
|
+
|
|
190
|
+
### Initialization
|
|
191
|
+
|
|
192
|
+
The CLI replicates the server's init sequence:
|
|
193
|
+
1. `initLogger()` — redirect console to stderr + file logger
|
|
194
|
+
2. `ensureHaloHome()` — ensure `~/.halo/` structure
|
|
195
|
+
3. `initBwrapCheck()` — probe sandbox availability
|
|
196
|
+
4. `setSandboxHiddenPaths()` — configure sandbox paths
|
|
197
|
+
5. `new SessionManager(workspace)` — create agent session manager
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
What to do the first time you open Halo.
|
|
4
|
+
|
|
5
|
+
## Log in
|
|
6
|
+
|
|
7
|
+
Open `http://localhost:9527` (or your deployment URL) in a browser and enter the password.
|
|
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`
|
|
11
|
+
|
|
12
|
+
## Open a workspace
|
|
13
|
+
|
|
14
|
+
After login, you land in the workspace. A URL with `?folder=/abs/path` opens that directory directly; without `?folder`, Halo falls back to your home directory as the workspace — everything still works.
|
|
15
|
+
|
|
16
|
+
The Explorer top bar has two ways to switch workspace:
|
|
17
|
+
- **Type an absolute path** + Enter — invalid paths raise an error
|
|
18
|
+
- **Click the 📁🔍 button** — opens a VS Code-style directory picker: single click to select, double click to enter, ArrowUp to go up, 🏠 for home, paste paths into the top input
|
|
19
|
+
|
|
20
|
+
Halo auto-creates a `.halo/` subdirectory in the target folder (for sessions, agents, skills, memory). If `.halo/` already exists, opening the folder just works.
|
|
21
|
+
|
|
22
|
+
## First conversation (bootstrap)
|
|
23
|
+
|
|
24
|
+
The first time a new user chats with the Default agent, the agent asks a few questions:
|
|
25
|
+
- What should I call you?
|
|
26
|
+
- What would you like to call me?
|
|
27
|
+
- Preferred communication style (formal/casual, English/other language, etc.)
|
|
28
|
+
|
|
29
|
+
Your answers are written to `~/.halo/global/USER.md`; from then on every root agent reads that user profile.
|
|
30
|
+
|
|
31
|
+
> Don't want the bootstrap flow? Create `~/.halo/global/USER.md` manually (any content) and the agent will skip the guided flow.
|
|
32
|
+
|
|
33
|
+
### Workspace onboarding
|
|
34
|
+
|
|
35
|
+
The global `INSTRUCTIONS.md` template explains Halo's `.halo/` conventions (`INDEX.md`, `INSTRUCTIONS.md`, `memory/`). When the current workspace has no `INDEX.md`, the system prompt also nudges the agent to offer drafting one from the README / package.json. If you want a guided setup, type `/workspace setup`; to clean up an existing workspace later, type `/workspace tidy` — both backed by the `workspace` skill (setup: interview + draft; tidy: review + prune + reshape).
|
|
36
|
+
|
|
37
|
+
## Send a message
|
|
38
|
+
|
|
39
|
+
In the bottom Chat panel:
|
|
40
|
+
1. Type in the input
|
|
41
|
+
2. Enter to send (Shift+Enter for newline)
|
|
42
|
+
3. The agent streams its reply, showing text + tool call cards
|
|
43
|
+
|
|
44
|
+
You can keep typing while it replies — messages queue and run at the next safe checkpoint.
|
|
45
|
+
|
|
46
|
+
**Stop button** (red): interrupt immediately, no checkpoint waiting.
|
|
47
|
+
|
|
48
|
+
## Handy shortcuts
|
|
49
|
+
|
|
50
|
+
| Action | Shortcut / Method |
|
|
51
|
+
|---|---|
|
|
52
|
+
| File mention | Type `@` in the input, pick a file |
|
|
53
|
+
| Slash command | Type `/`, auto-complete pops up (`/session`, `/agent`, …) |
|
|
54
|
+
| Quick find file | `Cmd/Ctrl+P` |
|
|
55
|
+
| Save file | `Cmd/Ctrl+S` |
|
|
56
|
+
| New conversation | `/session new` |
|
|
57
|
+
| Compact context | `/session compact` |
|
|
58
|
+
| Set up / reorganize workspace | `/workspace setup` / `/workspace tidy` |
|
|
59
|
+
|
|
60
|
+
## What `~/.halo/` looks like
|
|
61
|
+
|
|
62
|
+
After `halo setup`:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
~/.halo/
|
|
66
|
+
├── global/ ← server-managed, see overwrite policy below
|
|
67
|
+
│ ├── INSTRUCTIONS.md ← refreshed on upgrade
|
|
68
|
+
│ ├── prompts/{bootstrap,all,root}/ ← refreshed on upgrade
|
|
69
|
+
│ ├── models/<provider>.yaml ← refreshed on upgrade
|
|
70
|
+
│ ├── docs/ ← refreshed on upgrade (bundled platform docs)
|
|
71
|
+
│ ├── agents/ ← built-in ids refreshed; user-added ones untouched
|
|
72
|
+
│ └── skills/ ← built-in ids refreshed; user-added ones untouched
|
|
73
|
+
└── secrets/ ← never overwritten after first creation
|
|
74
|
+
├── config.yaml ← leaf-merged: new server knobs added, existing values kept
|
|
75
|
+
├── settings.yaml ← created empty if missing; otherwise untouched
|
|
76
|
+
└── channels/channels.db ← per-channel account state
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**When does "refreshed on upgrade" actually run?** `halo setup` always re-runs the seed; the server's startup check also re-runs it automatically when `~/.halo/global/.template-version` is behind the bundled `TEMPLATE_VERSION`. So the routine flow `halo upgrade && halo server restart` is enough — no need to remember `halo setup`.
|
|
80
|
+
|
|
81
|
+
**Server-refreshed**: `INSTRUCTIONS.md`, `prompts/`, `models/`, `docs/`, the built-in agent ids (`default`, `executor`, `deep-executor`, `__evo_agent__`, `__score__`, `__apply_agent__`), and the built-in skill ids (`agent`, `skill`, `workspace`, `cron`, `acp`, `send-file`, `self`, `aws-knowledge`, `nova-web-search`, `halo`). To customize one, copy it into the workspace scope (`<project>/.halo/...`) — workspace replaces global at runtime.
|
|
82
|
+
|
|
83
|
+
**Never overwritten**: anything else under `agents/` or `skills/` (your own creations), and everything under `secrets/`.
|
|
84
|
+
|
|
85
|
+
**`secrets/config.yaml`** is leaf-merged on each refresh — new keys introduced by a server upgrade are added, your existing `value`s (password, port, jwt_secret) are kept.
|
|
86
|
+
|
|
87
|
+
## Next
|
|
88
|
+
|
|
89
|
+
- [chat.md](chat.md) — everything the chat panel does
|
|
90
|
+
- [agents.md](agents.md) — managing agents
|
|
91
|
+
- [skills.md](skills.md) — what skills are and how to use them
|
|
92
|
+
- [sessions.md](sessions.md) — viewing session history, debugging
|
|
93
|
+
- [workspace.md](workspace.md) — the overall interface
|