@turmind/halo 1.5.10 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +2 -2
  2. package/admin-out/404.html +1 -1
  3. package/admin-out/_next/static/chunks/{388-d5950f264d91625a.js → 147-d4200c70445aabb6.js} +1 -1
  4. package/admin-out/_next/static/chunks/989-a7f752480eaaa2dc.js +1 -0
  5. package/admin-out/_next/static/chunks/app/{layout-5ec6c5f713a8562b.js → layout-ea161287d934ba96.js} +1 -1
  6. package/admin-out/_next/static/chunks/app/page-8173112f256bc483.js +1 -0
  7. package/admin-out/_next/static/chunks/{webpack-efd27999305b080a.js → webpack-dc73047e0279979b.js} +1 -1
  8. package/admin-out/_next/static/css/7b736202f0b1dbfd.css +1 -0
  9. package/admin-out/_next/static/css/981c9e5610ce535a.css +1 -0
  10. package/admin-out/index.html +1 -1
  11. package/admin-out/index.txt +6 -5
  12. package/bundled-docs/design/a2a.md +286 -0
  13. package/bundled-docs/design/agent.md +7 -5
  14. package/bundled-docs/design/agentcore.md +194 -122
  15. package/bundled-docs/design/architecture.md +2 -2
  16. package/bundled-docs/design/canvas-extensions.md +30 -9
  17. package/bundled-docs/design/halo-city.md +6 -0
  18. package/bundled-docs/design/observability.md +12 -4
  19. package/bundled-docs/design/prompt-system.md +1 -1
  20. package/bundled-docs/design/relay.md +6 -6
  21. package/bundled-docs/design/session.md +15 -12
  22. package/bundled-docs/design/storage.md +9 -2
  23. package/bundled-docs/design/web.md +36 -59
  24. package/bundled-docs/dev/acp-adapter.md +59 -175
  25. package/bundled-docs/dev/api.md +75 -6
  26. package/bundled-docs/dev/deploy.md +3 -2
  27. package/bundled-docs/dev/desktop-packaging.md +14 -0
  28. package/bundled-docs/dev/env.md +10 -6
  29. package/bundled-docs/dev/tools.md +101 -11
  30. package/bundled-docs/guide/README.md +1 -1
  31. package/bundled-docs/guide/channels/README.md +3 -3
  32. package/bundled-docs/guide/channels/acp.md +67 -42
  33. package/bundled-docs/guide/channels/feishu.md +1 -1
  34. package/bundled-docs/guide/channels/slack.md +1 -1
  35. package/bundled-docs/guide/channels/telegram.md +1 -1
  36. package/bundled-docs/guide/channels/web.md +10 -34
  37. package/bundled-docs/guide/channels/wechat.md +1 -1
  38. package/bundled-docs/guide/channels/wecom.md +1 -1
  39. package/bundled-docs/guide/chat.md +0 -1
  40. package/bundled-docs/guide/cli.md +41 -6
  41. package/bundled-docs/guide/delegation-and-access.md +3 -2
  42. package/bundled-docs/guide/getting-started.md +1 -1
  43. package/bundled-docs/guide/skills.md +2 -3
  44. package/bundled-docs/requirements/agent.md +1 -1
  45. package/bundled-docs/requirements/chat.md +17 -1
  46. package/bundled-docs/requirements/command.md +1 -2
  47. package/bundled-docs/requirements/editor.md +9 -3
  48. package/bundled-docs/requirements/explorer.md +1 -0
  49. package/bundled-docs/requirements/terminal.md +15 -0
  50. package/bundled-docs/requirements/workspace.md +6 -0
  51. package/dist/index.js +5392 -2786
  52. package/package.json +1 -1
  53. package/templates/agents/__score__/AGENT.md +1 -1
  54. package/templates/agents/default/agent.yaml +0 -1
  55. package/templates/models/aws-bedrock-claude-invoke.yaml +40 -1
  56. package/templates/models/aws-bedrock-openai.yaml +100 -6
  57. package/templates/prompts/all/RUNTIME.md +2 -1
  58. package/templates/prompts/all/TOOL_SHELL.windows.md +2 -1
  59. package/templates/skills/send-file/SKILL.md +1 -1
  60. package/templates/skills/send-file/a2a.md +13 -0
  61. package/templates/skills/skill/SKILL.md +1 -1
  62. package/templates/skills/workspace/stage.py +1 -1
  63. package/admin-out/_next/static/chunks/989-1797287c46139412.js +0 -1
  64. package/admin-out/_next/static/chunks/app/page-44ab337b2f071e4d.js +0 -1
  65. package/admin-out/_next/static/css/d53aa54212002364.css +0 -3
  66. package/templates/skills/acp/SKILL.md +0 -243
  67. package/templates/skills/acp/templates/SKILL.md.tmpl +0 -75
  68. package/templates/skills/acp/templates/ask.py +0 -177
  69. package/templates/skills/acp/templates/config.yaml.tmpl +0 -38
  70. /package/admin-out/_next/static/{A-Rjx2yltZDKaSO1qVv7K → _F_Fkyh9PainUNY82EEjY}/_buildManifest.js +0 -0
  71. /package/admin-out/_next/static/{A-Rjx2yltZDKaSO1qVv7K → _F_Fkyh9PainUNY82EEjY}/_ssgManifest.js +0 -0
@@ -1,177 +0,0 @@
1
- #!/usr/bin/env python3
2
- """ask.py — call an agent over ACP: remote halo server, local Claude Code, or local Kiro. See SKILL.md."""
3
- from __future__ import annotations
4
-
5
- import argparse
6
- import json
7
- import os
8
- import shutil
9
- import subprocess
10
- import sys
11
- import threading
12
- import time
13
- from typing import Any
14
-
15
-
16
- def fail(msg: str, code: int = 1) -> None:
17
- sys.stderr.write(f"[ask-acp-agent] {msg}\n")
18
- sys.exit(code)
19
-
20
-
21
- def main() -> None:
22
- p = argparse.ArgumentParser(prog="ask.py", description="Ask a remote agent over ACP.")
23
- p.add_argument("question")
24
- p.add_argument("--kind", default="halo", choices=["halo", "claude", "kiro"],
25
- help="halo: remote halo server via `halo acp`; claude: local Claude Code via `claude-agent-acp`; kiro: local Kiro via `kiro-cli acp`.")
26
- p.add_argument("--host")
27
- p.add_argument("--port")
28
- p.add_argument("--scheme", default="http")
29
- p.add_argument("--token")
30
- p.add_argument("--workspace")
31
- p.add_argument("--cwd", default=None, help="claude kind: working directory for the session (defaults to CWD).")
32
- p.add_argument("--agent-id", default=None)
33
- p.add_argument("--session-id", default=None)
34
- p.add_argument("--timeout", type=int, default=600)
35
- p.add_argument("--halo-bin", default=None)
36
- p.add_argument("--claude-bin", default=None)
37
- p.add_argument("--kiro-bin", default=None)
38
- args = p.parse_args()
39
-
40
- if args.kind == "claude":
41
- bin_ = args.claude_bin or os.environ.get("CLAUDE_ACP_BIN") or "claude-agent-acp"
42
- if shutil.which(bin_) is None and not os.path.isabs(bin_):
43
- fail(f"`{bin_}` not found in PATH. npm install -g @agentclientprotocol/claude-agent-acp, or set --claude-bin.", 2)
44
- cmd = [bin_]
45
- elif args.kind == "kiro":
46
- bin_ = args.kiro_bin or os.environ.get("KIRO_ACP_BIN") or "kiro-cli"
47
- if shutil.which(bin_) is None and not os.path.isabs(bin_):
48
- fail(f"`{bin_}` not found in PATH. Install Kiro CLI, or set --kiro-bin.", 2)
49
- # --trust-all-tools: the binding is a headless relay; there's no human
50
- # at this end to answer kiro's per-tool permission prompts.
51
- cmd = [bin_, "acp", "--trust-all-tools"]
52
- if args.agent_id and not args.agent_id.startswith("{{"):
53
- cmd += ["--agent", args.agent_id]
54
- else:
55
- for k in ("host", "port", "token", "workspace"):
56
- if not getattr(args, k):
57
- fail(f"--{k} is required for --kind halo", 2)
58
- halo = args.halo_bin or os.environ.get("HALO_BIN") or "halo"
59
- if shutil.which(halo) is None and not os.path.isabs(halo):
60
- fail(f"`{halo}` not found in PATH. Install @turmind/halo or set --halo-bin.", 2)
61
- cmd = [halo, "acp", "--host", args.host, "--port", str(args.port),
62
- "--scheme", args.scheme, "--token", args.token, "--workspace", args.workspace]
63
- # Drop `--agent-id` when blank OR an unsubstituted `{{...}}` literal.
64
- # Both mean "user hasn't configured this optional field" — the first
65
- # because settings.yaml has `agent_id: ""`, the second because the
66
- # key isn't in settings.yaml at all and halo's shell_exec
67
- # substitute leaves the placeholder verbatim (its "fail loud"
68
- # contract for required params). For an optional flag like this, we
69
- # want graceful degrade, not a literal-as-value going to acp.
70
- aid = (args.agent_id or "").strip()
71
- if aid and not (aid.startswith("{{") and aid.endswith("}}")):
72
- cmd += ["--agent-id", aid]
73
-
74
- proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
75
- stderr=subprocess.PIPE, text=True, bufsize=1)
76
- assert proc.stdin and proc.stdout and proc.stderr
77
-
78
- def _drain_stderr() -> None:
79
- for line in proc.stderr:
80
- sys.stderr.write(line)
81
- threading.Thread(target=_drain_stderr, daemon=True).start()
82
-
83
- next_id = 1
84
- pending: dict[int, dict[str, Any]] = {}
85
- chunks: list[str] = []
86
-
87
- def send(method: str, params: dict[str, Any] | None = None) -> int:
88
- nonlocal next_id
89
- rid = next_id
90
- next_id += 1
91
- msg = {"jsonrpc": "2.0", "id": rid, "method": method}
92
- if params is not None:
93
- msg["params"] = params
94
- proc.stdin.write(json.dumps(msg) + "\n")
95
- proc.stdin.flush()
96
- return rid
97
-
98
- def wait_for(rid: int, deadline: float) -> dict[str, Any]:
99
- while True:
100
- if rid in pending:
101
- return pending.pop(rid)
102
- if time.time() > deadline:
103
- proc.kill()
104
- fail(f"timeout waiting for response to request {rid}", 124)
105
- line = proc.stdout.readline()
106
- if line == "":
107
- rc = proc.wait(timeout=1)
108
- fail(f"adapter exited prematurely (rc={rc})", rc or 1)
109
- line = line.strip()
110
- if not line:
111
- continue
112
- try:
113
- msg = json.loads(line)
114
- except json.JSONDecodeError:
115
- sys.stderr.write(f"[ask-acp-agent] non-JSON: {line[:200]}\n")
116
- continue
117
- if "id" in msg and ("result" in msg or "error" in msg):
118
- pending[msg["id"]] = msg
119
- continue
120
- method = msg.get("method")
121
- if method == "session/update":
122
- update = (msg.get("params") or {}).get("update") or {}
123
- if update.get("sessionUpdate") == "agent_message_chunk":
124
- text = (update.get("content") or {}).get("text", "")
125
- if text:
126
- chunks.append(text)
127
-
128
- deadline = time.time() + args.timeout
129
- try:
130
- rid = send("initialize", {"protocolVersion": 1, "clientCapabilities": {}})
131
- resp = wait_for(rid, deadline)
132
- if "error" in resp:
133
- fail(f"initialize failed: {resp['error']}")
134
-
135
- if args.session_id:
136
- # ACP session/load requires cwd + mcpServers (same as session/new);
137
- # kiro-cli exits silently if they're missing.
138
- load_params: dict[str, Any] = {"sessionId": args.session_id}
139
- if args.kind in ("claude", "kiro"):
140
- load_params["cwd"] = args.cwd or os.getcwd()
141
- load_params["mcpServers"] = []
142
- rid = send("session/load", load_params)
143
- resp = wait_for(rid, deadline)
144
- if "error" in resp:
145
- fail(f"session/load failed: {resp['error']}")
146
- session_id = args.session_id
147
- else:
148
- new_params = {"cwd": args.cwd or os.getcwd(), "mcpServers": []} if args.kind in ("claude", "kiro") else {}
149
- rid = send("session/new", new_params)
150
- resp = wait_for(rid, deadline)
151
- if "error" in resp:
152
- fail(f"session/new failed: {resp['error']}")
153
- session_id = resp["result"]["sessionId"]
154
-
155
- rid = send("session/prompt", {
156
- "sessionId": session_id,
157
- "prompt": [{"type": "text", "text": args.question}],
158
- })
159
- resp = wait_for(rid, deadline)
160
- if "error" in resp:
161
- fail(f"session/prompt failed: {resp['error']}")
162
- stop_reason = resp["result"].get("stopReason", "unknown")
163
-
164
- sys.stdout.write(f"SESSION: {session_id}\n---\n")
165
- sys.stdout.write("".join(chunks).rstrip() + "\n")
166
-
167
- if stop_reason != "end_turn":
168
- sys.stderr.write(f"[ask-acp-agent] stopReason={stop_reason}\n")
169
- finally:
170
- try: proc.stdin.close()
171
- except Exception: pass
172
- try: proc.wait(timeout=5)
173
- except subprocess.TimeoutExpired: proc.kill()
174
-
175
-
176
- if __name__ == "__main__":
177
- main()
@@ -1,38 +0,0 @@
1
- displayName: Ask {{LABEL_DISPLAY}}
2
- description: Forward a question to the {{LABEL_DISPLAY}} halo agent over ACP.
3
-
4
- params:
5
- - key: host
6
- description: Remote halo server hostname or IP.
7
- description_zh: 远端 halo server 主机名 / IP。
8
- default: "{{HOST}}"
9
-
10
- - key: port
11
- description: Remote halo server port.
12
- description_zh: 远端 halo server 端口。
13
- default: "{{PORT}}"
14
-
15
- - key: scheme
16
- description: URL scheme to reach the remote halo server — http or https.
17
- description_zh: 连接远端 halo server 的协议 — http 或 https。
18
- default: "{{SCHEME}}"
19
-
20
- - key: workspace
21
- description: Absolute path of the remote workspace to drive.
22
- description_zh: 要驱动的远端 workspace 绝对路径。
23
- default: "{{WORKSPACE}}"
24
-
25
- - key: label
26
- description: Friendly name for the remote, shown when reporting back to the user.
27
- description_zh: 报告给用户时使用的称呼。
28
- default: "{{LABEL_DISPLAY}}"
29
-
30
- - key: agent_id
31
- description: Optional remote agent profile id. Blank = remote 'default'.
32
- description_zh: 可选的远端 agent id,留空则用远端 default。
33
- default: ""
34
-
35
- - key: token
36
- description: Web-channel token from the remote halo admin. Must be a full-access token if cross-workspace addressing is needed.
37
- description_zh: 远端 halo 后台 Web channel token。若需跨 workspace 调用必须是 full 权限。
38
- secret: true