@turmind/halo 2.1.0 → 2.1.2

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 (155) hide show
  1. package/admin-out/404.html +1 -1
  2. package/admin-out/_next/static/{a5z_n1eIm6T8T3Ty_MMHF → 1yjkA6O2OJ9CQ1XyyoazM}/_buildManifest.js +1 -1
  3. package/admin-out/_next/static/chunks/0.700b96fc96b80936.js +1 -0
  4. package/admin-out/_next/static/chunks/1160.e199e2decb964814.js +1 -0
  5. package/admin-out/_next/static/chunks/1208.0d86b06cbdf8a97e.js +38 -0
  6. package/admin-out/_next/static/chunks/1299.9ae1e73c8ca9cc34.js +23 -0
  7. package/admin-out/_next/static/chunks/1336.3eb7654fcfae2a58.js +1 -0
  8. package/admin-out/_next/static/chunks/1494.56493f36b01d2bda.js +1 -0
  9. package/admin-out/_next/static/chunks/1522.7d80e505c25fc865.js +1 -0
  10. package/admin-out/_next/static/chunks/1650.78e7ab21cb8bbb48.js +62 -0
  11. package/admin-out/_next/static/chunks/1690.20f8661b1877aa3d.js +1 -0
  12. package/admin-out/_next/static/chunks/1807.764b0338b13846a5.js +1 -0
  13. package/admin-out/_next/static/chunks/1989-669da2a252898797.js +1 -0
  14. package/admin-out/_next/static/chunks/199.fca450ee70f089fb.js +1 -0
  15. package/admin-out/_next/static/chunks/1b86ba38-4193816aebc732b9.js +1 -0
  16. package/admin-out/_next/static/chunks/{1d2d5650-d8d130c85727fdbb.js → 1d2d5650-c677408087984c7a.js} +1 -1
  17. package/admin-out/_next/static/chunks/2202.59a95bacad0d8c25.js +1 -0
  18. package/admin-out/_next/static/chunks/2204.93c869dacb19e384.js +1 -0
  19. package/admin-out/_next/static/chunks/2329.2f32de914b104261.js +148 -0
  20. package/admin-out/_next/static/chunks/2449.53d632fa8e412643.js +1 -0
  21. package/admin-out/_next/static/chunks/2477.79f2f92780311a37.js +94 -0
  22. package/admin-out/_next/static/chunks/2555.279979b7abe9d67f.js +104 -0
  23. package/admin-out/_next/static/chunks/2612.427656205dd7d7cc.js +1 -0
  24. package/admin-out/_next/static/chunks/2938.1555d68665415ace.js +1 -0
  25. package/admin-out/_next/static/chunks/295.0ef9b18be46f06e5.js +1 -0
  26. package/admin-out/_next/static/chunks/2979.d5a2293e776ec5de.js +1 -0
  27. package/admin-out/_next/static/chunks/3023.8f2b6311aae80029.js +36 -0
  28. package/admin-out/_next/static/chunks/3047.a49ae982be1f9fd4.js +226 -0
  29. package/admin-out/_next/static/chunks/304eda7d.2c6ab1276b03c10a.js +1 -0
  30. package/admin-out/_next/static/chunks/3483.cb8f5ba28c565e7f.js +1 -0
  31. package/admin-out/_next/static/chunks/391.71124432b84c926d.js +24 -0
  32. package/admin-out/_next/static/chunks/3986.a6181916d2c44515.js +1 -0
  33. package/admin-out/_next/static/chunks/4120.c271dfe3e1bc082e.js +1 -0
  34. package/admin-out/_next/static/chunks/4267.030877aaeac1bd71.js +1 -0
  35. package/admin-out/_next/static/chunks/4362.9d2ee4f9b6facc49.js +1 -0
  36. package/admin-out/_next/static/chunks/43ad6dab.4911ea318c123311.js +62 -0
  37. package/admin-out/_next/static/chunks/4480-6ceca99203a95c0e.js +1 -0
  38. package/admin-out/_next/static/chunks/4613.0985db499409cf22.js +1 -0
  39. package/admin-out/_next/static/chunks/4794.ba746110cfcbf536.js +1 -0
  40. package/admin-out/_next/static/chunks/4808.1cbe5b52fa01fc3d.js +1 -0
  41. package/admin-out/_next/static/chunks/4ec056c8.fe288ac8bd38a73b.js +160 -0
  42. package/admin-out/_next/static/chunks/5056.a87b1e056ba592b1.js +32 -0
  43. package/admin-out/_next/static/chunks/5058.8514aa6d6a947cce.js +1 -0
  44. package/admin-out/_next/static/chunks/545.e760052f10d36a9b.js +1 -0
  45. package/admin-out/_next/static/chunks/{510.e6c6faeb60ef3c33.js → 5510.f3889206b5768b33.js} +1 -1
  46. package/admin-out/_next/static/chunks/5593.d4c5f6a0862b4c6c.js +34 -0
  47. package/admin-out/_next/static/chunks/5700.4189184227fcf178.js +1 -0
  48. package/admin-out/_next/static/chunks/5741.dd7360163a2374cf.js +8 -0
  49. package/admin-out/_next/static/chunks/5850.b58c01f1e835d335.js +1 -0
  50. package/admin-out/_next/static/chunks/6066.1571d105977d528c.js +86 -0
  51. package/admin-out/_next/static/chunks/61527465.ae14a459dbfc381c.js +1 -0
  52. package/admin-out/_next/static/chunks/6203.672c38fcc2748c83.js +1 -0
  53. package/admin-out/_next/static/chunks/6390.4de9361c493b8d29.js +27 -0
  54. package/admin-out/_next/static/chunks/63c91ae9.ed896f9d6d01dfd4.js +1 -0
  55. package/admin-out/_next/static/chunks/6476.c7ec7d60350855c8.js +1 -0
  56. package/admin-out/_next/static/chunks/6574.30661d21e54bb004.js +1 -0
  57. package/admin-out/_next/static/chunks/6694.91c424de10ee2a24.js +79 -0
  58. package/admin-out/_next/static/chunks/6927.7f60d259473bb56a.js +193 -0
  59. package/admin-out/_next/static/chunks/7073.9d5f9dd7a77827b7.js +1 -0
  60. package/admin-out/_next/static/chunks/7250.a005173b9af23f14.js +1 -0
  61. package/admin-out/_next/static/chunks/7267.09e9b83beadc4847.js +1 -0
  62. package/admin-out/_next/static/chunks/72d2e465.c6751b76f1fa1cb3.js +1 -0
  63. package/admin-out/_next/static/chunks/7423.ce958b2d6a455a2f.js +1 -0
  64. package/admin-out/_next/static/chunks/7443.ee6684ba397e49da.js +41 -0
  65. package/admin-out/_next/static/chunks/7482.7f6f11637c008b77.js +1 -0
  66. package/admin-out/_next/static/chunks/7498.621ff3bc139607ad.js +1 -0
  67. package/admin-out/_next/static/chunks/7573.7f7f2a6fe7891e68.js +1 -0
  68. package/admin-out/_next/static/chunks/7613.fe24922a6a839656.js +1 -0
  69. package/admin-out/_next/static/chunks/7796.052a2a69f9bc0471.js +287 -0
  70. package/admin-out/_next/static/chunks/8148.156aea8f2a9ce398.js +115 -0
  71. package/admin-out/_next/static/chunks/8300.6c86a2236d42618f.js +64 -0
  72. package/admin-out/_next/static/chunks/8555.2e8d51736bfefd63.js +1 -0
  73. package/admin-out/_next/static/chunks/8558.baa0cf80a6964d20.js +286 -0
  74. package/admin-out/_next/static/chunks/8608.dba2a172fa47a740.js +77 -0
  75. package/admin-out/_next/static/chunks/8680.ed502a4a22357230.js +92 -0
  76. package/admin-out/_next/static/chunks/8698.28ca7821a30dba63.js +1 -0
  77. package/admin-out/_next/static/chunks/8712.e587efd8a6256aa9.js +1 -0
  78. package/admin-out/_next/static/chunks/8771.53592f31c08edafa.js +309 -0
  79. package/admin-out/_next/static/chunks/8878.330238d3d9f33faf.js +1 -0
  80. package/admin-out/_next/static/chunks/8892.9df3095f6c52e734.js +1 -0
  81. package/admin-out/_next/static/chunks/9104.6d57df418831714a.js +74 -0
  82. package/admin-out/_next/static/chunks/9121.574e833259fe9085.js +1 -0
  83. package/admin-out/_next/static/chunks/9142.0aac6a6c8e06bcaa.js +149 -0
  84. package/admin-out/_next/static/chunks/9180.3c809798364a0c62.js +1 -0
  85. package/admin-out/_next/static/chunks/92.788f49cdb265a668.js +217 -0
  86. package/admin-out/_next/static/chunks/9590.3e1a4754a7e66e84.js +93 -0
  87. package/admin-out/_next/static/chunks/9599.b2fd519c8a2951c9.js +1 -0
  88. package/admin-out/_next/static/chunks/9698-0157e7ac70c3f9fc.js +1 -0
  89. package/admin-out/_next/static/chunks/9837.92abff094b289f98.js +1 -0
  90. package/admin-out/_next/static/chunks/9839.73433bbeec6e1a51.js +1 -0
  91. package/admin-out/_next/static/chunks/9868.dcc9fd5f0041ffa8.js +1 -0
  92. package/admin-out/_next/static/chunks/9937.cff3c28655b07c61.js +24 -0
  93. package/admin-out/_next/static/chunks/a89fe872.304b3efb308b10a1.js +122 -0
  94. package/admin-out/_next/static/chunks/app/_not-found/page-e21cd35ca818a886.js +1 -0
  95. package/admin-out/_next/static/chunks/app/layout-0ed29966e0abc26b.js +1 -0
  96. package/admin-out/_next/static/chunks/app/page-30279944f9000c87.js +1 -0
  97. package/admin-out/_next/static/chunks/bf5d185f.735c9f3d05199f97.js +1 -0
  98. package/admin-out/_next/static/chunks/db534642.8e8a9023cd90863d.js +1 -0
  99. package/admin-out/_next/static/chunks/fcb912be.a7d93c5f2dd72e30.js +66 -0
  100. package/admin-out/_next/static/chunks/framework-98918e2142cd6d06.js +1 -0
  101. package/admin-out/_next/static/chunks/main-93c216652d4113b1.js +1 -0
  102. package/admin-out/_next/static/chunks/main-app-5e981adb363c52e5.js +1 -0
  103. package/admin-out/_next/static/chunks/pages/{_app-a3b7e86f97343e7a.js → _app-6fab9bb03f9f4fdf.js} +1 -1
  104. package/admin-out/_next/static/chunks/pages/_error-ada6d7affab6ebcc.js +1 -0
  105. package/admin-out/_next/static/chunks/webpack-7f8156dbbdb54868.js +1 -0
  106. package/admin-out/_next/static/css/46c83727621f8763.css +1 -0
  107. package/admin-out/index.html +1 -1
  108. package/admin-out/index.txt +5 -5
  109. package/bundled-docs/design/agentcore.md +1 -1
  110. package/bundled-docs/design/architecture.md +3 -3
  111. package/bundled-docs/design/storage.md +3 -3
  112. package/bundled-docs/design/ws.md +7 -7
  113. package/bundled-docs/dev/env.md +1 -2
  114. package/bundled-docs/guide/chat.md +1 -0
  115. package/bundled-docs/guide/workspace.md +7 -4
  116. package/bundled-docs/requirements/chat.md +1 -0
  117. package/bundled-docs/requirements/editor.md +1 -1
  118. package/bundled-docs/requirements/explorer.md +2 -0
  119. package/bundled-docs/requirements/source-control.md +2 -0
  120. package/bundled-docs/requirements/terminal.md +76 -44
  121. package/bundled-docs/requirements/workspace.md +10 -1
  122. package/dist/evo-wrapper.js +4 -5
  123. package/dist/index.js +176 -118
  124. package/package.json +3 -1
  125. package/templates/config.yaml +0 -6
  126. package/templates/models/aws-bedrock-claude-invoke.yaml +3 -3
  127. package/admin-out/_next/static/chunks/160.c52d3d6cf7bc8286.js +0 -1
  128. package/admin-out/_next/static/chunks/1b86ba38-c29611e086b2ce25.js +0 -1
  129. package/admin-out/_next/static/chunks/250.9094fea2325b09a3.js +0 -1
  130. package/admin-out/_next/static/chunks/304eda7d.f525962766560ba5.js +0 -1
  131. package/admin-out/_next/static/chunks/336.3171154ecc29c80a.js +0 -1
  132. package/admin-out/_next/static/chunks/362.a0c58d3bf9b1300b.js +0 -1
  133. package/admin-out/_next/static/chunks/398-9a8be186767b4504.js +0 -1
  134. package/admin-out/_next/static/chunks/449.c4b881b9ebdc556e.js +0 -1
  135. package/admin-out/_next/static/chunks/522.9e25c63e3082cb1c.js +0 -1
  136. package/admin-out/_next/static/chunks/58.d26b1c4f14404226.js +0 -1
  137. package/admin-out/_next/static/chunks/613.fb09e55e0a61d3fe.js +0 -1
  138. package/admin-out/_next/static/chunks/690.6a83d18b488a3e2e.js +0 -1
  139. package/admin-out/_next/static/chunks/698-19872069fed27164.js +0 -1
  140. package/admin-out/_next/static/chunks/73.05abce37d312e880.js +0 -1
  141. package/admin-out/_next/static/chunks/839.a2729fd33013d763.js +0 -1
  142. package/admin-out/_next/static/chunks/868.bbb91afd48c9eb58.js +0 -1
  143. package/admin-out/_next/static/chunks/892.a35118e09d8d8efd.js +0 -1
  144. package/admin-out/_next/static/chunks/989-04766caa08c5f506.js +0 -1
  145. package/admin-out/_next/static/chunks/app/_not-found/page-4271518f2746cf73.js +0 -1
  146. package/admin-out/_next/static/chunks/app/layout-ea161287d934ba96.js +0 -1
  147. package/admin-out/_next/static/chunks/app/page-ee1d0dae346ba9d2.js +0 -1
  148. package/admin-out/_next/static/chunks/db534642.657a5bd93dc1e8c7.js +0 -1
  149. package/admin-out/_next/static/chunks/framework-c48c994d2190a38e.js +0 -1
  150. package/admin-out/_next/static/chunks/main-app-340a5b58ed229c4d.js +0 -1
  151. package/admin-out/_next/static/chunks/main-f1f665fbc24e1033.js +0 -1
  152. package/admin-out/_next/static/chunks/pages/_error-751fca0c729a7e01.js +0 -1
  153. package/admin-out/_next/static/chunks/webpack-662d2cae1104f635.js +0 -1
  154. package/admin-out/_next/static/css/e395d2ae2e0636a0.css +0 -1
  155. /package/admin-out/_next/static/{a5z_n1eIm6T8T3Ty_MMHF → 1yjkA6O2OJ9CQ1XyyoazM}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -1924,7 +1924,7 @@ var init_init = __esm({
1924
1924
  path8.resolve(__dirname, "..", "bundled-docs"),
1925
1925
  path8.resolve(__dirname, "..", "..", "..", ".halo", "docs")
1926
1926
  ];
1927
- TEMPLATE_VERSION = 111;
1927
+ TEMPLATE_VERSION = 113;
1928
1928
  VERSION_FILE = ".template-version";
1929
1929
  SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
1930
1930
  BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
@@ -2653,7 +2653,7 @@ function generalSection() {
2653
2653
  { key: "limits.tool_result_render_chars", type: "int", globalOnly: true, description: 'Per-tool-result cap on the content fed back to the LLM. Larger results are truncated (with a "[Content truncated]" marker telling the model to re-run with narrower scope) to protect the context window and prompt cache. The UI/admin chat panel shows a far larger slice \u2014 see tool_result_ui_chars.', description_zh: "\u6BCF\u6761 tool result \u56DE\u4F20\u7ED9 LLM \u7684\u5185\u5BB9\u957F\u5EA6\u4E0A\u9650\u3002\u8D85\u51FA\u90E8\u5206\u4F1A\u88AB\u622A\u65AD\uFF08\u5E76\u9644 [Content truncated] \u6807\u8BB0\u63D0\u793A\u6A21\u578B\u7F29\u5C0F\u8303\u56F4\u91CD\u67E5\uFF09\uFF0C\u4EE5\u4FDD\u62A4\u4E0A\u4E0B\u6587\u7A97\u53E3\u548C\u63D0\u793A\u8BCD\u7F13\u5B58\u3002UI/admin \u804A\u5929\u9762\u677F\u5C55\u793A\u7684\u5185\u5BB9\u4E0A\u9650\u8981\u5927\u5F97\u591A\uFF0C\u89C1 tool_result_ui_chars\u3002", default: "8000" },
2654
2654
  { key: "limits.tool_result_ui_chars", type: "int", globalOnly: true, description: "Per-tool-result cap on the content stored for UI display (admin/web chat panel). Far larger than the LLM cap so the full output of a normal command stays visible, but bounded so a multi-MB `cat` does not bloat the session file, the WS payload, or the browser render. Output past this is truncated with a marker pointing at file_read for the complete content.", description_zh: "\u6BCF\u6761 tool result \u5B58\u7ED9 UI \u5C55\u793A\uFF08admin/web \u804A\u5929\u9762\u677F\uFF09\u7684\u5185\u5BB9\u957F\u5EA6\u4E0A\u9650\u3002\u8FDC\u5927\u4E8E LLM \u4E0A\u9650\uFF0C\u4FDD\u8BC1\u666E\u901A\u547D\u4EE4\u7684\u5B8C\u6574\u8F93\u51FA\u90FD\u80FD\u770B\u5230\uFF1B\u4F46\u4ECD\u6709\u754C\uFF0C\u907F\u514D cat \u4E2A\u51E0 MB \u7684\u6587\u4EF6\u6491\u7206\u4F1A\u8BDD\u6587\u4EF6\u3001WS \u4F20\u8F93\u548C\u6D4F\u89C8\u5668\u6E32\u67D3\u3002\u8D85\u51FA\u90E8\u5206\u622A\u65AD\u5E76\u9644\u6807\u8BB0\uFF0C\u63D0\u793A\u7528 file_read \u770B\u5B8C\u6574\u5185\u5BB9\u3002", default: String(64 * 1024) },
2655
2655
  { key: "limits.auto_report_chars", type: "int", globalOnly: true, description: "Cap on the auto-report a finished sub-agent delivers to its parent. Longer reports are truncated with a pointer to get_session_output for the full text.", description_zh: "\u5B50\u4F1A\u8BDD\u5B8C\u6210\u540E\u81EA\u52A8\u4E0A\u62A5\u7ED9\u7236\u4F1A\u8BDD\u7684\u5185\u5BB9\u957F\u5EA6\u4E0A\u9650\u3002\u8D85\u51FA\u622A\u65AD\uFF0C\u5E76\u63D0\u793A\u7528 get_session_output \u53D6\u5168\u6587\u3002", default: "8192" },
2656
- { key: "limits.terminal_scrollback_bytes", type: "int", globalOnly: true, description: "Off-screen scrollback bytes retained per persistent terminal while detached.", description_zh: "\u7EC8\u7AEF\u65AD\u5F00\u671F\u95F4\u4FDD\u7559\u7684\u56DE\u6EDA\u7F13\u51B2\u5B57\u8282\u6570\u3002", default: "50000" }
2656
+ { key: "limits.terminal_scrollback_lines", type: "int", globalOnly: true, description: "Scrollback lines the server keeps per terminal, restored to every page that attaches (reconnect, another browser or device). Applies to terminals opened after the change.", description_zh: "\u670D\u52A1\u7AEF\u4E3A\u6BCF\u4E2A\u7EC8\u7AEF\u4FDD\u7559\u7684\u56DE\u6EDA\u884C\u6570\uFF0C\u4EFB\u4F55\u9875\u9762\u63A5\u5165\uFF08\u91CD\u8FDE\u3001\u6362\u6D4F\u89C8\u5668\u6216\u8BBE\u5907\uFF09\u65F6\u6062\u590D\u3002\u4FEE\u6539\u540E\u5BF9\u65B0\u5F00\u7684\u7EC8\u7AEF\u751F\u6548\u3002", default: "5000" }
2657
2657
  ].map((f) => ({
2658
2658
  ...f,
2659
2659
  kind: "param",
@@ -3308,8 +3308,7 @@ var init_config = __esm({
3308
3308
  // fragments, SSE comments included), so for them it is an idle timeout — a
3309
3309
  // long but live stream is never cut off.
3310
3310
  modelRequest: systemInt("HALO_MODEL_TIMEOUT", "timeout.model_request", 10 * 6e4),
3311
- sessionGrace: systemInt("HALO_SESSION_GRACE", "timeout.session_grace", 5 * 6e4),
3312
- terminalGrace: systemInt("HALO_TERMINAL_GRACE", "timeout.terminal_grace", 5 * 6e4)
3311
+ sessionGrace: systemInt("HALO_SESSION_GRACE", "timeout.session_grace", 5 * 6e4)
3313
3312
  },
3314
3313
  // Runtime caps — read live from settings.yaml on every access. Getters
3315
3314
  // (not literals) so a settings reload takes effect on the next tool
@@ -3334,8 +3333,8 @@ var init_config = __esm({
3334
3333
  get autoReportMax() {
3335
3334
  return settingsInt("general.limits.auto_report_chars", 8192);
3336
3335
  },
3337
- get terminalOutputBuffer() {
3338
- return settingsInt("general.limits.terminal_scrollback_bytes", 5e4);
3336
+ get terminalScrollbackLines() {
3337
+ return settingsInt("general.limits.terminal_scrollback_lines", 5e3);
3339
3338
  }
3340
3339
  },
3341
3340
  compact: {
@@ -9979,10 +9978,10 @@ function completeTask(taskId, s) {
9979
9978
  if (!row || row.state !== "working")
9980
9979
  return;
9981
9980
  const level = s.accessLevel === null ? "full" : s.accessLevel ?? "readonly";
9982
- const attach = (text6) => attachResultFiles(text6, row.workspace, level);
9981
+ const attach2 = (text6) => attachResultFiles(text6, row.workspace, level);
9983
9982
  if (s.turnError) {
9984
9983
  const next = s.turnErrorKind === "account" ? "This is a model account / credential / balance / permission problem on the remote: re-sending will fail the same way until its model configuration is fixed." : "Send again on the same context to let it resume.";
9985
- const partial = s.output ? attach(s.output) : null;
9984
+ const partial = s.output ? attach2(s.output) : null;
9986
9985
  transition(taskId, "failed", {
9987
9986
  statusText: `The last turn was terminated by an unrecoverable error, NOT completed. Error: ${s.turnError}. ${next}`,
9988
9987
  result: partial?.text || null,
@@ -9991,7 +9990,7 @@ function completeTask(taskId, s) {
9991
9990
  });
9992
9991
  return;
9993
9992
  }
9994
- const done = attach(s.finalOutput || s.output || "");
9993
+ const done = attach2(s.finalOutput || s.output || "");
9995
9994
  transition(taskId, "completed", { result: done.text, resultFiles: done.files });
9996
9995
  }
9997
9996
  function pushConfigJson(r) {
@@ -16446,7 +16445,7 @@ async function initObservability(haloProcess = "server") {
16446
16445
  return true;
16447
16446
  }
16448
16447
  const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
16449
- providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.1.0", haloProcess);
16448
+ providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.1.2", haloProcess);
16450
16449
  console.log(`[Observability] OTLP export \u2192 ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT} (service.name=${process.env.OTEL_SERVICE_NAME}, halo.process=${haloProcess}, capture_content=${config.observability.captureContent})`);
16451
16450
  return true;
16452
16451
  }
@@ -23217,7 +23216,7 @@ function isUnwatchablePath(absPath) {
23217
23216
  }
23218
23217
  return null;
23219
23218
  }
23220
- var IGNORED_SEGMENTS, IS_WIN32, IGNORED_SEGMENT_SET, NATIVE_IGNORE, nativeOpChain, WorkspaceWatcher;
23219
+ var IGNORED_SEGMENTS, IS_WIN32, IGNORED_SEGMENT_SET, NATIVE_IGNORE, NATIVE_BACKEND, nativeOpChain, WorkspaceWatcher;
23221
23220
  var init_file_watcher = __esm({
23222
23221
  "../server/dist/ws/file-watcher.js"() {
23223
23222
  "use strict";
@@ -23284,6 +23283,7 @@ var init_file_watcher = __esm({
23284
23283
  IS_WIN32 = process.platform === "win32";
23285
23284
  IGNORED_SEGMENT_SET = new Set(IGNORED_SEGMENTS);
23286
23285
  NATIVE_IGNORE = IS_WIN32 ? IGNORED_SEGMENTS : [...IGNORED_SEGMENTS, `**/{${IGNORED_SEGMENTS.join(",")}}/**`];
23286
+ NATIVE_BACKEND = process.platform === "linux" ? "inotify" : IS_WIN32 ? "windows" : void 0;
23287
23287
  nativeOpChain = Promise.resolve();
23288
23288
  WorkspaceWatcher = class {
23289
23289
  subscription = null;
@@ -23325,7 +23325,7 @@ var init_file_watcher = __esm({
23325
23325
  }
23326
23326
  for (const e of events)
23327
23327
  this.handleEvent(e.type, e.path);
23328
- }, { ignore: NATIVE_IGNORE }));
23328
+ }, { ignore: NATIVE_IGNORE, backend: NATIVE_BACKEND }));
23329
23329
  if (this.startEpoch !== epoch) {
23330
23330
  void enqueueNativeOp(() => sub.unsubscribe()).catch((err) => {
23331
23331
  console.warn(`[FileWatcher] failed to unsubscribe superseded watch on ${root}: ${err instanceof Error ? err.message : String(err)}`);
@@ -30486,27 +30486,77 @@ function getPty() {
30486
30486
  ptyModule = requireFromHere("node-pty");
30487
30487
  return ptyModule;
30488
30488
  }
30489
+ function getHeadless() {
30490
+ if (!headlessModule) {
30491
+ headlessModule = {
30492
+ Terminal: requireFromHere("@xterm/headless").Terminal,
30493
+ SerializeAddon: requireFromHere("@xterm/addon-serialize").SerializeAddon
30494
+ };
30495
+ }
30496
+ return headlessModule;
30497
+ }
30498
+ function isOnline(t2, m) {
30499
+ return m !== null && (t2.attached.has(m) || t2.pending.has(m));
30500
+ }
30501
+ function applySize(t2, cols, rows) {
30502
+ if (t2.pty.cols === cols && t2.pty.rows === rows)
30503
+ return;
30504
+ try {
30505
+ t2.pty.resize(cols, rows);
30506
+ } catch {
30507
+ return;
30508
+ }
30509
+ t2.headless.resize(cols, rows);
30510
+ }
30511
+ function extraModes(term) {
30512
+ const core = term._core;
30513
+ let out = core?.coreService?.isCursorHidden ? "\x1B[?25l" : "";
30514
+ const encoding = core?.coreMouseService?.activeEncoding;
30515
+ if (encoding === "SGR")
30516
+ out += "\x1B[?1006h";
30517
+ else if (encoding === "SGR_PIXELS")
30518
+ out += "\x1B[?1016h";
30519
+ return out;
30520
+ }
30521
+ function attach(t2, m) {
30522
+ if (t2.attached.has(m) || t2.pending.has(m))
30523
+ return;
30524
+ t2.pending.set(m, []);
30525
+ t2.headless.write("", () => {
30526
+ const queued = t2.pending.get(m);
30527
+ if (!queued || terminals.get(t2.id) !== t2)
30528
+ return;
30529
+ t2.pending.delete(m);
30530
+ m.send({ type: "terminal:snapshot", terminalId: t2.id, data: t2.serializer.serialize() + extraModes(t2.headless), cols: t2.headless.cols, rows: t2.headless.rows });
30531
+ for (const data of queued)
30532
+ m.send({ type: "terminal:output", data, terminalId: t2.id });
30533
+ t2.attached.add(m);
30534
+ });
30535
+ }
30536
+ function endTerminal(t2, exitCode) {
30537
+ if (terminals.get(t2.id) !== t2)
30538
+ return;
30539
+ terminals.delete(t2.id);
30540
+ for (const m of [...t2.attached, ...t2.pending.keys()]) {
30541
+ m.send({ type: "terminal:exit", exitCode, terminalId: t2.id });
30542
+ }
30543
+ t2.attached.clear();
30544
+ t2.pending.clear();
30545
+ t2.sizes.clear();
30546
+ t2.driver = null;
30547
+ t2.headless.dispose();
30548
+ }
30489
30549
  function attachListenersOnce(t2) {
30490
30550
  t2.pty.onData((data) => {
30491
- if (t2.currentWs && t2.currentWs.readyState === t2.currentWs.OPEN) {
30492
- sendJson(t2.currentWs, { type: "terminal:output", data, terminalId: t2.id });
30493
- } else {
30494
- t2.buffer += data;
30495
- if (t2.buffer.length > config.limits.terminalOutputBuffer) {
30496
- t2.buffer = t2.buffer.slice(-config.limits.terminalOutputBuffer);
30497
- }
30498
- }
30499
- });
30500
- t2.pty.onExit(({ exitCode }) => {
30501
- if (t2.currentWs && t2.currentWs.readyState === t2.currentWs.OPEN) {
30502
- sendJson(t2.currentWs, { type: "terminal:exit", exitCode, terminalId: t2.id });
30503
- }
30504
- if (t2.graceTimer)
30505
- clearTimeout(t2.graceTimer);
30506
- terminals.delete(t2.id);
30551
+ t2.headless.write(data);
30552
+ for (const queued of t2.pending.values())
30553
+ queued.push(data);
30554
+ for (const m of t2.attached)
30555
+ m.send({ type: "terminal:output", data, terminalId: t2.id });
30507
30556
  });
30557
+ t2.pty.onExit(({ exitCode }) => endTerminal(t2, exitCode));
30508
30558
  }
30509
- var requireFromHere, ptyModule, TERMINAL_GRACE_MS, terminals, TerminalManager;
30559
+ var requireFromHere, ptyModule, headlessModule, terminals, subscribers, TerminalManager;
30510
30560
  var init_terminal_manager = __esm({
30511
30561
  "../server/dist/ws/terminal-manager.js"() {
30512
30562
  "use strict";
@@ -30515,14 +30565,19 @@ var init_terminal_manager = __esm({
30515
30565
  init_event_processor();
30516
30566
  requireFromHere = createRequire(import.meta.url);
30517
30567
  ptyModule = null;
30518
- TERMINAL_GRACE_MS = config.timeout.terminalGrace;
30568
+ headlessModule = null;
30519
30569
  terminals = /* @__PURE__ */ new Map();
30570
+ subscribers = /* @__PURE__ */ new Map();
30520
30571
  TerminalManager = class {
30521
- ownedIds = /* @__PURE__ */ new Set();
30522
30572
  ws;
30573
+ /** Workspace this connection subscribed to via terminal:reattach. */
30574
+ workspace = null;
30523
30575
  constructor(ws) {
30524
30576
  this.ws = ws;
30525
30577
  }
30578
+ send(frame) {
30579
+ sendJson(this.ws, frame);
30580
+ }
30526
30581
  start(opts) {
30527
30582
  const terminalId = opts.terminalId ?? `term_${Date.now().toString(36)}`;
30528
30583
  const existing = terminals.get(terminalId);
@@ -30531,9 +30586,7 @@ var init_terminal_manager = __esm({
30531
30586
  existing.pty.kill();
30532
30587
  } catch {
30533
30588
  }
30534
- if (existing.graceTimer)
30535
- clearTimeout(existing.graceTimer);
30536
- terminals.delete(terminalId);
30589
+ endTerminal(existing, 0);
30537
30590
  }
30538
30591
  const cwd = opts.cwd === "~" || !opts.cwd ? homedir23() : opts.cwd;
30539
30592
  const cols = opts.cols ?? 80;
@@ -30544,113 +30597,119 @@ var init_terminal_manager = __esm({
30544
30597
  const shellName = basename(shell).toLowerCase();
30545
30598
  const args = ["bash", "zsh", "sh", "fish"].some((s) => shellName.startsWith(s)) ? ["-l"] : [];
30546
30599
  const child = getPty().spawn(shell, args, { name: "xterm-256color", cols, rows, cwd, env: termEnv });
30600
+ const { Terminal, SerializeAddon } = getHeadless();
30601
+ const headless = new Terminal({ cols: child.cols, rows: child.rows, scrollback: config.limits.terminalScrollbackLines, allowProposedApi: true, logLevel: "off" });
30602
+ const serializer = new SerializeAddon();
30603
+ headless.loadAddon(serializer);
30547
30604
  const t2 = {
30548
30605
  pty: child,
30549
30606
  id: terminalId,
30550
- currentWs: this.ws,
30551
- buffer: "",
30552
- graceTimer: null,
30553
- browserId: opts.browserId ?? "",
30554
- workspacePath: opts.workspacePath ?? ""
30607
+ name: opts.name || basename(shell),
30608
+ workspacePath: opts.workspacePath ?? "",
30609
+ headless,
30610
+ serializer,
30611
+ attached: /* @__PURE__ */ new Set([this]),
30612
+ pending: /* @__PURE__ */ new Map(),
30613
+ sizes: /* @__PURE__ */ new Map([[this, { cols: child.cols, rows: child.rows }]]),
30614
+ driver: this
30555
30615
  };
30556
30616
  attachListenersOnce(t2);
30557
30617
  terminals.set(terminalId, t2);
30558
- this.ownedIds.add(terminalId);
30559
- sendJson(this.ws, { type: "terminal:ready", terminalId });
30618
+ this.send({ type: "terminal:ready", terminalId });
30619
+ for (const m of subscribers.get(t2.workspacePath) ?? []) {
30620
+ if (m === this)
30621
+ continue;
30622
+ m.send({ type: "terminal:opened", terminalId, name: t2.name });
30623
+ attach(t2, m);
30624
+ }
30560
30625
  console.log(`[WS] Terminal started (id=${terminalId}, pid=${child.pid}, cwd=${cwd})`);
30561
30626
  return terminalId;
30562
30627
  }
30563
30628
  // No terminalId → reject (audit A-M3). The old fallback took the FIRST entry
30564
- // of the global `terminals` map — not even scoped to this.ownedIds — so with
30565
- // several admin connections an id-less input could write into another
30566
- // browser's PTY. Every admin send site always includes terminalId (verified
30567
- // against the panel and the compiled desktop bundle), so nothing legitimate
30568
- // hits this path.
30629
+ // of the global `terminals` map, so with several admin connections an
30630
+ // id-less input could write into a PTY of another workspace. Every admin
30631
+ // send site always includes terminalId (verified against the panel and the
30632
+ // compiled desktop bundle), so nothing legitimate hits this path.
30569
30633
  writeInput(terminalId, data) {
30570
30634
  if (!terminalId) {
30571
30635
  console.warn("[WS] terminal:input without terminalId rejected");
30572
30636
  return;
30573
30637
  }
30574
30638
  const t2 = terminals.get(terminalId);
30575
- if (t2)
30576
- t2.pty.write(data);
30577
- }
30639
+ if (!t2)
30640
+ return;
30641
+ t2.driver = this;
30642
+ const size = t2.sizes.get(this);
30643
+ if (size)
30644
+ applySize(t2, size.cols, size.rows);
30645
+ t2.pty.write(data);
30646
+ }
30647
+ /** Records this page's size; applies it only when this page is the driver
30648
+ * or no driver is attached — otherwise a background page's resize would
30649
+ * reflow the screen under whoever is typing. */
30578
30650
  resize(terminalId, cols, rows) {
30579
30651
  if (!terminalId) {
30580
30652
  console.warn("[WS] terminal:resize without terminalId rejected");
30581
30653
  return;
30582
30654
  }
30655
+ if (!Number.isInteger(cols) || !Number.isInteger(rows) || cols < 1 || rows < 1)
30656
+ return;
30583
30657
  const t2 = terminals.get(terminalId);
30584
- if (t2)
30585
- t2.pty.resize(cols, rows);
30658
+ if (!t2)
30659
+ return;
30660
+ t2.sizes.set(this, { cols, rows });
30661
+ if (t2.driver === this || !isOnline(t2, t2.driver)) {
30662
+ t2.driver = this;
30663
+ applySize(t2, cols, rows);
30664
+ }
30586
30665
  }
30587
30666
  close(terminalId) {
30588
30667
  const t2 = terminals.get(terminalId);
30589
30668
  if (!t2)
30590
30669
  return;
30591
- if (t2.graceTimer)
30592
- clearTimeout(t2.graceTimer);
30593
30670
  try {
30594
30671
  t2.pty.kill();
30595
30672
  } catch {
30596
30673
  }
30597
- if (t2.currentWs && t2.currentWs.readyState === t2.currentWs.OPEN) {
30598
- sendJson(t2.currentWs, { type: "terminal:exit", terminalId, exitCode: 0 });
30599
- }
30600
- terminals.delete(terminalId);
30601
- this.ownedIds.delete(terminalId);
30674
+ endTerminal(t2, 0);
30602
30675
  }
30603
- /** WS closed: set currentWs=null and start grace timer for each owned PTY. */
30676
+ /** WS closed: leave every PTY's attached set and the workspace
30677
+ * subscription. The PTYs keep running — no timer. */
30604
30678
  detachAll() {
30605
- for (const id of this.ownedIds) {
30606
- const t2 = terminals.get(id);
30607
- if (!t2)
30608
- continue;
30609
- if (t2.currentWs !== this.ws)
30610
- continue;
30611
- t2.currentWs = null;
30612
- t2.graceTimer = setTimeout(() => {
30613
- console.log(`[WS] Terminal ${id} grace period expired, killing`);
30614
- try {
30615
- t2.pty.kill();
30616
- } catch {
30617
- }
30618
- terminals.delete(id);
30619
- }, TERMINAL_GRACE_MS);
30620
- }
30621
- }
30622
- /** Reconnect: claim PTYs that match (browserId × workspacePath) the
30623
- * caller reports. Both must match — different browser, different
30624
- * workspace, or either missing means "not yours, leave alone". PTYs
30625
- * not claimed here keep streaming to whoever currently owns them,
30626
- * or stay buffered until their original (browser, workspace) returns.
30627
- * Returns the ids that were reattached.
30628
- *
30629
- * Empty `browserId` is treated as "unidentified" and only matches
30630
- * other unidentified PTYs (legacy clients pre-upgrade); new admin
30631
- * builds always send a real id. */
30632
- reattachAll(browserId, workspacePath) {
30633
- const reattached = [];
30634
- for (const [id, t2] of terminals) {
30635
- if (t2.browserId !== browserId)
30636
- continue;
30637
- if (t2.workspacePath !== workspacePath)
30638
- continue;
30639
- if (t2.graceTimer) {
30640
- clearTimeout(t2.graceTimer);
30641
- t2.graceTimer = null;
30642
- }
30643
- t2.currentWs = this.ws;
30644
- this.ownedIds.add(id);
30645
- if (t2.buffer) {
30646
- sendJson(this.ws, { type: "terminal:output", data: t2.buffer, terminalId: id });
30647
- t2.buffer = "";
30648
- }
30649
- reattached.push(id);
30650
- }
30651
- sendJson(this.ws, { type: "terminal:reattached", terminalIds: reattached });
30652
- console.log(`[WS] Reattached ${reattached.length} terminals for browser=${browserId.slice(0, 8) || "(none)"} workspace=${workspacePath || "(none)"}`);
30653
- return reattached;
30679
+ for (const t2 of terminals.values()) {
30680
+ t2.attached.delete(this);
30681
+ t2.pending.delete(this);
30682
+ t2.sizes.delete(this);
30683
+ if (t2.driver === this)
30684
+ t2.driver = null;
30685
+ }
30686
+ this.unsubscribe();
30687
+ }
30688
+ /** Attach to every PTY of `workspacePath` (snapshot each) and subscribe to
30689
+ * the workspace, so PTYs started there later are pushed here too. Any
30690
+ * browser / device may attach — the admin has one login, terminals have
30691
+ * no per-browser owner. Re-sending is harmless: attached PTYs are skipped. */
30692
+ reattachAll(workspacePath) {
30693
+ this.unsubscribe();
30694
+ this.workspace = workspacePath;
30695
+ let subs = subscribers.get(workspacePath);
30696
+ if (!subs)
30697
+ subscribers.set(workspacePath, subs = /* @__PURE__ */ new Set());
30698
+ subs.add(this);
30699
+ const list = [...terminals.values()].filter((t2) => t2.workspacePath === workspacePath);
30700
+ this.send({ type: "terminal:reattached", terminals: list.map((t2) => ({ id: t2.id, name: t2.name })) });
30701
+ for (const t2 of list)
30702
+ attach(t2, this);
30703
+ console.log(`[WS] Reattached ${list.length} terminals for workspace=${workspacePath || "(none)"}`);
30704
+ }
30705
+ unsubscribe() {
30706
+ if (this.workspace === null)
30707
+ return;
30708
+ const subs = subscribers.get(this.workspace);
30709
+ subs?.delete(this);
30710
+ if (subs?.size === 0)
30711
+ subscribers.delete(this.workspace);
30712
+ this.workspace = null;
30654
30713
  }
30655
30714
  };
30656
30715
  }
@@ -30909,7 +30968,7 @@ function setupWebSocketHandler(deps) {
30909
30968
  terminalManager.close(msg.terminalId);
30910
30969
  break;
30911
30970
  case "terminal:reattach":
30912
- terminalManager.reattachAll(msg.browserId ?? "", msg.workspacePath ?? "");
30971
+ terminalManager.reattachAll(msg.workspacePath ?? "");
30913
30972
  break;
30914
30973
  case "session:delete":
30915
30974
  await handleSessionDelete(client, ws, msg);
@@ -31237,8 +31296,8 @@ ${msg.message}` : markers.join("\n");
31237
31296
  cwd,
31238
31297
  cols: msg.cols,
31239
31298
  rows: msg.rows,
31240
- browserId: msg.browserId ?? "",
31241
- workspacePath: msg.workspacePath ?? ""
31299
+ workspacePath: msg.workspacePath ?? "",
31300
+ name: msg.name
31242
31301
  });
31243
31302
  } catch (err) {
31244
31303
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -31632,7 +31691,7 @@ function buildCard(workspace, interfaceUrl, caps) {
31632
31691
  return {
31633
31692
  name: raw.name,
31634
31693
  description: raw.description,
31635
- version: typeof raw.version === "string" ? raw.version : "2.1.0",
31694
+ version: typeof raw.version === "string" ? raw.version : "2.1.2",
31636
31695
  supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
31637
31696
  capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
31638
31697
  ...caps.tokenAuth === false ? {} : {
@@ -34393,7 +34452,7 @@ function createCoreChecker(opts) {
34393
34452
  }
34394
34453
  function getCoreStatus(force) {
34395
34454
  checker ??= createCoreChecker({
34396
- haloVersion: "2.1.0",
34455
+ haloVersion: "2.1.2",
34397
34456
  fetchLatest: fetchNpmLatest,
34398
34457
  onChange: (status) => broadcast({ type: "updates:changed", scope: "core", status })
34399
34458
  });
@@ -34561,7 +34620,7 @@ function hubBase() {
34561
34620
  }
34562
34621
  function serverChecker() {
34563
34622
  checker2 ??= createExtensionsChecker({
34564
- haloVersion: "2.1.0",
34623
+ haloVersion: "2.1.2",
34565
34624
  installed: () => {
34566
34625
  const s = getSnapshot();
34567
34626
  return [...s.extensions, ...s.disabled];
@@ -40850,7 +40909,7 @@ var init_dist2 = __esm({
40850
40909
  init_git_ssh();
40851
40910
  __dirname3 = path90.dirname(fileURLToPath3(import.meta.url));
40852
40911
  PORT = config.server.port;
40853
- HALO_VERSION = "2.1.0";
40912
+ HALO_VERSION = "2.1.2";
40854
40913
  PROJECT_ROOT = findProjectRoot();
40855
40914
  HALO_HOME4 = path90.join(homedir25(), ".halo");
40856
40915
  GIT_SHA = readGitSha();
@@ -41624,7 +41683,6 @@ var init_agentcore_front = __esm({
41624
41683
  "HALO_WEB_FETCH_TIMEOUT",
41625
41684
  "HALO_MODEL_TIMEOUT",
41626
41685
  "HALO_SESSION_GRACE",
41627
- "HALO_TERMINAL_GRACE",
41628
41686
  "HALO_MAX_CACHED_SESSIONS",
41629
41687
  "HALO_LOG_MAX_SIZE",
41630
41688
  "HALO_LOG_MAX_FILES"
@@ -42910,7 +42968,7 @@ function runNode(opts) {
42910
42968
  shellTimeoutMs: config.timeout.shellExec,
42911
42969
  os: process.platform,
42912
42970
  hostname: os13.hostname(),
42913
- version: "2.1.0"
42971
+ version: "2.1.2"
42914
42972
  };
42915
42973
  const exec2 = createNodeExecutor({ root, base, allowShell }, log2);
42916
42974
  const instance = crypto16.randomUUID();
@@ -43426,7 +43484,7 @@ function installUserUnit(opts, run = runCommand) {
43426
43484
  }
43427
43485
 
43428
43486
  // src/index.ts
43429
- var VERSION = "2.1.0";
43487
+ var VERSION = "2.1.2";
43430
43488
  var HELP_TOP = `Usage: halo <command> [options]
43431
43489
 
43432
43490
  Commands:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turmind/halo",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Halo — multi-agent collaborative workspace. CLI + TUI + HTTP/WS server in one package.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,6 +37,8 @@
37
37
  "@parcel/watcher": "^2.5.6",
38
38
  "@smithy/signature-v4": "^5.3.13",
39
39
  "@wecom/aibot-node-sdk": "^1.0.7",
40
+ "@xterm/addon-serialize": "^0.14.0",
41
+ "@xterm/headless": "^6.0.0",
40
42
  "better-sqlite3": "^11.7.0",
41
43
  "croner": "^10.0.1",
42
44
  "drizzle-orm": "^0.45.2",
@@ -9,7 +9,6 @@
9
9
  # timeout.web_fetch → HALO_WEB_FETCH_TIMEOUT
10
10
  # timeout.model_request → HALO_MODEL_TIMEOUT
11
11
  # timeout.session_grace → HALO_SESSION_GRACE
12
- # timeout.terminal_grace → HALO_TERMINAL_GRACE
13
12
  # logging.max_file_size → HALO_LOG_MAX_SIZE
14
13
  # logging.max_files → HALO_LOG_MAX_FILES
15
14
 
@@ -56,11 +55,6 @@ timeout:
56
55
  default: 300000
57
56
  description: "Idle session grace period before unloading from memory (ms)."
58
57
  description_zh: "空闲会话保留在内存中的时长(毫秒)。"
59
- terminal_grace:
60
- value: 300000
61
- default: 300000
62
- description: "Terminal grace period after disconnect before killing the pty (ms)."
63
- description_zh: "终端断连后保留 pty 的时长(毫秒)。"
64
58
 
65
59
  logging:
66
60
  max_file_size:
@@ -1,10 +1,10 @@
1
1
  id: aws-bedrock-claude-invoke
2
2
  runtime: bedrock-invoke
3
- revision: 2026101005
3
+ revision: 2026110401
4
4
  displayName: AWS Bedrock Claude (Invoke API)
5
5
  displayName_zh: AWS Bedrock Claude(Invoke API)
6
- description: Invokes Bedrock via InvokeModel (non-streaming), sends raw Anthropic Messages API format
7
- description_zh: 通过 Bedrock InvokeModel(非流式)调用,发送原生 Anthropic Messages API 格式
6
+ description: Invokes Bedrock via InvokeModelWithResponseStream (streaming), sends raw Anthropic Messages API format
7
+ description_zh: 通过 Bedrock InvokeModelWithResponseStream(流式)调用,发送原生 Anthropic Messages API 格式
8
8
  defaultEndpoint: https://bedrock-runtime.us-east-1.amazonaws.com
9
9
  endpointPresets:
10
10
  - https://bedrock-runtime.us-east-1.amazonaws.com