@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.
Files changed (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/admin-out/404.html +1 -0
  4. package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_buildManifest.js +1 -0
  5. package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_ssgManifest.js +1 -0
  6. package/admin-out/_next/static/chunks/1d2d5650-810a3ca1ae20cab5.js +18 -0
  7. package/admin-out/_next/static/chunks/200.3b8f8a74f005a134.js +1 -0
  8. package/admin-out/_next/static/chunks/220.3dc41cd6269b88e6.js +1 -0
  9. package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +1 -0
  10. package/admin-out/_next/static/chunks/304eda7d.b1ee7f523653e027.js +1 -0
  11. package/admin-out/_next/static/chunks/330.3b784cf0dcd69163.js +1 -0
  12. package/admin-out/_next/static/chunks/442.f4302087bddb1ec1.js +1 -0
  13. package/admin-out/_next/static/chunks/443.d1b289781793f8de.js +25 -0
  14. package/admin-out/_next/static/chunks/503-7c6d9935df6e0cea.js +1 -0
  15. package/admin-out/_next/static/chunks/533.5f2d4bfe3d076095.js +1 -0
  16. package/admin-out/_next/static/chunks/579.a2718ddd395a2f3a.js +1 -0
  17. package/admin-out/_next/static/chunks/635-3dd0043ed0520b9d.js +1 -0
  18. package/admin-out/_next/static/chunks/65.859665ba6717967a.js +1 -0
  19. package/admin-out/_next/static/chunks/661.a4fe93f3f2a5e871.js +1 -0
  20. package/admin-out/_next/static/chunks/688.4e014ac6cfc7e152.js +1 -0
  21. package/admin-out/_next/static/chunks/868.0c95dfe283400a00.js +1 -0
  22. package/admin-out/_next/static/chunks/app/_not-found/page-8e35399c8fd5016d.js +1 -0
  23. package/admin-out/_next/static/chunks/app/layout-58f773336e6fce61.js +1 -0
  24. package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +1 -0
  25. package/admin-out/_next/static/chunks/db534642.09d3c650ff587175.js +1 -0
  26. package/admin-out/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js +1 -0
  27. package/admin-out/_next/static/chunks/framework-c3031ae54a63fe16.js +1 -0
  28. package/admin-out/_next/static/chunks/main-14b48e3c2588354f.js +1 -0
  29. package/admin-out/_next/static/chunks/main-app-483b436873410ddc.js +1 -0
  30. package/admin-out/_next/static/chunks/pages/_app-b2fc6e5f920d1b1a.js +1 -0
  31. package/admin-out/_next/static/chunks/pages/_error-f3696a8f3d67d150.js +1 -0
  32. package/admin-out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  33. package/admin-out/_next/static/chunks/webpack-8bd7ef88a6527feb.js +1 -0
  34. package/admin-out/_next/static/css/659eccb5db697b76.css +1 -0
  35. package/admin-out/_next/static/css/8fce4e1a54dac12a.css +3 -0
  36. package/admin-out/_next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
  37. package/admin-out/_next/static/media/21350d82a1f187e9-s.woff2 +0 -0
  38. package/admin-out/_next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
  39. package/admin-out/_next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
  40. package/admin-out/_next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
  41. package/admin-out/_next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
  42. package/admin-out/_next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
  43. package/admin-out/favicon.ico +0 -0
  44. package/admin-out/icon.svg +18 -0
  45. package/admin-out/index.html +1 -0
  46. package/admin-out/index.txt +23 -0
  47. package/admin-out/monaco/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
  48. package/admin-out/monaco/vs/abap-D-t0cyap.js +1 -0
  49. package/admin-out/monaco/vs/apex-CcIm7xu6.js +1 -0
  50. package/admin-out/monaco/vs/assets/css.worker-HnVq6Ewq.js +93 -0
  51. package/admin-out/monaco/vs/assets/editor.worker-Be8ye1pW.js +26 -0
  52. package/admin-out/monaco/vs/assets/html.worker-B51mlPHg.js +470 -0
  53. package/admin-out/monaco/vs/assets/json.worker-DKiEKt88.js +58 -0
  54. package/admin-out/monaco/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
  55. package/admin-out/monaco/vs/azcli-BA0tQDCg.js +1 -0
  56. package/admin-out/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  57. package/admin-out/monaco/vs/bat-C397hTD6.js +1 -0
  58. package/admin-out/monaco/vs/bicep-DF5aW17k.js +2 -0
  59. package/admin-out/monaco/vs/cameligo-plsz8qhj.js +1 -0
  60. package/admin-out/monaco/vs/clojure-Y2auQMzK.js +1 -0
  61. package/admin-out/monaco/vs/coffee-Bu45yuWE.js +1 -0
  62. package/admin-out/monaco/vs/cpp-CkKPQIni.js +1 -0
  63. package/admin-out/monaco/vs/csharp-CX28MZyh.js +1 -0
  64. package/admin-out/monaco/vs/csp-D8uWnyxW.js +1 -0
  65. package/admin-out/monaco/vs/css-CaeNmE3S.js +3 -0
  66. package/admin-out/monaco/vs/cssMode-CjiAH6dQ.js +1 -0
  67. package/admin-out/monaco/vs/cypher-DVThT8BS.js +1 -0
  68. package/admin-out/monaco/vs/dart-CmGfCvrO.js +1 -0
  69. package/admin-out/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  70. package/admin-out/monaco/vs/ecl-30fUercY.js +1 -0
  71. package/admin-out/monaco/vs/editor/editor.main.css +1 -0
  72. package/admin-out/monaco/vs/editor/editor.main.js +5 -0
  73. package/admin-out/monaco/vs/editor.api-CalNCsUg.js +903 -0
  74. package/admin-out/monaco/vs/elixir-xjPaIfzF.js +1 -0
  75. package/admin-out/monaco/vs/flow9-DqtmStfK.js +1 -0
  76. package/admin-out/monaco/vs/freemarker2-Cz_sV6Md.js +3 -0
  77. package/admin-out/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  78. package/admin-out/monaco/vs/go-D_hbi-Jt.js +1 -0
  79. package/admin-out/monaco/vs/graphql-CKUU4kLG.js +1 -0
  80. package/admin-out/monaco/vs/handlebars-OwglfO-1.js +1 -0
  81. package/admin-out/monaco/vs/hcl-DTaboeZW.js +1 -0
  82. package/admin-out/monaco/vs/html-Pa1xEWsY.js +1 -0
  83. package/admin-out/monaco/vs/htmlMode-Bz67EXwp.js +1 -0
  84. package/admin-out/monaco/vs/ini-CsNwO04R.js +1 -0
  85. package/admin-out/monaco/vs/java-CI4ZMsH9.js +1 -0
  86. package/admin-out/monaco/vs/javascript-PczUCGdz.js +1 -0
  87. package/admin-out/monaco/vs/jsonMode-DULH5oaX.js +7 -0
  88. package/admin-out/monaco/vs/julia-BwzEvaQw.js +1 -0
  89. package/admin-out/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  90. package/admin-out/monaco/vs/language/css/monaco.contribution.js +1 -0
  91. package/admin-out/monaco/vs/language/html/monaco.contribution.js +1 -0
  92. package/admin-out/monaco/vs/language/json/monaco.contribution.js +1 -0
  93. package/admin-out/monaco/vs/language/typescript/monaco.contribution.js +1 -0
  94. package/admin-out/monaco/vs/less-C0eDYdqa.js +2 -0
  95. package/admin-out/monaco/vs/lexon-iON-Kj97.js +1 -0
  96. package/admin-out/monaco/vs/liquid-DqKjdPGy.js +1 -0
  97. package/admin-out/monaco/vs/loader.js +1368 -0
  98. package/admin-out/monaco/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
  99. package/admin-out/monaco/vs/lua-DtygF91M.js +1 -0
  100. package/admin-out/monaco/vs/m3-CsR4AuFi.js +1 -0
  101. package/admin-out/monaco/vs/markdown-C_rD0bIw.js +1 -0
  102. package/admin-out/monaco/vs/mdx-DEWtB1K5.js +1 -0
  103. package/admin-out/monaco/vs/mips-CiYP61RB.js +1 -0
  104. package/admin-out/monaco/vs/monaco.contribution-D2OdxNBt.js +1 -0
  105. package/admin-out/monaco/vs/monaco.contribution-DO3azKX8.js +1 -0
  106. package/admin-out/monaco/vs/monaco.contribution-EcChJV6a.js +1 -0
  107. package/admin-out/monaco/vs/monaco.contribution-qLAYrEOP.js +1 -0
  108. package/admin-out/monaco/vs/msdax-C38-sJlp.js +1 -0
  109. package/admin-out/monaco/vs/mysql-CdtbpvbG.js +1 -0
  110. package/admin-out/monaco/vs/nls.messages-loader.js +1 -0
  111. package/admin-out/monaco/vs/nls.messages.cs.js.js +17 -0
  112. package/admin-out/monaco/vs/nls.messages.de.js.js +17 -0
  113. package/admin-out/monaco/vs/nls.messages.es.js.js +17 -0
  114. package/admin-out/monaco/vs/nls.messages.fr.js.js +15 -0
  115. package/admin-out/monaco/vs/nls.messages.it.js.js +15 -0
  116. package/admin-out/monaco/vs/nls.messages.ja.js.js +17 -0
  117. package/admin-out/monaco/vs/nls.messages.js.js +10 -0
  118. package/admin-out/monaco/vs/nls.messages.ko.js.js +25 -0
  119. package/admin-out/monaco/vs/nls.messages.pl.js.js +17 -0
  120. package/admin-out/monaco/vs/nls.messages.pt-br.js.js +6 -0
  121. package/admin-out/monaco/vs/nls.messages.ru.js.js +17 -0
  122. package/admin-out/monaco/vs/nls.messages.tr.js.js +15 -0
  123. package/admin-out/monaco/vs/nls.messages.zh-cn.js.js +17 -0
  124. package/admin-out/monaco/vs/nls.messages.zh-tw.js.js +15 -0
  125. package/admin-out/monaco/vs/objective-c-CntZFaHX.js +1 -0
  126. package/admin-out/monaco/vs/pascal-r6kuqfl_.js +1 -0
  127. package/admin-out/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  128. package/admin-out/monaco/vs/perl-DABw_TcH.js +1 -0
  129. package/admin-out/monaco/vs/pgsql-me_jFXeX.js +1 -0
  130. package/admin-out/monaco/vs/php-D_kh-9LK.js +1 -0
  131. package/admin-out/monaco/vs/pla-VfZjczW0.js +1 -0
  132. package/admin-out/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  133. package/admin-out/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  134. package/admin-out/monaco/vs/powershell-B-7ap1zc.js +1 -0
  135. package/admin-out/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  136. package/admin-out/monaco/vs/pug-BRpRNeEb.js +1 -0
  137. package/admin-out/monaco/vs/python-Cr0UkIbn.js +1 -0
  138. package/admin-out/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  139. package/admin-out/monaco/vs/r-f8dDdrp4.js +1 -0
  140. package/admin-out/monaco/vs/razor-BYAHOTkz.js +1 -0
  141. package/admin-out/monaco/vs/redis-fvZQY4PI.js +1 -0
  142. package/admin-out/monaco/vs/redshift-45Et0LQi.js +1 -0
  143. package/admin-out/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  144. package/admin-out/monaco/vs/ruby-CZO8zYTz.js +1 -0
  145. package/admin-out/monaco/vs/rust-Bfetafyc.js +1 -0
  146. package/admin-out/monaco/vs/sb-3GYllVck.js +1 -0
  147. package/admin-out/monaco/vs/scala-foMgrKo1.js +1 -0
  148. package/admin-out/monaco/vs/scheme-CHdMtr7p.js +1 -0
  149. package/admin-out/monaco/vs/scss-C1cmLt9V.js +3 -0
  150. package/admin-out/monaco/vs/shell-ClXCKCEW.js +1 -0
  151. package/admin-out/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  152. package/admin-out/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  153. package/admin-out/monaco/vs/sparql-AUGFYSyk.js +1 -0
  154. package/admin-out/monaco/vs/sql-32GpJSV2.js +1 -0
  155. package/admin-out/monaco/vs/st-CuDFIVZ_.js +1 -0
  156. package/admin-out/monaco/vs/swift-n-2HociN.js +3 -0
  157. package/admin-out/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  158. package/admin-out/monaco/vs/tcl-D74tq1nH.js +1 -0
  159. package/admin-out/monaco/vs/tsMode-CZz1Umrk.js +11 -0
  160. package/admin-out/monaco/vs/twig-C6taOxMV.js +1 -0
  161. package/admin-out/monaco/vs/typescript-DfOrAzoV.js +1 -0
  162. package/admin-out/monaco/vs/typespec-D-PIh9Xw.js +1 -0
  163. package/admin-out/monaco/vs/vb-Dyb2648j.js +1 -0
  164. package/admin-out/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  165. package/admin-out/monaco/vs/workers-DcJshg-q.js +1 -0
  166. package/admin-out/monaco/vs/xml-CdsdnY8S.js +1 -0
  167. package/admin-out/monaco/vs/yaml-DYGvmE88.js +1 -0
  168. package/bin/halo.js +9 -0
  169. package/bundled-docs/design/agent.md +145 -0
  170. package/bundled-docs/design/architecture.md +270 -0
  171. package/bundled-docs/design/background-dispatch.md +151 -0
  172. package/bundled-docs/design/command.md +58 -0
  173. package/bundled-docs/design/cron.md +88 -0
  174. package/bundled-docs/design/evolution.md +383 -0
  175. package/bundled-docs/design/express-self.md +145 -0
  176. package/bundled-docs/design/feishu.md +224 -0
  177. package/bundled-docs/design/halo-city.md +112 -0
  178. package/bundled-docs/design/prompt-system.md +411 -0
  179. package/bundled-docs/design/session.md +321 -0
  180. package/bundled-docs/design/slack.md +212 -0
  181. package/bundled-docs/design/storage.md +578 -0
  182. package/bundled-docs/design/telegram.md +161 -0
  183. package/bundled-docs/design/web.md +222 -0
  184. package/bundled-docs/design/wechat.md +146 -0
  185. package/bundled-docs/design/ws.md +144 -0
  186. package/bundled-docs/dev/acp-adapter.md +337 -0
  187. package/bundled-docs/dev/add-channel.md +376 -0
  188. package/bundled-docs/dev/add-model-provider.md +386 -0
  189. package/bundled-docs/dev/api.md +686 -0
  190. package/bundled-docs/dev/deploy.md +198 -0
  191. package/bundled-docs/dev/desktop-packaging.md +327 -0
  192. package/bundled-docs/dev/env.md +158 -0
  193. package/bundled-docs/dev/logging.md +85 -0
  194. package/bundled-docs/dev/previews.md +225 -0
  195. package/bundled-docs/dev/tools.md +331 -0
  196. package/bundled-docs/guide/README.md +29 -0
  197. package/bundled-docs/guide/agents.md +264 -0
  198. package/bundled-docs/guide/channels/README.md +62 -0
  199. package/bundled-docs/guide/channels/acp.md +150 -0
  200. package/bundled-docs/guide/channels/feishu.md +154 -0
  201. package/bundled-docs/guide/channels/slack.md +156 -0
  202. package/bundled-docs/guide/channels/telegram.md +112 -0
  203. package/bundled-docs/guide/channels/web.md +149 -0
  204. package/bundled-docs/guide/channels/wechat.md +110 -0
  205. package/bundled-docs/guide/chat.md +112 -0
  206. package/bundled-docs/guide/cli.md +197 -0
  207. package/bundled-docs/guide/getting-started.md +93 -0
  208. package/bundled-docs/guide/secrets-and-credentials.md +161 -0
  209. package/bundled-docs/guide/sessions.md +104 -0
  210. package/bundled-docs/guide/skills.md +302 -0
  211. package/bundled-docs/guide/testing-agents-and-skills.md +136 -0
  212. package/bundled-docs/guide/workspace.md +131 -0
  213. package/bundled-docs/plans/cron-tasks.md +362 -0
  214. package/bundled-docs/plans/design-suggestions.md +203 -0
  215. package/bundled-docs/plans/issue-session-deep-nesting.md +208 -0
  216. package/bundled-docs/plans/launch-plan.md +111 -0
  217. package/bundled-docs/plans/md-and-agent-refactor.md +197 -0
  218. package/bundled-docs/plans/remote-mac-worker.md +196 -0
  219. package/bundled-docs/plans/roadmap.md +40 -0
  220. package/bundled-docs/plans/self-evolution.md +1379 -0
  221. package/bundled-docs/plans/todo.md +32 -0
  222. package/bundled-docs/plans/weixin-channel.md +255 -0
  223. package/bundled-docs/requirements/agent.md +92 -0
  224. package/bundled-docs/requirements/chat.md +81 -0
  225. package/bundled-docs/requirements/command.md +130 -0
  226. package/bundled-docs/requirements/editor.md +82 -0
  227. package/bundled-docs/requirements/explorer.md +89 -0
  228. package/bundled-docs/requirements/overview.md +62 -0
  229. package/bundled-docs/requirements/session.md +73 -0
  230. package/bundled-docs/requirements/settings.md +224 -0
  231. package/bundled-docs/requirements/skill.md +125 -0
  232. package/bundled-docs/requirements/source-control.md +82 -0
  233. package/bundled-docs/requirements/terminal.md +118 -0
  234. package/bundled-docs/requirements/workspace.md +80 -0
  235. package/bundled-docs/test/docs-seeding.md +101 -0
  236. package/bundled-docs/test/session.md +374 -0
  237. package/dist/index.js +26750 -0
  238. package/package.json +67 -0
  239. package/templates/INSTRUCTIONS.md +25 -0
  240. package/templates/agents/__apply_agent__/AGENT.md +229 -0
  241. package/templates/agents/__apply_agent__/agent.yaml +30 -0
  242. package/templates/agents/__evo_agent__/AGENT.md +323 -0
  243. package/templates/agents/__evo_agent__/agent.yaml +29 -0
  244. package/templates/agents/__score__/AGENT.md +177 -0
  245. package/templates/agents/__score__/agent.yaml +29 -0
  246. package/templates/agents/deep-executor/AGENT.md +60 -0
  247. package/templates/agents/deep-executor/agent.yaml +25 -0
  248. package/templates/agents/default/AGENT.md +38 -0
  249. package/templates/agents/default/agent.yaml +51 -0
  250. package/templates/agents/executor/AGENT.md +38 -0
  251. package/templates/agents/executor/agent.yaml +25 -0
  252. package/templates/aliases.yaml +26 -0
  253. package/templates/canvas/self.html +660 -0
  254. package/templates/config.yaml +69 -0
  255. package/templates/models/anthropic.yaml +47 -0
  256. package/templates/models/aws-bedrock-claude-invoke.yaml +156 -0
  257. package/templates/models/aws-bedrock-mantle.yaml +89 -0
  258. package/templates/models/deepseek.yaml +62 -0
  259. package/templates/models/doubao.yaml +137 -0
  260. package/templates/models/hunyuan.yaml +56 -0
  261. package/templates/models/kimi.yaml +41 -0
  262. package/templates/models/mimo-token-plan-china.yaml +61 -0
  263. package/templates/models/minimax.yaml +80 -0
  264. package/templates/models/openai.yaml +51 -0
  265. package/templates/models/qwen.yaml +78 -0
  266. package/templates/optional-skills/tavily-web-search/SKILL.md +91 -0
  267. package/templates/optional-skills/tavily-web-search/config.yaml +10 -0
  268. package/templates/prompts/all/TOOL_GUIDELINES.md +35 -0
  269. package/templates/prompts/all/TOOL_SHELL.md +4 -0
  270. package/templates/prompts/all/TOOL_SHELL.windows.md +7 -0
  271. package/templates/prompts/bootstrap/BOOTSTRAP.md +26 -0
  272. package/templates/prompts/root/WORKSPACE_MEMORY.md +11 -0
  273. package/templates/schema.sql +30 -0
  274. package/templates/skills/acp/SKILL.md +236 -0
  275. package/templates/skills/acp/templates/SKILL.md.tmpl +74 -0
  276. package/templates/skills/acp/templates/ask.py +176 -0
  277. package/templates/skills/acp/templates/config.yaml.tmpl +33 -0
  278. package/templates/skills/agent/SKILL.md +128 -0
  279. package/templates/skills/aws-knowledge/SKILL.md +82 -0
  280. package/templates/skills/aws-knowledge/scripts/aws_kb.py +61 -0
  281. package/templates/skills/cron/SKILL.md +217 -0
  282. package/templates/skills/cron/manage-cron.py +434 -0
  283. package/templates/skills/halo/SKILL.md +98 -0
  284. package/templates/skills/nova-web-search/SKILL.md +65 -0
  285. package/templates/skills/self/SKILL.md +139 -0
  286. package/templates/skills/send-file/SKILL.md +28 -0
  287. package/templates/skills/send-file/feishu.md +16 -0
  288. package/templates/skills/send-file/slack.md +7 -0
  289. package/templates/skills/send-file/telegram.md +9 -0
  290. package/templates/skills/send-file/web.md +6 -0
  291. package/templates/skills/send-file/wechat.md +8 -0
  292. package/templates/skills/skill/SKILL.md +131 -0
  293. package/templates/skills/workspace/SKILL.md +28 -0
  294. package/templates/skills/workspace/setup-tidy.md +265 -0
  295. package/templates/skills/workspace/share.md +187 -0
  296. package/templates/skills/workspace/stage.py +487 -0
@@ -0,0 +1,158 @@
1
+ # Development Environment
2
+
3
+ ## Ports
4
+
5
+ - **8080** is code-server — don't touch, don't occupy, don't kill
6
+ - **9527** is Hono (Halo server); one process serves API + WebSocket + static frontend
7
+
8
+ ## Browser testing
9
+
10
+ - URL: `http://localhost:9527/?folder=<url-encoded absolute workspace path>`
11
+ - Password: set via `halo setup` (stored as scrypt hash in `~/.halo/secrets/config.yaml server.password`) **or** `HALO_PASSWORD` env (plaintext — preferred for Docker / CI). Env wins over hash if both are set.
12
+ - Workspace path: any absolute directory you want to bind
13
+
14
+ ## Deploy commands
15
+
16
+ ### Frontend build (web only)
17
+
18
+ ```bash
19
+ cd packages/admin && npx next build --no-lint && node scripts/copy-monaco.mjs
20
+ ```
21
+
22
+ ### Backend redeploy (server only)
23
+
24
+ ```bash
25
+ cd packages/server && npx tsc
26
+ kill -9 $(ss -tlnp | grep ':9527' | grep -oP 'pid=\K\d+') 2>/dev/null
27
+ sleep 1
28
+ nohup node dist/index.js >> /dev/null 2>&1 & # HALO_PASSWORD read from env/config
29
+ ```
30
+
31
+ ### Full deploy in one go
32
+
33
+ ```bash
34
+ cd packages/admin && npx next build --no-lint && node scripts/copy-monaco.mjs
35
+ cd ../server && npx tsc
36
+ kill -9 $(ss -tlnp | grep ':9527' | grep -oP 'pid=\K\d+') 2>/dev/null
37
+ sleep 1
38
+ nohup node dist/index.js >> /dev/null 2>&1 & # HALO_PASSWORD read from env/config
39
+ ```
40
+
41
+ ## Prerequisites
42
+
43
+ - Node.js ≥ 22 (better-sqlite3 native binding is bound to v22)
44
+ - pnpm ≥ 9
45
+ - AWS credentials configured (`~/.aws/credentials` or env vars) with Bedrock access
46
+ - bubblewrap (`sudo apt install bubblewrap`) — OS-level sandbox for non-full access levels. Without it, only app-level path validation is active and `shell_exec` is blocked for non-full sessions
47
+
48
+ ### nvm PATH
49
+
50
+ If the shell doesn't auto-load nvm:
51
+
52
+ ```bash
53
+ export PATH=$HOME/.nvm/versions/node/v22.21.1/bin:$PATH
54
+ ```
55
+
56
+ Your deployment scripts should also prepend this line.
57
+
58
+ ## Runtime directories
59
+
60
+ - SQLite: `data/halo.db` (auto-created on first start)
61
+ - Session files: `.halo/sessions/{agentId}/{sessionId}.json`
62
+ - Global config: `~/.halo/global/`
63
+ - Per-project config: `<workspace>/.halo/`
64
+
65
+ ## Configuration sources
66
+
67
+ Three config file types, precedence **env vars > config.yaml / settings.yaml > code defaults**:
68
+
69
+ | File | Scope | Contents |
70
+ |---|---|---|
71
+ | `~/.halo/secrets/config.yaml` | System | Port, password, CORS, timeouts, limits, logging — "infrastructure" settings |
72
+ | `~/.halo/secrets/settings.yaml` | User | Model, region, session behaviour — "preferences" |
73
+ | `<project>/.halo/settings.yaml` | Project | Overrides of global settings |
74
+
75
+ `init.ts` seeds these on first run with a per-category policy. Refresh trigger: `halo setup` always re-runs the seed, and the server's startup check re-runs it automatically when `~/.halo/global/.template-version` is behind the bundled `TEMPLATE_VERSION` (see `init.ts:TEMPLATE_VERSION` + `index.ts` startup block).
76
+
77
+ - **Always overwritten** (platform-owned, refreshed when the template version moves): `~/.halo/global/{prompts,models,docs}/`, `INSTRUCTIONS.md`, the built-in agent ids (`default`, `executor`, `deep-executor`, `__evo_agent__`, `__score__`, `__apply_agent__`), built-in skill ids (`agent`, `skill`, `workspace`, `cron`, `acp`, `send-file`, `self`, `aws-knowledge`, `nova-web-search`, `halo`).
78
+ - **Built-in agents** keep the user's `model:` block on overwrite — the admin UI lets users change which model an agent uses, and that choice survives upgrades.
79
+ - **Optional skills** (`tavily-web-search`) install only when picked via `halo setup`; the opt-in list is `~/.halo/global/.installed-optional-skills`. Picked skills are force-overwritten alongside the always-overwritten set.
80
+ - **`secrets/config.yaml`** is leaf-merged: existing leaf `value`s preserved, new leaves added when a server upgrade introduces them.
81
+ - **`secrets/settings.yaml`** is created empty if missing and never touched again. Defaults live in `settings-schema.ts`.
82
+
83
+ ## Environment variable overrides
84
+
85
+ Source: `packages/server/src/config.ts`
86
+
87
+ | Variable | Default | Config path | Description |
88
+ |---|---|---|---|
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. |
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
+ | `HALO_FRONTEND_DIR` | `packages/admin/out` | — | Static frontend dir (resolved as absolute path from project root) |
93
+ | `HALO_MAX_CONTEXT_TOKENS` | `200000` | — | Model max context |
94
+ | `HALO_SHELL_TIMEOUT` | `120000` | `config.yaml timeout.shell_exec` | Shell command timeout (ms) |
95
+ | `HALO_WEB_FETCH_TIMEOUT` | `10000` | `config.yaml timeout.web_fetch` | web_fetch timeout |
96
+ | `HALO_MODEL_TIMEOUT` | `1800000` | `config.yaml timeout.model_request` | Per model-call wall-clock cap (ms, 30 min). A bare fetch has no default timeout, so a half-open connection would hang the request forever; on expiry the call aborts and the agent loop retries with backoff. |
97
+ | `HALO_SESSION_GRACE` | `300000` | `config.yaml timeout.session_grace` | WS-disconnect session grace |
98
+ | `HALO_TERMINAL_GRACE` | `300000` | `config.yaml timeout.terminal_grace` | Terminal disconnect grace |
99
+ | `HALO_MAX_CACHED_SESSIONS` | `50` | — | In-memory session cache |
100
+ | `HALO_LOG_MAX_SIZE` | `10485760` | `config.yaml logging.max_file_size` | Log file size cap (10 MB) |
101
+ | `HALO_LOG_MAX_FILES` | `5` | `config.yaml logging.max_files` | Retained rotated logs |
102
+
103
+ settings.yaml only (no env override):
104
+ - `general.session.max_queue_size` (default 256)
105
+ - `general.session.max_nesting_depth` (default 16)
106
+ - `general.agent.max_retries` (default 5)
107
+ - `general.compact.keep_messages` (default 5) — recent messages to keep uncompacted
108
+ - `general.compact.max_summary_input` (default 15000) — local compaction fallback input cap
109
+ - `general.compact.max_message_slice` (default 800) — local compaction per-message cap
110
+ - `general.compact.summarize_timeout_sec` (default 300) — self-compact timeout
111
+ - `general.sandbox.hidden_dirs` (default `~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker`) — bwrap tmpfs overlays, scope: global
112
+ - `general.sandbox.hidden_files` (default `~/.npmrc,~/.bash_history,~/.gitconfig`) — bwrap /dev/null binds, scope: global
113
+ - `general.logging.level` (default `warn`) — log level: debug | info | warn | error
114
+
115
+ `<provider-id>.secrets.*` (server-only, hard-rejected by `{{}}` substitution; declared in `models/<provider-id>.yaml` `secrets:`):
116
+ - `aws-bedrock-claude-invoke.secrets.access_key_id` / `.secret_access_key` — AWS / Bedrock credentials
117
+ - `kimi.secrets.api_key` — Kimi (Moonshot AI)
118
+ - `deepseek.secrets.api_key` — DeepSeek
119
+
120
+ `<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
+ - `tavily-search.params.api_key` — example only; declared by whichever skill needs it
122
+
123
+ Hardcoded (config.ts, no override):
124
+ - `auth.tokenMaxAge` — 14 days
125
+ - `auth.refreshAfter` — 24 hours
126
+ - `model.compressAt` — default 0.8 (auto-compact threshold; configurable via `general.compact.compress_at` in settings.yaml)
127
+
128
+ settings.yaml-driven `general.limits.*` (no env override):
129
+ - `general.limits.shell_output_bytes` (default 5 MiB)
130
+ - `general.limits.web_fetch_bytes` (default 50 KiB)
131
+ - `general.limits.grep_default_matches` (default 50)
132
+ - `general.limits.tool_result_render_chars` (default 8000)
133
+ - `general.limits.ws_event_buffer` (default 5000)
134
+ - `general.limits.terminal_scrollback_bytes` (default 50000)
135
+
136
+ Two ways to authenticate:
137
+
138
+ 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.
140
+
141
+ ## Verify
142
+
143
+ ```bash
144
+ curl http://localhost:9527/api/health
145
+ # expect: {"status":"ok", ...}
146
+
147
+ curl -s -o /dev/null -w "%{http_code}" http://localhost:9527
148
+ # expect: 200
149
+ ```
150
+
151
+ ## Coding conventions
152
+
153
+ - TypeScript strict, ESM only
154
+ - camelCase variables/functions, PascalCase types, kebab-case filenames
155
+ - React functional components; styling via Tailwind only; UI prefers shadcn/ui
156
+ - Log format `[Module] message`
157
+ - Bedrock model ID: `global.anthropic.claude-sonnet-4-6`, default region `us-east-1` (configured per agent via `agent.yaml model.endpoint`)
158
+ - File operations are sandboxed by bwrap (OS-level) + `assertPathAllowed` (app-level fallback) for non-full sessions
@@ -0,0 +1,85 @@
1
+ # Logging
2
+
3
+ File-backed logs: intercepts console, auto-rotates.
4
+
5
+ File: `packages/server/src/logger.ts`
6
+
7
+ ## Architecture
8
+
9
+ On startup the logger intercepts `console.log` / `console.error` / `console.warn` / `console.debug`. Every call writes twice:
10
+ 1. The original console (stdout/stderr) — live monitoring
11
+ 2. A disk log file — persistent history
12
+
13
+ ## Log locations
14
+
15
+ | Scenario | Directory | File |
16
+ |---|---|---|
17
+ | Default (no workspace) | `~/.halo/logs/` | `server.log` |
18
+ | Workspace open | `<project>/.halo/logs/` | `server.log` |
19
+
20
+ When the WS handler receives a `subscribe` or `chat` with `projectId`, it calls `setLogDir()` to switch to the project's log directory.
21
+
22
+ ## Log format
23
+
24
+ ```
25
+ 2026-04-19T10:30:00.000Z INFO [Server] Hono server listening on http://localhost:9527
26
+ 2026-04-19T10:30:01.234Z ERROR [WS] Chat error: ThrottlingException
27
+ 2026-04-19T10:30:02.567Z WARN [Orchestrator] Context overflow, auto-compacting...
28
+ ```
29
+
30
+ Every line: `ISO timestamp` + `level (DEBUG/INFO/WARN/ERROR)` + `message`.
31
+
32
+ ## Rotation
33
+
34
+ When the log file exceeds the cap:
35
+ 1. Delete `server.log.{maxFiles}` (oldest)
36
+ 2. Shift `server.log.N` → `server.log.N+1`
37
+ 3. Rename `server.log` → `server.log.1`
38
+ 4. New `server.log` starts fresh
39
+
40
+ ### Config
41
+
42
+ | Config key | Default | Env var | Purpose |
43
+ |---|---|---|---|
44
+ | `logging.maxFileSize` | 10 MB | `HALO_LOG_MAX_SIZE` | Rotation threshold |
45
+ | `logging.maxFiles` | 5 | `HALO_LOG_MAX_FILES` | Retained rotated files |
46
+
47
+ Defined in `packages/server/src/config.ts`.
48
+
49
+ ## Initialization
50
+
51
+ ```typescript
52
+ import { initLogger } from './logger.js'
53
+ initLogger()
54
+ ```
55
+
56
+ Called once from `packages/server/src/index.ts` at startup. Steps:
57
+ 1. Create the log directory
58
+ 2. Replace console methods with the interceptor
59
+ 3. Each interceptor calls the original method and appends to the log file
60
+
61
+ ## Workspace switching
62
+
63
+ ```typescript
64
+ import { setLogDir } from './logger.js'
65
+ setLogDir('/path/to/project')
66
+ ```
67
+
68
+ Called from `packages/server/src/ws/handler.ts` when the client subscribes to a workspace.
69
+
70
+ ## Error handling
71
+
72
+ Log writes use synchronous `fs.appendFileSync` and fail silently — logging must not crash the server.
73
+
74
+ ## Viewing logs
75
+
76
+ ```bash
77
+ # live stdout (if started with nohup > /tmp/server.log)
78
+ tail -f /tmp/server.log
79
+
80
+ # file logs (always written, regardless of nohup redirection)
81
+ tail -f ~/.halo/logs/server.log
82
+
83
+ # project-specific logs
84
+ tail -f /path/to/your-project/.halo/logs/server.log
85
+ ```
@@ -0,0 +1,225 @@
1
+ # Preview Plugin System
2
+
3
+ Canvas renders non-text files via a **plugin registry**. Each plugin declares the extensions it handles and a React component. Adding a new file type = write one plugin, register it. No changes to the core framework or Canvas panel.
4
+
5
+ Location: [`packages/admin/src/features/editor/previews/`](../../../packages/admin/src/features/editor/previews/)
6
+
7
+ ## Layout
8
+
9
+ ```
10
+ previews/
11
+ ├── FilePreview.tsx Public entry. Looks up plugin by extension,
12
+ │ renders <Suspense><Component/></Suspense>.
13
+ ├── types.ts PreviewPlugin, PreviewProps
14
+ ├── registry.ts register() / getPlugin() / registeredExtensions() / isHeavyPreview()
15
+ ├── ui/
16
+ │ ├── preview-shell.tsx Standard header (filename + Open-as-Text + Download + extraToolbar)
17
+ │ ├── use-preview-fetch.ts Hook: fetch + AbortController + parse, returns {data, error, loading}
18
+ │ └── print.ts Pop-up print helper
19
+ ├── workers/ Parse workers (one per heavy format)
20
+ │ ├── worker-client.ts Generic WorkerClient<T> class — id-routed postMessage
21
+ │ ├── xlsx.worker.ts
22
+ │ └── docx.worker.ts
23
+ └── plugins/
24
+ ├── index.ts Registers all built-in plugins
25
+ ├── pdf.tsx Metadata (id, extensions, lazy Component)
26
+ ├── pdf-view.tsx Actual React component
27
+ ├── docx.tsx / docx-view.tsx
28
+ ├── xlsx.tsx / xlsx-view.tsx
29
+ ├── pptx.tsx / pptx-view.tsx
30
+ └── media.tsx / media-view.tsx
31
+ ```
32
+
33
+ **Two-file-per-plugin pattern**: `foo.tsx` is tiny metadata (no runtime deps). `foo-view.tsx` holds the component and its heavy dependencies. The metadata file uses `React.lazy()` so the view file (and its deps) only loads when a user actually opens that file type.
34
+
35
+ ## PreviewPlugin interface
36
+
37
+ ```typescript
38
+ interface PreviewPlugin {
39
+ id: string // stable id, e.g. 'pdf'
40
+ extensions: readonly string[] // lowercase, no dot — e.g. ['xlsx', 'xls', 'csv']
41
+ Component: React.ComponentType<PreviewProps>
42
+ heavy?: boolean // true = main-thread-heavy; active-only mount, skip MRU cache
43
+ }
44
+
45
+ interface PreviewProps {
46
+ name: string // full filename including extension
47
+ path: string // relative workspace path (or absolute for /tmp files)
48
+ viewUrl: string // for inline viewing, supports HTTP Range
49
+ downloadUrl: string // for forced download (used by the shell's Download button)
50
+ onOpenAsText?: () => void // set when the file can also be force-opened as text
51
+ }
52
+ ```
53
+
54
+ ## Adding a new file type
55
+
56
+ ### 1. Create the view component
57
+
58
+ ```tsx
59
+ // plugins/foo-view.tsx
60
+ 'use client'
61
+
62
+ import type { PreviewProps } from '../types'
63
+ import { PreviewShell } from '../ui/preview-shell'
64
+ import { usePreviewFetch } from '../ui/use-preview-fetch'
65
+
66
+ export function FooPreview(props: PreviewProps) {
67
+ const { name, viewUrl, downloadUrl, onOpenAsText } = props
68
+ const { data, error, loading } = usePreviewFetch(viewUrl, async (buf) => {
69
+ // Parse `buf` here. For heavy parsing, call into a Worker (see Workers below).
70
+ return parseFoo(buf)
71
+ })
72
+ return (
73
+ <PreviewShell
74
+ name={name}
75
+ downloadUrl={downloadUrl}
76
+ onOpenAsText={onOpenAsText}
77
+ loading={loading}
78
+ error={error}
79
+ >
80
+ {data && <div className="h-full overflow-auto">{/* render your data */}</div>}
81
+ </PreviewShell>
82
+ )
83
+ }
84
+ ```
85
+
86
+ ### 2. Declare the plugin
87
+
88
+ ```tsx
89
+ // plugins/foo.tsx
90
+ 'use client'
91
+
92
+ import { lazy } from 'react'
93
+ import type { PreviewPlugin } from '../types'
94
+
95
+ export const fooPlugin: PreviewPlugin = {
96
+ id: 'foo',
97
+ extensions: ['foo', 'foobar'],
98
+ Component: lazy(() => import('./foo-view').then((m) => ({ default: m.FooPreview }))),
99
+ }
100
+ ```
101
+
102
+ ### 3. Register it
103
+
104
+ ```ts
105
+ // plugins/index.ts
106
+ import { fooPlugin } from './foo'
107
+ register(fooPlugin)
108
+ ```
109
+
110
+ Done. The Canvas panel will:
111
+ - Treat `.foo` / `.foobar` as non-text (routes to preview instead of Monaco)
112
+ - Mount `FooPreview` inside an MRU cache (up to 5 concurrent plugins cached)
113
+
114
+ ## PreviewShell — the standard header
115
+
116
+ Every plugin should wrap its content in `<PreviewShell>` for consistency. The shell gives you:
117
+ - Filename on the left
118
+ - Your plugin-specific buttons via `extraToolbar` (right-aligned, before the standard buttons)
119
+ - Standard Open-as-Text + Download buttons
120
+ - Loading overlay (pass `loading={true}`)
121
+ - Error state (pass `error={'…'}` — the children are hidden)
122
+
123
+ ```tsx
124
+ <PreviewShell
125
+ name={name}
126
+ downloadUrl={downloadUrl}
127
+ onOpenAsText={onOpenAsText}
128
+ extraToolbar={myButtons} // optional
129
+ loading={loading}
130
+ error={error}
131
+ >
132
+ {content}
133
+ </PreviewShell>
134
+ ```
135
+
136
+ Plugin-specific buttons use the shared `<ToolbarButton>`:
137
+
138
+ ```tsx
139
+ <ToolbarButton onClick={...} title="Print">
140
+ <Printer className="h-3 w-3" />
141
+ <span>Print</span>
142
+ </ToolbarButton>
143
+ ```
144
+
145
+ ## Workers — parsing off the main thread
146
+
147
+ If your format needs CPU-heavy parsing (non-trivial ArrayBuffer → structured data), run it in a Web Worker so the UI stays responsive even with several tabs parsing concurrently.
148
+
149
+ ### 1. Write the worker
150
+
151
+ ```ts
152
+ // workers/foo.worker.ts
153
+ /// <reference lib="webworker" />
154
+
155
+ type Req = { id: number; buf: ArrayBuffer; meta?: unknown }
156
+ type Res = { id: number; ok: true; data: FooResult } | { id: number; ok: false; error: string }
157
+
158
+ self.addEventListener('message', (e: MessageEvent<Req>) => {
159
+ const { id, buf } = e.data
160
+ try {
161
+ const data = parseFoo(buf)
162
+ ;(self as any).postMessage({ id, ok: true, data } satisfies Res)
163
+ } catch (err) {
164
+ ;(self as any).postMessage({ id, ok: false, error: String(err) } satisfies Res)
165
+ }
166
+ })
167
+ ```
168
+
169
+ ### 2. Wire it in the view
170
+
171
+ ```tsx
172
+ import { WorkerClient } from '../workers/worker-client'
173
+
174
+ let client: WorkerClient | null = null
175
+ function getClient() {
176
+ if (!client) {
177
+ client = new WorkerClient(
178
+ () => new Worker(new URL('../workers/foo.worker.ts', import.meta.url), { type: 'module' }),
179
+ )
180
+ }
181
+ return client
182
+ }
183
+
184
+ // Inside your component:
185
+ const { data } = usePreviewFetch(viewUrl, (buf, signal) =>
186
+ getClient().call<FooResult>(signal, buf),
187
+ )
188
+ ```
189
+
190
+ `WorkerClient.call(signal, buf, meta?)` handles id routing, transfer of the ArrayBuffer, and abort (when the caller's signal fires, the reply is dropped).
191
+
192
+ ## `heavy: true` — when to use it
193
+
194
+ Set `heavy: true` when the preview:
195
+ - Needs DOM access (can't run in a Worker — e.g. `pptx-preview` draws to canvas)
196
+ - Is the dominant memory cost of the page (large canvas, many cached elements)
197
+
198
+ Effect: the MRU cache skips this plugin. Only the **active** instance mounts; switching away unmounts the component (releases memory and stops any in-flight work). Switching back re-fetches/re-renders.
199
+
200
+ Only pptx currently uses this. Don't set it by default — the MRU cache gives much faster switches.
201
+
202
+ ## `onOpenAsText`
203
+
204
+ When the user right-clicks a previewable file in Explorer and picks "Open as Text", Canvas closes the preview tab and opens the raw file in Monaco. The preview plugin receives this as `props.onOpenAsText` — pass it straight through to `PreviewShell` and the button appears automatically.
205
+
206
+ ## Server side
207
+
208
+ All previews fetch via `GET /api/files/download?inline=1` which:
209
+ - Streams the file (doesn't read entire buffer into memory)
210
+ - Supports HTTP `Range` (206 Partial Content) for video/audio seek + progressive load
211
+ - Aborts the read when the client disconnects (tab closed / URL changed)
212
+
213
+ See [`dev/api.md`](api.md) for the route details.
214
+
215
+ ## Testing a new plugin
216
+
217
+ 1. Drop a test file into your workspace
218
+ 2. Click it in the Explorer — Canvas should open it in preview mode automatically
219
+ 3. Verify:
220
+ - Loading overlay appears briefly
221
+ - Download button works (forces attachment download)
222
+ - Open-as-Text button works (closes preview, opens in Monaco)
223
+ - Closing the preview tab cleanly aborts any in-flight fetch/parse
224
+ - Opening a second file of the same type reuses the worker (no second worker instance — check DevTools → Application → Service Workers / the process graph)
225
+ - Switching between up to 5 preview tabs is instant (MRU cache); the 6th oldest unmounts