@tt-a1i/hive 1.5.0 → 1.7.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 (82) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.en.md +23 -1
  3. package/README.md +10 -1
  4. package/dist/src/cli/team.js +19 -2
  5. package/dist/src/server/agent-run-bootstrap.d.ts +6 -1
  6. package/dist/src/server/agent-run-bootstrap.js +5 -2
  7. package/dist/src/server/agent-run-starter.d.ts +6 -7
  8. package/dist/src/server/agent-run-starter.js +18 -4
  9. package/dist/src/server/agent-runtime-contract.d.ts +10 -0
  10. package/dist/src/server/agent-runtime-stop-run.d.ts +1 -1
  11. package/dist/src/server/agent-runtime-stop-run.js +4 -1
  12. package/dist/src/server/agent-runtime.d.ts +2 -1
  13. package/dist/src/server/agent-runtime.js +10 -5
  14. package/dist/src/server/agent-startup-instructions.d.ts +7 -8
  15. package/dist/src/server/agent-startup-instructions.js +6 -4
  16. package/dist/src/server/agent-stdin-dispatcher.d.ts +20 -7
  17. package/dist/src/server/agent-stdin-dispatcher.js +22 -10
  18. package/dist/src/server/command-preset-defaults.js +12 -0
  19. package/dist/src/server/feature-flags.d.ts +42 -0
  20. package/dist/src/server/feature-flags.js +24 -0
  21. package/dist/src/server/hive-team-guidance.d.ts +4 -3
  22. package/dist/src/server/hive-team-guidance.js +17 -16
  23. package/dist/src/server/post-start-input-writer.js +2 -2
  24. package/dist/src/server/preset-launch-support.js +2 -1
  25. package/dist/src/server/recovery-summary.d.ts +5 -6
  26. package/dist/src/server/recovery-summary.js +3 -2
  27. package/dist/src/server/report-outbox-store.d.ts +36 -0
  28. package/dist/src/server/report-outbox-store.js +33 -0
  29. package/dist/src/server/restart-policy-support.d.ts +4 -5
  30. package/dist/src/server/restart-policy.d.ts +5 -1
  31. package/dist/src/server/restart-policy.js +51 -33
  32. package/dist/src/server/routes-settings.js +3 -3
  33. package/dist/src/server/routes-tasks.js +23 -0
  34. package/dist/src/server/routes-workspaces.js +5 -0
  35. package/dist/src/server/runtime-restart-policy.d.ts +3 -3
  36. package/dist/src/server/runtime-restart-policy.js +2 -3
  37. package/dist/src/server/runtime-store-contract.d.ts +3 -0
  38. package/dist/src/server/runtime-store-helpers.d.ts +2 -0
  39. package/dist/src/server/runtime-store-helpers.js +14 -9
  40. package/dist/src/server/runtime-store-workflows.js +8 -0
  41. package/dist/src/server/runtime-store.js +1 -0
  42. package/dist/src/server/session-capture.d.ts +6 -0
  43. package/dist/src/server/session-capture.js +32 -0
  44. package/dist/src/server/sqlite-schema-v22.d.ts +2 -0
  45. package/dist/src/server/sqlite-schema-v22.js +27 -0
  46. package/dist/src/server/sqlite-schema.d.ts +1 -1
  47. package/dist/src/server/sqlite-schema.js +19 -1
  48. package/dist/src/server/task-deps.d.ts +32 -0
  49. package/dist/src/server/task-deps.js +40 -0
  50. package/dist/src/server/tasks-file-watcher.d.ts +6 -7
  51. package/dist/src/server/tasks-file-watcher.js +3 -2
  52. package/dist/src/server/tasks-file.d.ts +2 -1
  53. package/dist/src/server/tasks-file.js +3 -2
  54. package/dist/src/server/team-authz.d.ts +1 -1
  55. package/dist/src/server/team-authz.js +1 -0
  56. package/dist/src/server/team-operations.d.ts +7 -1
  57. package/dist/src/server/team-operations.js +81 -19
  58. package/dist/src/server/webhook-notifier.d.ts +34 -0
  59. package/dist/src/server/webhook-notifier.js +47 -0
  60. package/dist/src/server/workflow-cli-policy.d.ts +1 -1
  61. package/dist/src/server/workflow-cli-policy.js +1 -1
  62. package/dist/src/server/workflow-output-schema.d.ts +18 -0
  63. package/dist/src/server/workflow-output-schema.js +41 -0
  64. package/dist/src/server/workflow-runner.js +12 -2
  65. package/dist/src/shared/types.d.ts +2 -2
  66. package/package.json +1 -1
  67. package/web/dist/assets/{AddWorkerDialog-CcC-7kgG.js → AddWorkerDialog-BRUxpa3f.js} +2 -2
  68. package/web/dist/assets/{AddWorkspaceDialog-BDpOTfmt.js → AddWorkspaceDialog-D56x5JCb.js} +1 -1
  69. package/web/dist/assets/{FirstRunWizard-BYX_ocQn.js → FirstRunWizard-BFVaMIsE.js} +1 -1
  70. package/web/dist/assets/{MarketplaceDrawer-DUxSk7db.js → MarketplaceDrawer-DeEZ35dN.js} +1 -1
  71. package/web/dist/assets/{WhatsNewDialog-B_RlCXcV.js → WhatsNewDialog-CHkZeINH.js} +1 -1
  72. package/web/dist/assets/{WorkerModal-D9-7YfZZ.js → WorkerModal-BBCuMLIa.js} +1 -1
  73. package/web/dist/assets/{WorkspaceTaskDrawer-BCKoF7qc.js → WorkspaceTaskDrawer-CpZHAcj1.js} +1 -1
  74. package/web/dist/assets/WorkspaceTerminalPanels-7If2mDyp.js +1 -0
  75. package/web/dist/assets/index-5zh61jMg.css +1 -0
  76. package/web/dist/assets/index-CxNL0O-C.js +73 -0
  77. package/web/dist/cli-icons/hermes.png +0 -0
  78. package/web/dist/index.html +2 -2
  79. package/web/dist/sw.js +1 -1
  80. package/web/dist/assets/WorkspaceTerminalPanels-Dq8y91t2.js +0 -1
  81. package/web/dist/assets/index-BiOvKIVw.css +0 -1
  82. package/web/dist/assets/index-DMRUklT3.js +0 -73
package/CHANGELOG.md CHANGED
@@ -2,6 +2,45 @@
2
2
 
3
3
  All notable user-facing changes will be documented in this file.
4
4
 
5
+ ## 1.7.0 - 2026-06-05
6
+
7
+ Hermes joins the roster.
8
+
9
+ - Adds Hermes as a fifth built-in CLI agent preset alongside Claude Code,
10
+ Codex, OpenCode, and Gemini: available as an Orchestrator or Worker, in
11
+ `team spawn --cli hermes`, and in the workflow CLI allowlist.
12
+ - Hermes runs YOLO via `--yolo` and resumes sessions via
13
+ `--resume <session_id>`; crash recovery (Layer A) captures its session id
14
+ from the CLI's own startup output through a new stdout-based capture
15
+ source.
16
+ - Existing installs pick the preset up automatically via a database
17
+ migration — no manual setup beyond having `hermes` on your PATH.
18
+
19
+ ## 1.6.0 - 2026-06-02
20
+
21
+ Orchestrator controls, worker visibility, and protocol-trust fixes.
22
+
23
+ - Adds a Stop control to the running Orchestrator pane so a runaway Orchestrator
24
+ can be halted from the UI (the default is auto-approve, so this is the only
25
+ in-UI kill switch).
26
+ - Surfaces per-worker queue depth and a latest-activity line on worker cards,
27
+ with a legend on the working badge clarifying that Hive does not auto-detect
28
+ stalls — the terminal is the source of truth.
29
+ - Redelivers worker reports the Orchestrator missed: a report is no longer
30
+ silently lost when the Orchestrator is down or restarting; it is queued and
31
+ redelivered on the next report or `team list`.
32
+ - Stops injecting the crash-recovery handover after a deliberate Stop and
33
+ Restart, so the Orchestrator is not handed stale open tasks it was meant to
34
+ drop.
35
+ - Adds an outbound completion webhook setting: Hive POSTs a small JSON payload
36
+ to a URL you choose when a worker reports or a workflow finishes — wire it to
37
+ Slack, ntfy, Feishu, and the like.
38
+ - Adds opt-in structured output to workflow `agent()` via `outputSchema`, so
39
+ fan-out/verify scripts receive a parsed object instead of parsing free text.
40
+ - Adds `team next`: tasks in `.hive/tasks.md` can carry an optional
41
+ `[needs: #2]` dependency, and `team next` returns the tasks that are unblocked
42
+ now.
43
+
5
44
  ## 1.5.0 - 2026-05-31
6
45
 
7
46
  Workflow runtime, experimental team automation, and Codex reliability.
package/README.en.md CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  **Hive is a browser-native workbench where a team of agents works together — one orchestrates, the rest execute, all on your laptop.** The orchestrator
12
- is a real `claude` / `codex` / `opencode` / `gemini` process — not you, and
12
+ is a real `claude` / `codex` / `opencode` / `gemini` / `hermes` process — not you, and
13
13
  not a script — and so are the workers it dispatches to. Every agent runs as
14
14
  a real PTY on your machine, talks through a small `team` protocol that Hive
15
15
  injects into each agent's shell, and shares a markdown task graph at
@@ -123,6 +123,18 @@ First-run flow:
123
123
  5. Ask the Orchestrator to delegate work. It sends tasks with
124
124
  `team send <worker-name> "<task>"`; workers report back with `team report`.
125
125
 
126
+ If you want the Orchestrator to size the team itself, leave **Auto-staff**
127
+ enabled (it is on by default). It can `team spawn` the right temporary mix of
128
+ coders, testers, and reviewers for the task, then Hive dismisses those
129
+ temporary workers when their work is done.
130
+
131
+ For stronger automation, enable the experimental **Workflows** toggle in
132
+ settings. The Orchestrator can then author and run multi-agent workflows that
133
+ fan out across implementation, review, testing, or other stages. The topbar
134
+ **Workflows** panel shows runs, phase results, logs, schedules, and stop
135
+ controls. The same panel also lets you choose which CLI workflow-created
136
+ agents use by default and which CLIs they are allowed to use.
137
+
126
138
  ## How It Works
127
139
 
128
140
  ```text
@@ -164,6 +176,7 @@ Three details matter:
164
176
  | Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
165
177
  | OpenCode | `opencode` | Config-driven in `~/.config/opencode/opencode.json` | `--session <session_id>` |
166
178
  | Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
179
+ | Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
167
180
  | Custom | Any executable | User configured | User configured |
168
181
 
169
182
  Hive does not install these CLIs for you. Install and authenticate them in the
@@ -175,8 +188,17 @@ same shell environment you use to start Hive.
175
188
  - Orchestrator and worker terminals backed by real PTYs.
176
189
  - Add Worker flow with role presets for coder, reviewer, tester, and fully
177
190
  custom prompts and commands — wire any CLI agent into the role you need.
191
+ - Auto-staff (experimental, on by default): the Orchestrator can create
192
+ temporary coders, testers, and reviewers based on the task, and Hive cleans
193
+ them up after their dispatch reports back.
194
+ - Workflows (experimental, off by default): the Orchestrator can run
195
+ multi-stage, multi-agent workflows while Hive shows runs, logs, results,
196
+ schedules, and stop controls in the Workflows panel.
197
+ - Workflow CLI policy: choose the default CLI for workflow-created agents and
198
+ restrict which CLIs workflow scripts may launch.
178
199
  - `.hive/tasks.md` editor with external-file conflict handling.
179
200
  - Background PTY preservation and best-effort native session resume.
201
+ - A What's New dialog after upgrades with curated release highlights.
180
202
  - Local SQLite metadata under `~/.config/hive` by default, or `$HIVE_DATA_DIR`
181
203
  when set.
182
204
 
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  <img src="./assets/hive-hero.png" alt="Hive 本机多 agent 协作工作台" />
9
9
  </p>
10
10
 
11
- **Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `claude` / `codex` / `opencode` / `gemini` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
11
+ **Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `claude` / `codex` / `opencode` / `gemini` / `hermes` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
12
12
 
13
13
  写代码、做调研、起草文档、做翻译——凡是能拆给一群人协作的脑力活,都可以让一群 Agent 合伙干。
14
14
 
@@ -84,6 +84,10 @@ PWA 只是 UI 壳,Hive 后端仍需要在终端里跑着。如果启动 PWA
84
84
  4. 在 Team Members 面板里添加 Worker。
85
85
  5. 跟 Orchestrator 说一声让它派活,它会用 `team send <worker-name> "<task>"` 发任务,Worker 完事后用 `team report` 回报。
86
86
 
87
+ 想让 Orchestrator 自己决定团队规模,可以保留 **自动组队** 开关开启(默认开启):它会按任务需要临时 `team spawn` 合适数量的 coder / tester / reviewer,任务结束后自动收回临时成员。
88
+
89
+ 想试更强的自动化,可以在右上角设置里开启实验性的 **Workflow** 开关。开启后,Orchestrator 可以编写并运行多 agent workflow,把一个目标拆成 fan-out / review / test 等阶段;顶部的 **Workflows** 面板会显示运行记录、阶段结果、定时任务和停止按钮。Workflow 创建的新 agent 默认使用哪种 CLI、允许使用哪些 CLI,也可以在 Workflows 面板里配置。
90
+
87
91
  ## 工作方式
88
92
 
89
93
  ```text
@@ -122,6 +126,7 @@ Workspace 任务图:
122
126
  | Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
123
127
  | OpenCode | `opencode` | 由 `~/.config/opencode/opencode.json` 配置 | `--session <session_id>` |
124
128
  | Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
129
+ | Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
125
130
  | 自定义 | 任意可执行文件 | 自己配 | 自己配 |
126
131
 
127
132
  Hive 不替你安装这些 CLI。请在启动 Hive 的同一个 shell 环境里先装好、登录好。
@@ -131,8 +136,12 @@ Hive 不替你安装这些 CLI。请在启动 Hive 的同一个 shell 环境里
131
136
  - Workspace 侧边栏,方便在多个本机项目之间切换。
132
137
  - Orchestrator 和 Worker 终端都是真实 PTY 支撑的。
133
138
  - Add Worker 预置 coder / reviewer / tester 等角色模板,也支持完全自定义 prompt 与命令——把任何 CLI agent 编排成你需要的角色。
139
+ - 自动组队(实验性,默认开启):Orchestrator 可以根据任务动态创建临时 coder / tester / reviewer,完成后自动回收。
140
+ - Workflows(实验性,默认关闭):Orchestrator 可以运行多阶段、多 agent 的 workflow,Hive 在 Workflows 面板里展示运行、日志、结果、定时任务和停止控制。
141
+ - Workflow CLI 策略:为 workflow 创建的 agent 选择默认 CLI,并限制允许使用的 CLI,避免脚本误启未配置的 agent。
134
142
  - `.hive/tasks.md` 编辑器,带外部文件冲突处理。
135
143
  - PTY 后台保留 + 尽力使用各 CLI 原生 session 恢复。
144
+ - 升级后的 What's New 弹窗,用简短 release highlights 告诉你新版改了什么。
136
145
  - 元数据存在本机 SQLite,默认在 `~/.config/hive`,或者通过 `$HIVE_DATA_DIR` 指定。
137
146
 
138
147
  Hive **不**提供 sandbox 隔离、多用户认证、云端托管,也不自带任何 agent 模型。它只负责调度你已经在用的本机 CLI。
@@ -9,8 +9,9 @@ const REQUIRED_ENV_KEYS = [
9
9
  const TEAM_USAGE = [
10
10
  'Usage:',
11
11
  ' team list',
12
+ ' team next (tasks in .hive/tasks.md that are unblocked now — those whose [needs: #n] deps are all done)',
12
13
  ' team send <worker-name> "<task>"',
13
- ' team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini>] [--ephemeral]',
14
+ ' team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini|hermes>] [--ephemeral]',
14
15
  ' team dismiss <worker-name>',
15
16
  " team workflow run --stdin [--args '<JSON>'] (script from stdin — for multi-line scripts)",
16
17
  ' team workflow run --inline "<source>" [--args \'<JSON>\']',
@@ -243,6 +244,22 @@ export const runTeamCommand = async (argv) => {
243
244
  console.log(JSON.stringify(await response.json()));
244
245
  return;
245
246
  }
247
+ if (command === 'next') {
248
+ const env = getHiveEnv();
249
+ const baseUrl = getBaseUrl(env);
250
+ const response = await fetchRuntime(baseUrl, `/api/workspaces/${env.HIVE_PROJECT_ID}/tasks/next`, {
251
+ method: 'GET',
252
+ headers: {
253
+ 'x-hive-agent-id': env.HIVE_AGENT_ID,
254
+ 'x-hive-agent-token': env.HIVE_AGENT_TOKEN,
255
+ },
256
+ });
257
+ if (!response.ok) {
258
+ await throwHttpError(response);
259
+ }
260
+ console.log(JSON.stringify(await response.json()));
261
+ return;
262
+ }
246
263
  if (command === 'send') {
247
264
  const [workerName, ...taskParts] = args;
248
265
  const task = taskParts.join(' ').trim();
@@ -274,7 +291,7 @@ export const runTeamCommand = async (argv) => {
274
291
  if (command === 'spawn') {
275
292
  const role = args[0];
276
293
  if (!role || role.startsWith('--')) {
277
- throw new Error('Usage: team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini>] [--ephemeral]\n' +
294
+ throw new Error('Usage: team spawn <role> [--name <name>] [--cli <claude|codex|opencode|gemini|hermes>] [--ephemeral]\n' +
278
295
  ' Default: persistent member (lives until you `team dismiss` it).\n' +
279
296
  ' --ephemeral: auto-dismiss after the next dispatch report (one-shot worker).');
280
297
  }
@@ -60,6 +60,10 @@ export declare const buildAgentRunBootstrap: (workspace: WorkspaceSummary, agent
60
60
  };
61
61
  knownSessionIds: Set<string>;
62
62
  root: string;
63
+ } | {
64
+ knownSessionIds: Set<string>;
65
+ env?: never;
66
+ root?: never;
63
67
  } | undefined;
64
68
  startConfig: AgentLaunchConfigInput;
65
69
  startEnv: {
@@ -69,8 +73,9 @@ export declare const buildAgentRunBootstrap: (workspace: WorkspaceSummary, agent
69
73
  HIVE_AGENT_TOKEN: string;
70
74
  };
71
75
  };
72
- export declare const startAgentRunCapture: ({ agentId, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }: {
76
+ export declare const startAgentRunCapture: ({ agentId, getRunOutput, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }: {
73
77
  agentId: string;
78
+ getRunOutput?: () => string | null;
74
79
  sessionCaptureSnapshot: SessionCaptureSnapshot | undefined;
75
80
  sessionStore: AgentSessionStorePort;
76
81
  startConfig: AgentLaunchConfigInput;
@@ -84,10 +84,13 @@ export const buildAgentRunBootstrap = (workspace, agentId, config, sessionStore,
84
84
  },
85
85
  };
86
86
  };
87
- export const startAgentRunCapture = ({ agentId, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }) => {
87
+ export const startAgentRunCapture = ({ agentId, getRunOutput, sessionCaptureSnapshot, sessionStore, startConfig, workspace, }) => {
88
88
  if (!sessionCaptureSnapshot || !startConfig.sessionIdCapture)
89
89
  return;
90
- void captureSessionIdForCapture(workspace.path, startConfig.sessionIdCapture, sessionCaptureSnapshot, (sessionId) => {
90
+ const captureSnapshot = startConfig.sessionIdCapture.source === 'stdout_regex' && getRunOutput
91
+ ? { ...sessionCaptureSnapshot, getOutput: getRunOutput }
92
+ : sessionCaptureSnapshot;
93
+ void captureSessionIdForCapture(workspace.path, startConfig.sessionIdCapture, captureSnapshot, (sessionId) => {
91
94
  sessionStore.setLastSessionId(workspace.id, agentId, sessionId);
92
95
  }, SESSION_CAPTURE_TIMEOUT_MS);
93
96
  };
@@ -6,6 +6,7 @@ import type { AgentSessionStorePort } from './agent-runtime-ports.js';
6
6
  import type { LiveAgentRun } from './agent-runtime-types.js';
7
7
  import type { AgentTokenRegistry } from './agent-tokens.js';
8
8
  import type { CommandPresetRecord } from './command-preset-store.js';
9
+ import { type FeatureFlags } from './feature-flags.js';
9
10
  import type { LiveRunRegistry } from './live-run-registry.js';
10
11
  import type { RestartPolicy } from './restart-policy.js';
11
12
  interface AgentRunStarterInput {
@@ -18,12 +19,10 @@ interface AgentRunStarterInput {
18
19
  getCommandPreset: (id: string) => CommandPresetRecord | undefined;
19
20
  getAgent: ((workspaceId: string, agentId: string) => AgentSummary | undefined) | undefined;
20
21
  restartPolicy: RestartPolicy;
21
- /** Experimental workflow gate gates the `team workflow` line + the
22
- * workflow-authoring rule in the orchestrator's startup prompt. */
23
- getWorkflowsEnabled?: () => boolean;
24
- /** Experimental auto-staff gate (default on) gates the team-sizing rule
25
- * in the orchestrator's startup prompt. */
26
- getAutostaffEnabled?: () => boolean;
22
+ /** Resolves the live experimental flags for the orchestrator's startup
23
+ * prompt (`workflowsEnabled` gates the `team workflow` line + authoring
24
+ * rule; `autostaffEnabled` gates the team-sizing rule). */
25
+ getFlags?: () => FeatureFlags;
27
26
  }
28
- export declare const createAgentRunStarter: ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, getWorkflowsEnabled, getAutostaffEnabled, }: AgentRunStarterInput) => (workspace: WorkspaceSummary, agentId: string, config: AgentLaunchConfigInput, hivePort: string) => Promise<LiveAgentRun>;
27
+ export declare const createAgentRunStarter: ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, getFlags, }: AgentRunStarterInput) => (workspace: WorkspaceSummary, agentId: string, config: AgentLaunchConfigInput, hivePort: string) => Promise<LiveAgentRun>;
29
28
  export {};
@@ -1,8 +1,9 @@
1
1
  import { buildAgentRunBootstrap, startAgentRunCapture } from './agent-run-bootstrap.js';
2
2
  import { handleAgentRunExit } from './agent-run-exit-handler.js';
3
3
  import { buildAgentStartupInstructions } from './agent-startup-instructions.js';
4
+ import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
4
5
  import { createPostStartInputWriter, isInteractiveAgentCommand } from './post-start-input-writer.js';
5
- export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, getWorkflowsEnabled, getAutostaffEnabled, }) => async (workspace, agentId, config, hivePort) => {
6
+ export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, getFlags, }) => async (workspace, agentId, config, hivePort) => {
6
7
  if (!agentManager)
7
8
  throw new Error('Agent manager is required to start agents');
8
9
  const agent = getAgent?.(workspace.id, agentId);
@@ -84,7 +85,21 @@ export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, sto
84
85
  registry.clearPendingExitCode(run.runId);
85
86
  return liveRun;
86
87
  }
87
- startAgentRunCapture({ agentId, sessionCaptureSnapshot, sessionStore, startConfig, workspace });
88
+ startAgentRunCapture({
89
+ agentId,
90
+ getRunOutput: () => {
91
+ try {
92
+ return agentManager.getRun(run.runId).output;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ },
98
+ sessionCaptureSnapshot,
99
+ sessionStore,
100
+ startConfig,
101
+ workspace,
102
+ });
88
103
  const postStartWriter = createPostStartInputWriter(agentManager, startConfig.interactiveCommand ?? startConfig.command);
89
104
  queueMicrotask(() => {
90
105
  try {
@@ -102,8 +117,7 @@ export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, sto
102
117
  void postStartWriter(run.runId, buildAgentStartupInstructions({
103
118
  agent,
104
119
  workspace,
105
- workflowsEnabled: getWorkflowsEnabled?.() ?? false,
106
- autostaffEnabled: getAutostaffEnabled?.() ?? false,
120
+ flags: getFlags?.() ?? FEATURE_FLAGS_ALL_OFF,
107
121
  })).catch(() => {
108
122
  // The agent may have exited before post-start guidance could be written.
109
123
  });
@@ -34,5 +34,15 @@ export interface AgentRuntime {
34
34
  }) => void;
35
35
  writeUserInputPrompt: (workspaceId: string, text: string) => void;
36
36
  writeSystemMessageToAgent: (workspaceId: string, agentId: string, text: string) => void;
37
+ /** Awaitable report delivery — rejects if the orchestrator PTY write fails,
38
+ * so the caller can persist the report to the redelivery outbox. */
39
+ deliverReportToOrchestrator: (workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
40
+ requireActiveRun?: boolean;
41
+ }) => Promise<void>;
42
+ /** Awaitable opaque delivery — used to drain the report outbox so an entry
43
+ * is marked delivered only after the PTY write resolves. */
44
+ deliverSystemMessageToAgent: (workspaceId: string, agentId: string, text: string, input?: {
45
+ requireActiveRun?: boolean;
46
+ }) => Promise<void>;
37
47
  }
38
48
  export type { StartAgentOptions };
@@ -1,4 +1,4 @@
1
1
  import type { AgentManager } from './agent-manager.js';
2
2
  import type { LiveAgentRun } from './agent-runtime-types.js';
3
3
  import type { LiveRunRegistry } from './live-run-registry.js';
4
- export declare const stopLiveRun: (agentManager: AgentManager | undefined, registry: LiveRunRegistry, syncRun: (run: LiveAgentRun) => LiveAgentRun, runId: string) => void;
4
+ export declare const stopLiveRun: (agentManager: AgentManager | undefined, registry: LiveRunRegistry, syncRun: (run: LiveAgentRun) => LiveAgentRun, runId: string, onUserStop?: (runId: string) => void) => void;
@@ -1,4 +1,4 @@
1
- export const stopLiveRun = (agentManager, registry, syncRun, runId) => {
1
+ export const stopLiveRun = (agentManager, registry, syncRun, runId, onUserStop) => {
2
2
  if (!agentManager) {
3
3
  throw new Error('Agent manager is required to stop agents');
4
4
  }
@@ -12,5 +12,8 @@ export const stopLiveRun = (agentManager, registry, syncRun, runId) => {
12
12
  else if (['error', 'exited'].includes(agentManager.getRun(runId).status)) {
13
13
  return;
14
14
  }
15
+ // Reaching here means the run was genuinely live and we are about to kill it
16
+ // at the user's request — distinct from a crash that already ended the run.
17
+ onUserStop?.(runId);
15
18
  agentManager.stopRun(runId);
16
19
  };
@@ -3,6 +3,7 @@ import type { AgentManager } from './agent-manager.js';
3
3
  import type { AgentRuntime } from './agent-runtime-contract.js';
4
4
  import type { AgentRunStorePort, AgentSessionStorePort } from './agent-runtime-ports.js';
5
5
  import type { CommandPresetRecord } from './command-preset-store.js';
6
+ import type { FeatureFlags } from './feature-flags.js';
6
7
  import { type RestartPolicy } from './restart-policy.js';
7
- export declare const createAgentRuntime: (agentManager: AgentManager | undefined, agentRunStore: AgentRunStorePort, sessionStore: AgentSessionStorePort, getCommandPreset: (id: string) => CommandPresetRecord | undefined, onAgentExit: (workspaceId: string, agentId: string) => void, restartPolicy?: RestartPolicy, getAgent?: (workspaceId: string, agentId: string) => AgentSummary | undefined, getWorkflowsEnabled?: () => boolean, getAutostaffEnabled?: () => boolean) => AgentRuntime;
8
+ export declare const createAgentRuntime: (agentManager: AgentManager | undefined, agentRunStore: AgentRunStorePort, sessionStore: AgentSessionStorePort, getCommandPreset: (id: string) => CommandPresetRecord | undefined, onAgentExit: (workspaceId: string, agentId: string) => void, restartPolicy?: RestartPolicy, getAgent?: (workspaceId: string, agentId: string) => AgentSummary | undefined, getFlags?: () => FeatureFlags) => AgentRuntime;
8
9
  export type { AgentRuntime };
@@ -10,7 +10,7 @@ import { createAgentStdinDispatcher } from './agent-stdin-dispatcher.js';
10
10
  import { createAgentTokenRegistry } from './agent-tokens.js';
11
11
  import { createLiveRunRegistry } from './live-run-registry.js';
12
12
  import { createNoopRestartPolicy } from './restart-policy.js';
13
- export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, getCommandPreset, onAgentExit, restartPolicy = createNoopRestartPolicy(), getAgent, getWorkflowsEnabled, getAutostaffEnabled) => {
13
+ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, getCommandPreset, onAgentExit, restartPolicy = createNoopRestartPolicy(), getAgent, getFlags) => {
14
14
  const registry = createLiveRunRegistry();
15
15
  const launchCache = createAgentLaunchCache(agentRunStore);
16
16
  const tokenRegistry = createAgentTokenRegistry();
@@ -29,7 +29,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
29
29
  getWorkspaceId: launchCache.getWorkspaceId,
30
30
  registry,
31
31
  syncRun,
32
- ...(getWorkflowsEnabled ? { getWorkflowsEnabled } : {}),
32
+ ...(getFlags ? { getFlags } : {}),
33
33
  });
34
34
  const startLiveRun = createAgentRunStarter({
35
35
  agentManager,
@@ -41,8 +41,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
41
41
  getCommandPreset,
42
42
  getAgent,
43
43
  restartPolicy,
44
- ...(getWorkflowsEnabled ? { getWorkflowsEnabled } : {}),
45
- ...(getAutostaffEnabled ? { getAutostaffEnabled } : {}),
44
+ ...(getFlags ? { getFlags } : {}),
46
45
  });
47
46
  return {
48
47
  async close() {
@@ -106,7 +105,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
106
105
  return startPromise;
107
106
  },
108
107
  stopAgentRun(runId) {
109
- stopLiveRun(agentManager, registry, syncRun, runId);
108
+ stopLiveRun(agentManager, registry, syncRun, runId, (stoppedRunId) => restartPolicy.markUserStopped(stoppedRunId));
110
109
  },
111
110
  validateAgentToken: tokenRegistry.validate,
112
111
  writeReportPrompt(workspaceId, workerName, _workerId, text, artifacts, input = {}) {
@@ -127,5 +126,11 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
127
126
  writeSystemMessageToAgent(workspaceId, agentId, text) {
128
127
  stdinDispatcher.writeSystemMessageToAgent(workspaceId, agentId, text);
129
128
  },
129
+ deliverReportToOrchestrator(workspaceId, workerName, text, artifacts, input = {}) {
130
+ return stdinDispatcher.deliverReportToOrchestrator(workspaceId, workerName, text, artifacts, input);
131
+ },
132
+ deliverSystemMessageToAgent(workspaceId, agentId, text, input = {}) {
133
+ return stdinDispatcher.deliverSystemMessageToAgent(workspaceId, agentId, text, input);
134
+ },
130
135
  };
131
136
  };
@@ -1,4 +1,5 @@
1
1
  import type { AgentSummary, WorkspaceSummary } from '../shared/types.js';
2
+ import { type FeatureFlags } from './feature-flags.js';
2
3
  export declare const buildAgentSessionBindingMarker: ({ agent, workspace, }: {
3
4
  agent: AgentSummary;
4
5
  workspace: WorkspaceSummary;
@@ -7,14 +8,12 @@ export declare const buildAgentLegacyIdentityMarker: ({ agent, workspace, }: {
7
8
  agent: AgentSummary;
8
9
  workspace: WorkspaceSummary;
9
10
  }) => string;
10
- export declare const buildAgentStartupInstructions: ({ agent, workspace, workflowsEnabled, autostaffEnabled, }: {
11
+ export declare const buildAgentStartupInstructions: ({ agent, workspace, flags, }: {
11
12
  agent: AgentSummary;
12
13
  workspace: WorkspaceSummary;
13
- /** Experimental workflow gate. When off, the startup prompt omits the
14
- * `team workflow` command + the workflow-authoring rule so a fresh
15
- * orchestrator isn't told to run a command the runtime rejects. */
16
- workflowsEnabled?: boolean;
17
- /** Experimental auto-staff gate (default on). When on, the orchestrator is
18
- * told it may size the team to the task up front. */
19
- autostaffEnabled?: boolean;
14
+ /** Live experimental flags. `workflowsEnabled` gates the `team workflow`
15
+ * command line + the workflow-authoring rule (so a fresh orchestrator isn't
16
+ * told to run a command the runtime rejects); `autostaffEnabled` gates the
17
+ * team-sizing rule. Omitted → all off. */
18
+ flags?: FeatureFlags;
20
19
  }) => string;
@@ -1,8 +1,10 @@
1
+ import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
1
2
  import { getHiveTeamRules } from './hive-team-guidance.js';
2
3
  import { TASKS_RELATIVE_PATH } from './tasks-file.js';
3
4
  export const buildAgentSessionBindingMarker = ({ agent, workspace, }) => `Hive session binding: workspace_id=${workspace.id}; agent_id=${agent.id}`;
4
5
  export const buildAgentLegacyIdentityMarker = ({ agent, workspace, }) => `You are ${agent.name} (${agent.role}) in workspace ${workspace.name}.`;
5
- export const buildAgentStartupInstructions = ({ agent, workspace, workflowsEnabled = false, autostaffEnabled = false, }) => {
6
+ export const buildAgentStartupInstructions = ({ agent, workspace, flags = FEATURE_FLAGS_ALL_OFF, }) => {
7
+ const { workflowsEnabled } = flags;
6
8
  const lines = [
7
9
  '<hive-message kind="startup">',
8
10
  '',
@@ -17,14 +19,14 @@ export const buildAgentStartupInstructions = ({ agent, workspace, workflowsEnabl
17
19
  '',
18
20
  ];
19
21
  if (agent.role === 'orchestrator') {
20
- lines.push('Your responsibilities:', '- Respond to the user directly; clarify the goal and break it into dispatchable tasks', `- Maintain ${TASKS_RELATIVE_PATH}`, '- Dispatch by worker name and drive the next step from each report', '', 'Available team commands:', '- team list', '- team send "<worker-name>" "<task>"', '- team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini] [--ephemeral]', '- team cancel --dispatch <id> "<reason>"', ...(workflowsEnabled
22
+ lines.push('Your responsibilities:', '- Respond to the user directly; clarify the goal and break it into dispatchable tasks', `- Maintain ${TASKS_RELATIVE_PATH}`, '- Dispatch by worker name and drive the next step from each report', '', 'Available team commands:', '- team list', '- team send "<worker-name>" "<task>"', '- team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini|hermes] [--ephemeral]', '- team cancel --dispatch <id> "<reason>"', ...(workflowsEnabled
21
23
  ? [
22
24
  '- team workflow run --stdin (fan-out / staged work — see .hive/PROTOCOL.md for the DSL)',
23
25
  ]
24
- : []), '', 'Always dispatch by worker name, never by worker id.', 'Always cancel an open dispatch by its dispatch id.', '', 'Hive worker dispatch rules:', ...getHiveTeamRules(agent, workflowsEnabled, autostaffEnabled));
26
+ : []), '', 'Always dispatch by worker name, never by worker id.', 'Always cancel an open dispatch by its dispatch id.', '', 'Hive worker dispatch rules:', ...getHiveTeamRules(agent, flags));
25
27
  }
26
28
  else {
27
- lines.push('Available team commands:', '- team report "<result>" [--dispatch <id>] [--artifact <path>] report done / failed / blocked', '- team report --stdin [--dispatch <id>] [--artifact <path>] same, body read from stdin (multi-line / quotes / special chars)', '- team status "<state>" [--artifact <path>] mid-task progress / standby / connected status', '- team status --stdin [--artifact <path>] same, body read from stdin', '- team list list the workspace workers (with status)', '- team --help command syntax only; NOT a way to report', '', 'Syntax notes:', '- The body is the first positional argument; flag order is free: `team report "result" --dispatch X` and `team report --dispatch X "result"` are both valid.', "- Long bodies (multi-line / quotes / shell metacharacters) always go through `--stdin`, piped in via your shell (POSIX: a quoted heredoc `<<'EOF' … EOF` to stop $var / backtick expansion; Windows cmd: `type body.txt |` or `< body.txt`). `--stdin` only reads from stdin and relies on no shell syntax of its own.", '- On error the CLI also prints USAGE — fix the arguments against it.', '', 'When a task is done you MUST run `team report "<result>"`.', 'Failure, blocked, or partial completion are also reported with `team report "<current state and reason>"`.', 'When no task is in progress, report connection / standby / blocked state with `team status "<state>"`.', 'Do not call team send; workers cannot dispatch to each other.', '', 'Hive worker boundaries:', ...getHiveTeamRules(agent, workflowsEnabled, autostaffEnabled));
29
+ lines.push('Available team commands:', '- team report "<result>" [--dispatch <id>] [--artifact <path>] report done / failed / blocked', '- team report --stdin [--dispatch <id>] [--artifact <path>] same, body read from stdin (multi-line / quotes / special chars)', '- team status "<state>" [--artifact <path>] mid-task progress / standby / connected status', '- team status --stdin [--artifact <path>] same, body read from stdin', '- team list list the workspace workers (with status)', '- team --help command syntax only; NOT a way to report', '', 'Syntax notes:', '- The body is the first positional argument; flag order is free: `team report "result" --dispatch X` and `team report --dispatch X "result"` are both valid.', "- Long bodies (multi-line / quotes / shell metacharacters) always go through `--stdin`, piped in via your shell (POSIX: a quoted heredoc `<<'EOF' … EOF` to stop $var / backtick expansion; Windows cmd: `type body.txt |` or `< body.txt`). `--stdin` only reads from stdin and relies on no shell syntax of its own.", '- On error the CLI also prints USAGE — fix the arguments against it.', '', 'When a task is done you MUST run `team report "<result>"`.', 'Failure, blocked, or partial completion are also reported with `team report "<current state and reason>"`.', 'When no task is in progress, report connection / standby / blocked state with `team status "<state>"`.', 'Do not call team send; workers cannot dispatch to each other.', '', 'Hive worker boundaries:', ...getHiveTeamRules(agent, flags));
28
30
  }
29
31
  lines.push('', '</hive-message>', '');
30
32
  return lines.join('\n');
@@ -1,6 +1,7 @@
1
1
  import type { AgentManager } from './agent-manager.js';
2
2
  import type { AgentLaunchConfigInput } from './agent-run-store.js';
3
3
  import type { LiveAgentRun } from './agent-runtime-types.js';
4
+ import { type FeatureFlags } from './feature-flags.js';
4
5
  import type { LiveRunRegistry } from './live-run-registry.js';
5
6
  interface AgentStdinDispatcherInput {
6
7
  agentManager: AgentManager | undefined;
@@ -8,16 +9,17 @@ interface AgentStdinDispatcherInput {
8
9
  getWorkspaceId: (agentId: string) => string | undefined;
9
10
  registry: LiveRunRegistry;
10
11
  syncRun: (run: LiveAgentRun) => LiveAgentRun;
11
- /** Whether the experimental workflow feature is on. Controls whether the
12
- * orchestrator reminder tail mentions `team workflow`. Defaults to off. */
13
- getWorkflowsEnabled?: () => boolean;
12
+ /** Resolves the live experimental flags. The orchestrator reminder tail
13
+ * appended to every injected message reads `workflowsEnabled` from it.
14
+ * Optional; omitted all flags off. */
15
+ getFlags?: () => FeatureFlags;
14
16
  }
15
- export declare const buildOrchestratorReportPayload: (workerName: string, text: string, artifacts: string[], workflowsEnabled?: boolean) => string;
16
- export declare const buildOrchestratorStatusPayload: (workerName: string, text: string, artifacts: string[], workflowsEnabled?: boolean) => string;
17
- export declare const buildOrchestratorUserInputPayload: (text: string, workflowsEnabled?: boolean) => string;
17
+ export declare const buildOrchestratorReportPayload: (workerName: string, text: string, artifacts: string[], flags?: FeatureFlags) => string;
18
+ export declare const buildOrchestratorStatusPayload: (workerName: string, text: string, artifacts: string[], flags?: FeatureFlags) => string;
19
+ export declare const buildOrchestratorUserInputPayload: (text: string, flags?: FeatureFlags) => string;
18
20
  export declare const buildWorkerDispatchPayload: (fromAgentName: string, workerDescription: string, dispatchId: string, text: string) => string;
19
21
  export declare const buildWorkerCancelPayload: (dispatchId: string, reason: string) => string;
20
- export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getWorkflowsEnabled, }: AgentStdinDispatcherInput) => {
22
+ export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getFlags, }: AgentStdinDispatcherInput) => {
21
23
  writeReportPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
22
24
  requireActiveRun?: boolean;
23
25
  }): void;
@@ -33,5 +35,16 @@ export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfi
33
35
  * Used by the workflow runner to notify the triggering orchestrator
34
36
  * when a run finishes (mirrors Claude Code's <task-notification>). */
35
37
  writeSystemMessageToAgent(workspaceId: string, agentId: string, text: string): void;
38
+ /** Awaitable report delivery — same payload as writeReportPrompt but the
39
+ * promise is returned so the caller can persist the report to the
40
+ * redelivery outbox if the orchestrator PTY write rejects. */
41
+ deliverReportToOrchestrator(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
42
+ requireActiveRun?: boolean;
43
+ }): Promise<void>;
44
+ /** Awaitable opaque delivery — used to drain the report outbox so an entry
45
+ * is marked delivered only after the PTY write actually resolves. */
46
+ deliverSystemMessageToAgent(workspaceId: string, agentId: string, text: string, input?: {
47
+ requireActiveRun?: boolean;
48
+ }): Promise<void>;
36
49
  };
37
50
  export {};
@@ -1,21 +1,22 @@
1
+ import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
1
2
  import { buildOrchestratorReminderTail, buildWorkerReminderTail } from './hive-team-guidance.js';
2
3
  import { PtyInactiveError } from './http-errors.js';
3
4
  import { createPostStartInputWriter } from './post-start-input-writer.js';
4
- export const buildOrchestratorReportPayload = (workerName, text, artifacts, workflowsEnabled = false) => {
5
+ export const buildOrchestratorReportPayload = (workerName, text, artifacts, flags = FEATURE_FLAGS_ALL_OFF) => {
5
6
  const lines = [`<hive-message kind="report" from="@${workerName}">`, text];
6
7
  for (const artifact of artifacts)
7
8
  lines.push(`artifact: ${artifact}`);
8
- lines.push('</hive-message>', '', buildOrchestratorReminderTail(workflowsEnabled), '');
9
+ lines.push('</hive-message>', '', buildOrchestratorReminderTail(flags), '');
9
10
  return lines.join('\n');
10
11
  };
11
- export const buildOrchestratorStatusPayload = (workerName, text, artifacts, workflowsEnabled = false) => {
12
+ export const buildOrchestratorStatusPayload = (workerName, text, artifacts, flags = FEATURE_FLAGS_ALL_OFF) => {
12
13
  const lines = [`<hive-message kind="status" from="@${workerName}">`, text];
13
14
  for (const artifact of artifacts)
14
15
  lines.push(`artifact: ${artifact}`);
15
- lines.push('</hive-message>', '', buildOrchestratorReminderTail(workflowsEnabled), '');
16
+ lines.push('</hive-message>', '', buildOrchestratorReminderTail(flags), '');
16
17
  return lines.join('\n');
17
18
  };
18
- export const buildOrchestratorUserInputPayload = (text, workflowsEnabled = false) => [text, '', buildOrchestratorReminderTail(workflowsEnabled), ''].join('\n');
19
+ export const buildOrchestratorUserInputPayload = (text, flags = FEATURE_FLAGS_ALL_OFF) => [text, '', buildOrchestratorReminderTail(flags), ''].join('\n');
19
20
  export const buildWorkerDispatchPayload = (fromAgentName, workerDescription, dispatchId, text) => [
20
21
  `<hive-message kind="dispatch" from="@${fromAgentName}">`,
21
22
  '',
@@ -44,8 +45,8 @@ export const buildWorkerCancelPayload = (dispatchId, reason) => [
44
45
  '</hive-message>',
45
46
  '',
46
47
  ].join('\n');
47
- export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getWorkflowsEnabled, }) => {
48
- const workflowsEnabled = () => getWorkflowsEnabled?.() ?? false;
48
+ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getFlags, }) => {
49
+ const flags = () => getFlags?.() ?? FEATURE_FLAGS_ALL_OFF;
49
50
  const chains = new Map();
50
51
  const getChain = (agentId) => {
51
52
  let chain = chains.get(agentId);
@@ -156,10 +157,10 @@ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getW
156
157
  };
157
158
  return {
158
159
  writeReportPrompt(workspaceId, workerName, text, artifacts, input = {}) {
159
- swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts, workflowsEnabled()), input));
160
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts, flags()), input));
160
161
  },
161
162
  writeStatusPrompt(workspaceId, workerName, text, artifacts, input = {}) {
162
- swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts, workflowsEnabled()), input));
163
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts, flags()), input));
163
164
  },
164
165
  writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
165
166
  return writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
@@ -168,7 +169,7 @@ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getW
168
169
  swallowQueuedFailure(writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input));
169
170
  },
170
171
  writeUserInputPrompt(workspaceId, text) {
171
- swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text, workflowsEnabled())));
172
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text, flags())));
172
173
  },
173
174
  /** Generic: deliver an opaque text block to a specific agent's PTY.
174
175
  * Used by the workflow runner to notify the triggering orchestrator
@@ -176,5 +177,16 @@ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getW
176
177
  writeSystemMessageToAgent(workspaceId, agentId, text) {
177
178
  swallowQueuedFailure(writeToActiveAgentRun(workspaceId, agentId, text));
178
179
  },
180
+ /** Awaitable report delivery — same payload as writeReportPrompt but the
181
+ * promise is returned so the caller can persist the report to the
182
+ * redelivery outbox if the orchestrator PTY write rejects. */
183
+ deliverReportToOrchestrator(workspaceId, workerName, text, artifacts, input = {}) {
184
+ return writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts, flags()), input);
185
+ },
186
+ /** Awaitable opaque delivery — used to drain the report outbox so an entry
187
+ * is marked delivered only after the PTY write actually resolves. */
188
+ deliverSystemMessageToAgent(workspaceId, agentId, text, input = {}) {
189
+ return writeToActiveAgentRun(workspaceId, agentId, text, input);
190
+ },
179
191
  };
180
192
  };
@@ -2,6 +2,7 @@ import { CLAUDE_DEFAULT_YOLO_ARGS } from './claude-command-defaults.js';
2
2
  const CODEX_DEFAULT_YOLO_ARGS = ['--dangerously-bypass-approvals-and-sandbox'];
3
3
  const OPENCODE_DEFAULT_YOLO_ARGS = [];
4
4
  const GEMINI_DEFAULT_YOLO_ARGS = ['--yolo'];
5
+ const HERMES_DEFAULT_YOLO_ARGS = ['--yolo'];
5
6
  export const BUILTIN_COMMAND_PRESETS = [
6
7
  {
7
8
  command: 'claude',
@@ -47,5 +48,16 @@ export const BUILTIN_COMMAND_PRESETS = [
47
48
  },
48
49
  yoloArgsTemplate: GEMINI_DEFAULT_YOLO_ARGS,
49
50
  },
51
+ {
52
+ command: 'hermes',
53
+ displayName: 'Hermes',
54
+ id: 'hermes',
55
+ resumeArgsTemplate: '--resume {session_id}',
56
+ sessionIdCapture: {
57
+ pattern: String.raw `Session:\s*([A-Za-z0-9_-]+)`,
58
+ source: 'stdout_regex',
59
+ },
60
+ yoloArgsTemplate: HERMES_DEFAULT_YOLO_ARGS,
61
+ },
50
62
  ];
51
63
  export const getBuiltinCommandPreset = (id) => BUILTIN_COMMAND_PRESETS.find((preset) => preset.id === id);