@tt-a1i/hive 1.4.4 → 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 (180) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.en.md +21 -0
  3. package/README.md +16 -0
  4. package/assets/qq-group.jpg +0 -0
  5. package/dist/bin/team.cmd +1 -0
  6. package/dist/src/cli/hive-update.d.ts +45 -17
  7. package/dist/src/cli/hive-update.js +63 -25
  8. package/dist/src/cli/hive.d.ts +25 -0
  9. package/dist/src/cli/hive.js +41 -3
  10. package/dist/src/cli/team.d.ts +1 -0
  11. package/dist/src/cli/team.js +216 -3
  12. package/dist/src/server/agent-command-resolver.js +3 -19
  13. package/dist/src/server/agent-manager-support.d.ts +2 -2
  14. package/dist/src/server/agent-manager-support.js +98 -24
  15. package/dist/src/server/agent-run-starter.d.ts +6 -1
  16. package/dist/src/server/agent-run-starter.js +9 -2
  17. package/dist/src/server/agent-run-store.d.ts +1 -1
  18. package/dist/src/server/agent-runtime-close.d.ts +1 -0
  19. package/dist/src/server/agent-runtime-close.js +25 -1
  20. package/dist/src/server/agent-runtime-contract.d.ts +12 -1
  21. package/dist/src/server/agent-runtime-stop-run.d.ts +1 -1
  22. package/dist/src/server/agent-runtime-stop-run.js +4 -1
  23. package/dist/src/server/agent-runtime.d.ts +2 -1
  24. package/dist/src/server/agent-runtime.js +14 -3
  25. package/dist/src/server/agent-startup-instructions.d.ts +7 -1
  26. package/dist/src/server/agent-startup-instructions.js +17 -9
  27. package/dist/src/server/agent-stdin-dispatcher.d.ts +25 -5
  28. package/dist/src/server/agent-stdin-dispatcher.js +141 -40
  29. package/dist/src/server/cron-util.d.ts +7 -0
  30. package/dist/src/server/cron-util.js +19 -0
  31. package/dist/src/server/dispatch-ledger-store.d.ts +22 -0
  32. package/dist/src/server/dispatch-ledger-store.js +51 -3
  33. package/dist/src/server/env-sync-message.js +9 -9
  34. package/dist/src/server/feature-flags.d.ts +42 -0
  35. package/dist/src/server/feature-flags.js +24 -0
  36. package/dist/src/server/fs-pick-folder.js +4 -0
  37. package/dist/src/server/fs-sandbox.js +36 -7
  38. package/dist/src/server/hive-team-guidance.d.ts +12 -6
  39. package/dist/src/server/hive-team-guidance.js +253 -71
  40. package/dist/src/server/live-run-registry.d.ts +1 -0
  41. package/dist/src/server/live-run-registry.js +1 -1
  42. package/dist/src/server/open-target-commands.js +5 -6
  43. package/dist/src/server/orchestrator-autostart.d.ts +12 -0
  44. package/dist/src/server/orchestrator-autostart.js +15 -13
  45. package/dist/src/server/path-canonicalization.d.ts +3 -0
  46. package/dist/src/server/path-canonicalization.js +29 -0
  47. package/dist/src/server/platform-path.d.ts +3 -0
  48. package/dist/src/server/platform-path.js +13 -0
  49. package/dist/src/server/post-start-input-writer.d.ts +1 -1
  50. package/dist/src/server/post-start-input-writer.js +110 -13
  51. package/dist/src/server/preset-launch-support.d.ts +1 -1
  52. package/dist/src/server/preset-launch-support.js +33 -2
  53. package/dist/src/server/recovery-summary.d.ts +5 -1
  54. package/dist/src/server/recovery-summary.js +18 -17
  55. package/dist/src/server/report-outbox-store.d.ts +36 -0
  56. package/dist/src/server/report-outbox-store.js +33 -0
  57. package/dist/src/server/restart-policy-support.d.ts +5 -1
  58. package/dist/src/server/restart-policy-support.js +9 -1
  59. package/dist/src/server/restart-policy.d.ts +6 -2
  60. package/dist/src/server/restart-policy.js +51 -31
  61. package/dist/src/server/role-template-store.d.ts +1 -0
  62. package/dist/src/server/role-template-store.js +11 -1
  63. package/dist/src/server/route-types.d.ts +43 -0
  64. package/dist/src/server/routes-runtime.js +2 -1
  65. package/dist/src/server/routes-settings.js +76 -0
  66. package/dist/src/server/routes-tasks.js +23 -0
  67. package/dist/src/server/routes-team.js +211 -1
  68. package/dist/src/server/routes-workflow-schedules.d.ts +2 -0
  69. package/dist/src/server/routes-workflow-schedules.js +58 -0
  70. package/dist/src/server/routes-workflows.d.ts +2 -0
  71. package/dist/src/server/routes-workflows.js +83 -0
  72. package/dist/src/server/routes-workspaces.js +5 -0
  73. package/dist/src/server/routes.js +4 -0
  74. package/dist/src/server/runtime-restart-policy.d.ts +3 -1
  75. package/dist/src/server/runtime-restart-policy.js +2 -1
  76. package/dist/src/server/runtime-store-contract.d.ts +125 -0
  77. package/dist/src/server/runtime-store-contract.js +1 -0
  78. package/dist/src/server/runtime-store-helpers.d.ts +11 -0
  79. package/dist/src/server/runtime-store-helpers.js +106 -2
  80. package/dist/src/server/runtime-store-workflows.d.ts +6 -0
  81. package/dist/src/server/runtime-store-workflows.js +108 -0
  82. package/dist/src/server/runtime-store.d.ts +3 -72
  83. package/dist/src/server/runtime-store.js +71 -4
  84. package/dist/src/server/session-capture-codex.d.ts +3 -3
  85. package/dist/src/server/session-capture-codex.js +9 -7
  86. package/dist/src/server/session-capture-gemini.d.ts +1 -1
  87. package/dist/src/server/session-capture-gemini.js +6 -3
  88. package/dist/src/server/settings-store.d.ts +3 -0
  89. package/dist/src/server/settings-store.js +1 -0
  90. package/dist/src/server/sqlite-schema-v19.d.ts +2 -0
  91. package/dist/src/server/sqlite-schema-v19.js +17 -0
  92. package/dist/src/server/sqlite-schema-v20.d.ts +2 -0
  93. package/dist/src/server/sqlite-schema-v20.js +20 -0
  94. package/dist/src/server/sqlite-schema-v21.d.ts +2 -0
  95. package/dist/src/server/sqlite-schema-v21.js +20 -0
  96. package/dist/src/server/sqlite-schema.d.ts +1 -1
  97. package/dist/src/server/sqlite-schema.js +110 -1
  98. package/dist/src/server/system-message.d.ts +7 -0
  99. package/dist/src/server/system-message.js +8 -1
  100. package/dist/src/server/task-deps.d.ts +32 -0
  101. package/dist/src/server/task-deps.js +40 -0
  102. package/dist/src/server/tasks-file-watcher.d.ts +12 -1
  103. package/dist/src/server/tasks-file-watcher.js +128 -23
  104. package/dist/src/server/tasks-file.d.ts +3 -1
  105. package/dist/src/server/tasks-file.js +33 -9
  106. package/dist/src/server/tasks-websocket-server.js +13 -14
  107. package/dist/src/server/team-authz.d.ts +1 -1
  108. package/dist/src/server/team-authz.js +10 -1
  109. package/dist/src/server/team-autostaff.d.ts +16 -0
  110. package/dist/src/server/team-autostaff.js +16 -0
  111. package/dist/src/server/team-list-serializer.d.ts +1 -1
  112. package/dist/src/server/team-list-serializer.js +3 -1
  113. package/dist/src/server/team-operations.d.ts +21 -1
  114. package/dist/src/server/team-operations.js +183 -16
  115. package/dist/src/server/terminal-protocol.js +9 -3
  116. package/dist/src/server/terminal-stream-hub.js +16 -10
  117. package/dist/src/server/terminal-ws-server.js +10 -8
  118. package/dist/src/server/webhook-notifier.d.ts +34 -0
  119. package/dist/src/server/webhook-notifier.js +47 -0
  120. package/dist/src/server/websocket-upgrade-safety.d.ts +10 -0
  121. package/dist/src/server/websocket-upgrade-safety.js +35 -0
  122. package/dist/src/server/windows-command-line.d.ts +3 -0
  123. package/dist/src/server/windows-command-line.js +9 -0
  124. package/dist/src/server/windows-filename.d.ts +2 -0
  125. package/dist/src/server/windows-filename.js +33 -0
  126. package/dist/src/server/workflow-cli-policy.d.ts +60 -0
  127. package/dist/src/server/workflow-cli-policy.js +110 -0
  128. package/dist/src/server/workflow-dispatch-awaiter.d.ts +12 -0
  129. package/dist/src/server/workflow-dispatch-awaiter.js +80 -0
  130. package/dist/src/server/workflow-feature.d.ts +15 -0
  131. package/dist/src/server/workflow-feature.js +15 -0
  132. package/dist/src/server/workflow-http-serializers.d.ts +64 -0
  133. package/dist/src/server/workflow-http-serializers.js +58 -0
  134. package/dist/src/server/workflow-output-schema.d.ts +18 -0
  135. package/dist/src/server/workflow-output-schema.js +41 -0
  136. package/dist/src/server/workflow-run-log-store.d.ts +19 -0
  137. package/dist/src/server/workflow-run-log-store.js +45 -0
  138. package/dist/src/server/workflow-run-store.d.ts +50 -0
  139. package/dist/src/server/workflow-run-store.js +103 -0
  140. package/dist/src/server/workflow-runner.d.ts +147 -0
  141. package/dist/src/server/workflow-runner.js +411 -0
  142. package/dist/src/server/workflow-schedule-create.d.ts +14 -0
  143. package/dist/src/server/workflow-schedule-create.js +41 -0
  144. package/dist/src/server/workflow-schedule-store.d.ts +43 -0
  145. package/dist/src/server/workflow-schedule-store.js +112 -0
  146. package/dist/src/server/workflow-scheduler.d.ts +36 -0
  147. package/dist/src/server/workflow-scheduler.js +97 -0
  148. package/dist/src/server/workflow-script-loader.d.ts +34 -0
  149. package/dist/src/server/workflow-script-loader.js +106 -0
  150. package/dist/src/server/workspace-path-validation.js +16 -4
  151. package/dist/src/server/workspace-shell-runtime.d.ts +5 -0
  152. package/dist/src/server/workspace-shell-runtime.js +24 -2
  153. package/dist/src/server/workspace-store-contract.d.ts +4 -1
  154. package/dist/src/server/workspace-store-hydration.js +23 -7
  155. package/dist/src/server/workspace-store-mutations.js +2 -5
  156. package/dist/src/server/workspace-store-support.d.ts +4 -0
  157. package/dist/src/server/workspace-store-support.js +13 -1
  158. package/dist/src/server/workspace-store.js +38 -4
  159. package/dist/src/shared/types.d.ts +16 -1
  160. package/package.json +4 -2
  161. package/web/dist/assets/{AddWorkerDialog-DeZhTQLi.js → AddWorkerDialog-CGbaxu0T.js} +2 -2
  162. package/web/dist/assets/AddWorkspaceDialog-CNgExu6b.js +1 -0
  163. package/web/dist/assets/{FirstRunWizard-B5wLcat5.js → FirstRunWizard-DxGApUNc.js} +1 -1
  164. package/web/dist/assets/{MarketplaceDrawer-BC0eBOEW.js → MarketplaceDrawer-Bk6cpukn.js} +1 -1
  165. package/web/dist/assets/WhatsNewDialog-CSGzk-2U.js +1 -0
  166. package/web/dist/assets/WorkerModal-i2F3n3nZ.js +1 -0
  167. package/web/dist/assets/WorkspaceTaskDrawer-C_Ta_K13.js +1 -0
  168. package/web/dist/assets/WorkspaceTerminalPanels-VdDxtrQF.js +1 -0
  169. package/web/dist/assets/index-5zh61jMg.css +1 -0
  170. package/web/dist/assets/index-CAgGM6nb.js +75 -0
  171. package/web/dist/assets/path-join-7MR1s7b1.js +1 -0
  172. package/web/dist/index.html +2 -2
  173. package/web/dist/sw.js +1 -1
  174. package/web/dist/assets/AddWorkspaceDialog-DDpXNEKf.js +0 -1
  175. package/web/dist/assets/WorkerModal-BwMHq-Bi.js +0 -1
  176. package/web/dist/assets/WorkspaceTaskDrawer-CxvT4nqs.js +0 -1
  177. package/web/dist/assets/WorkspaceTerminalPanels-CvibsPSd.js +0 -1
  178. package/web/dist/assets/index-BEsTmfrO.css +0 -1
  179. package/web/dist/assets/index-Ddb7bDN5.js +0 -75
  180. package/web/dist/assets/path-join-S7qkXQtP.js +0 -1
@@ -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) => 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) => {
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,6 +29,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
29
29
  getWorkspaceId: launchCache.getWorkspaceId,
30
30
  registry,
31
31
  syncRun,
32
+ ...(getFlags ? { getFlags } : {}),
32
33
  });
33
34
  const startLiveRun = createAgentRunStarter({
34
35
  agentManager,
@@ -40,6 +41,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
40
41
  getCommandPreset,
41
42
  getAgent,
42
43
  restartPolicy,
44
+ ...(getFlags ? { getFlags } : {}),
43
45
  });
44
46
  return {
45
47
  async close() {
@@ -103,7 +105,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
103
105
  return startPromise;
104
106
  },
105
107
  stopAgentRun(runId) {
106
- stopLiveRun(agentManager, registry, syncRun, runId);
108
+ stopLiveRun(agentManager, registry, syncRun, runId, (stoppedRunId) => restartPolicy.markUserStopped(stoppedRunId));
107
109
  },
108
110
  validateAgentToken: tokenRegistry.validate,
109
111
  writeReportPrompt(workspaceId, workerName, _workerId, text, artifacts, input = {}) {
@@ -113,7 +115,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
113
115
  stdinDispatcher.writeStatusPrompt(workspaceId, workerName, text, artifacts, input);
114
116
  },
115
117
  writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
116
- stdinDispatcher.writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text);
118
+ return stdinDispatcher.writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text);
117
119
  },
118
120
  writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
119
121
  stdinDispatcher.writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input);
@@ -121,5 +123,14 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
121
123
  writeUserInputPrompt(workspaceId, text) {
122
124
  stdinDispatcher.writeUserInputPrompt(workspaceId, text);
123
125
  },
126
+ writeSystemMessageToAgent(workspaceId, agentId, text) {
127
+ stdinDispatcher.writeSystemMessageToAgent(workspaceId, agentId, text);
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
+ },
124
135
  };
125
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,7 +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, }: {
11
+ export declare const buildAgentStartupInstructions: ({ agent, workspace, flags, }: {
11
12
  agent: AgentSummary;
12
13
  workspace: WorkspaceSummary;
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;
13
19
  }) => string;
@@ -1,25 +1,33 @@
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
- export const buildAgentLegacyIdentityMarker = ({ agent, workspace, }) => `你是 ${workspace.name} ${agent.name}(${agent.role})。`;
5
- export const buildAgentStartupInstructions = ({ agent, workspace, }) => {
5
+ export const buildAgentLegacyIdentityMarker = ({ agent, workspace, }) => `You are ${agent.name} (${agent.role}) in workspace ${workspace.name}.`;
6
+ export const buildAgentStartupInstructions = ({ agent, workspace, flags = FEATURE_FLAGS_ALL_OFF, }) => {
7
+ const { workflowsEnabled } = flags;
6
8
  const lines = [
7
- '[Hive 系统消息:启动说明]',
9
+ '<hive-message kind="startup">',
8
10
  '',
9
11
  buildAgentLegacyIdentityMarker({ agent, workspace }),
10
- `当前 workspace: ${workspace.name}`,
11
- `项目路径: ${workspace.path}`,
12
+ `Current workspace: ${workspace.name}`,
13
+ `Project path: ${workspace.path}`,
12
14
  buildAgentSessionBindingMarker({ agent, workspace }),
13
15
  '',
14
- `你的角色:${agent.description}`,
16
+ // agent.description is the role contract — it follows the user's chosen
17
+ // language / custom edit and is intentionally left as authored.
18
+ `Your role: ${agent.description}`,
15
19
  '',
16
20
  ];
17
21
  if (agent.role === 'orchestrator') {
18
- lines.push('你的职责:', '- 直接响应 user,澄清需求并拆解任务', `- 维护 ${TASKS_RELATIVE_PATH}`, '- worker 名称派单,并根据汇报推进下一步', '', '可用 team 命令:', '- team list', '- team send <worker-name> "<task>"', '- team cancel --dispatch <id> "<reason>"', '', '派单时必须使用 worker name,不要使用 worker id。', '取消未完成派单时必须使用 dispatch id。', '', 'Hive worker 派单规则:', ...getHiveTeamRules(agent));
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] [--ephemeral]', '- team cancel --dispatch <id> "<reason>"', ...(workflowsEnabled
23
+ ? [
24
+ '- team workflow run --stdin (fan-out / staged work — see .hive/PROTOCOL.md for the DSL)',
25
+ ]
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));
19
27
  }
20
28
  else {
21
- lines.push('可用 team 命令:', '- team report "<完整汇报>" [--dispatch <id>] [--artifact <path>] 完成/失败/阻塞汇报', '- team report --stdin [--dispatch <id>] [--artifact <path>] 同上,从 stdin 读正文(适合多行/含引号/特殊字符)', '- team status "<当前状态>" [--artifact <path>] 中段进度/待命/接入状态', '- team status --stdin [--artifact <path>] 同上,从 stdin 读正文', '- team list 查看 workspace 内的 worker(含状态)', '- team --help 仅查命令用法;**不是**汇报手段', '', '语法要点:', '- 正文是第一个 positional argumentflag 顺序任意:`team report "结论" --dispatch X` `team report --dispatch X "结论"` 都成立。', '- 长正文(多行 / 含引号 / shell 特殊字符)一律走 `--stdin`,通过你所在 shell 的管道喂给它(POSIX quoted heredoc `<<\'EOF\' … EOF` 防止 $var/反引号展开,Windows cmd `type body.txt |` 或临时文件 `< body.txt`)。`--stdin` 自己只负责"从 stdin 读",不依赖任何 shell 语法。', '- CLI 报错会同时打印 USAGE,可直接对照修正参数。', '', '完成任务后必须执行 `team report "<结论>"`。', '失败、阻塞或部分完成也用 `team report "<当前状态与原因>"` 汇报。', '没有进行中的任务时,用 `team status "<当前状态>"` 汇报接入、待命或阻塞状态。', '不要调用 team send;worker 之间不能直接派单。', '', 'Hive worker 边界:', ...getHiveTeamRules(agent));
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));
22
30
  }
23
- lines.push('');
31
+ lines.push('', '</hive-message>', '');
24
32
  return lines.join('\n');
25
33
  };
@@ -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,23 +9,42 @@ interface AgentStdinDispatcherInput {
8
9
  getWorkspaceId: (agentId: string) => string | undefined;
9
10
  registry: LiveRunRegistry;
10
11
  syncRun: (run: LiveAgentRun) => LiveAgentRun;
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;
11
16
  }
12
- export declare const buildOrchestratorReportPayload: (workerName: string, text: string, artifacts: string[]) => string;
13
- export declare const buildOrchestratorStatusPayload: (workerName: string, text: string, artifacts: string[]) => string;
14
- export declare const buildOrchestratorUserInputPayload: (text: string) => 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;
15
20
  export declare const buildWorkerDispatchPayload: (fromAgentName: string, workerDescription: string, dispatchId: string, text: string) => string;
16
21
  export declare const buildWorkerCancelPayload: (dispatchId: string, reason: string) => string;
17
- export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }: AgentStdinDispatcherInput) => {
22
+ export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getFlags, }: AgentStdinDispatcherInput) => {
18
23
  writeReportPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
19
24
  requireActiveRun?: boolean;
20
25
  }): void;
21
26
  writeStatusPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
22
27
  requireActiveRun?: boolean;
23
28
  }): void;
24
- writeSendPrompt(workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string): void;
29
+ writeSendPrompt(workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string): Promise<void>;
25
30
  writeCancelPrompt(workspaceId: string, workerId: string, dispatchId: string, reason: string, input?: {
26
31
  requireActiveRun?: boolean;
27
32
  }): void;
28
33
  writeUserInputPrompt(workspaceId: string, text: string): void;
34
+ /** Generic: deliver an opaque text block to a specific agent's PTY.
35
+ * Used by the workflow runner to notify the triggering orchestrator
36
+ * when a run finishes (mirrors Claude Code's <task-notification>). */
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>;
29
49
  };
30
50
  export {};
@@ -1,91 +1,192 @@
1
- import { buildWorkerReminderTail, ORCHESTRATOR_REMINDER_TAIL } from './hive-team-guidance.js';
1
+ import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
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) => {
5
- const lines = [`[Hive 系统消息:来自 @${workerName} 的汇报]`, text];
5
+ export const buildOrchestratorReportPayload = (workerName, text, artifacts, flags = FEATURE_FLAGS_ALL_OFF) => {
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('', ORCHESTRATOR_REMINDER_TAIL, '');
9
+ lines.push('</hive-message>', '', buildOrchestratorReminderTail(flags), '');
9
10
  return lines.join('\n');
10
11
  };
11
- export const buildOrchestratorStatusPayload = (workerName, text, artifacts) => {
12
- const lines = [`[Hive 系统消息:来自 @${workerName} 的状态更新]`, text];
12
+ export const buildOrchestratorStatusPayload = (workerName, text, artifacts, flags = FEATURE_FLAGS_ALL_OFF) => {
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('', ORCHESTRATOR_REMINDER_TAIL, '');
16
+ lines.push('</hive-message>', '', buildOrchestratorReminderTail(flags), '');
16
17
  return lines.join('\n');
17
18
  };
18
- export const buildOrchestratorUserInputPayload = (text) => [text, '', ORCHESTRATOR_REMINDER_TAIL, ''].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
- `[Hive 系统消息:来自 @${fromAgentName} 的派单]`,
21
+ `<hive-message kind="dispatch" from="@${fromAgentName}">`,
21
22
  '',
22
- `你的角色:${workerDescription}`,
23
+ `Your role: ${workerDescription}`,
23
24
  '',
24
- '你必须遵守:',
25
- `- 完成、失败、阻塞或部分完成后,执行 \`team report "<result>" --dispatch ${dispatchId}\``,
26
- '- 不要做无关的事,做完就 report',
25
+ 'You must:',
26
+ `- When the task is done, failed, blocked, or partially done, run \`team report "<result>" --dispatch ${dispatchId}\``,
27
+ '- Do not do unrelated work; report as soon as you are done',
27
28
  '',
28
29
  `dispatch_id: ${dispatchId}`,
29
30
  '',
30
- '任务内容:',
31
+ 'Task:',
31
32
  text,
33
+ '</hive-message>',
32
34
  '',
33
35
  buildWorkerReminderTail(dispatchId),
34
36
  '',
35
37
  ].join('\n');
36
38
  export const buildWorkerCancelPayload = (dispatchId, reason) => [
37
- `[Hive 系统消息:dispatch ${dispatchId} 已取消]`,
39
+ `<hive-message kind="cancel" dispatch="${dispatchId}">`,
38
40
  '',
39
- '请停止执行这条派单,不要再为它调用 team report',
41
+ 'Stop working on this dispatch and do not call team report for it.',
40
42
  '',
41
- '取消原因:',
43
+ 'Cancellation reason:',
42
44
  reason,
45
+ '</hive-message>',
43
46
  '',
44
47
  ].join('\n');
45
- export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }) => {
46
- const writeToActiveAgentRun = (workspaceId, agentId, text, input = {}) => {
47
- const run = registry
48
- .list()
49
- .filter((item) => item.agentId === agentId && getWorkspaceId(item.agentId) === workspaceId)
50
- .sort((left, right) => right.startedAt - left.startedAt)
51
- .find((item) => {
52
- const status = syncRun(item).status;
53
- return status === 'starting' || status === 'running';
54
- });
55
- if (!run) {
48
+ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getFlags, }) => {
49
+ const flags = () => getFlags?.() ?? FEATURE_FLAGS_ALL_OFF;
50
+ const chains = new Map();
51
+ const getChain = (agentId) => {
52
+ let chain = chains.get(agentId);
53
+ if (!chain) {
54
+ chain = { busy: false, queue: [] };
55
+ chains.set(agentId, chain);
56
+ }
57
+ return chain;
58
+ };
59
+ const resolveActiveRun = (workspaceId, agentId) => registry
60
+ .list()
61
+ .filter((item) => item.agentId === agentId && getWorkspaceId(item.agentId) === workspaceId)
62
+ .sort((left, right) => right.startedAt - left.startedAt)
63
+ .find((item) => {
64
+ const status = syncRun(item).status;
65
+ return status === 'starting' || status === 'running';
66
+ });
67
+ // Synchronously enforce requireActiveRun (so writeSendPrompt still throws in
68
+ // the caller's stack when there is no live run), then return a thunk that
69
+ // re-resolves the run at EXECUTION time and performs the actual write,
70
+ // returning a promise that settles when the paste→submit sequence is done.
71
+ const prepareWrite = (workspaceId, agentId, text, input) => {
72
+ if (!resolveActiveRun(workspaceId, agentId)) {
56
73
  if (input.requireActiveRun) {
57
74
  throw new PtyInactiveError(`No active run for agent: ${agentId}`);
58
75
  }
59
- return;
76
+ return () => Promise.resolve();
60
77
  }
61
- try {
62
- const config = getLaunchConfig(workspaceId, agentId);
63
- if (agentManager && config) {
64
- createPostStartInputWriter(agentManager, config.interactiveCommand ?? config.command)(run.runId, text);
78
+ return () => {
79
+ const run = resolveActiveRun(workspaceId, agentId);
80
+ if (!run) {
81
+ if (input.requireActiveRun) {
82
+ throw new PtyInactiveError(`No active run for agent: ${agentId}`);
83
+ }
84
+ return Promise.resolve();
65
85
  }
66
- else {
86
+ try {
87
+ const config = getLaunchConfig(workspaceId, agentId);
88
+ if (agentManager && config) {
89
+ return (createPostStartInputWriter(agentManager, config.interactiveCommand ?? config.command)(run.runId, text).catch((error) => {
90
+ throw new PtyInactiveError(error instanceof Error ? error.message : String(error));
91
+ }) ?? Promise.resolve());
92
+ }
67
93
  agentManager?.writeInput(run.runId, text);
94
+ return Promise.resolve();
95
+ }
96
+ catch (error) {
97
+ throw new PtyInactiveError(error instanceof Error ? error.message : String(error));
68
98
  }
99
+ };
100
+ };
101
+ const settle = (agentId, promise) => promise.finally(() => {
102
+ const chain = chains.get(agentId);
103
+ if (!chain)
104
+ return;
105
+ chain.busy = false;
106
+ drain(agentId);
107
+ });
108
+ const runQueuedWrite = (agentId, write) => {
109
+ try {
110
+ void settle(agentId, write.run()).then(write.resolve, write.reject);
111
+ }
112
+ catch (error) {
113
+ write.reject(error);
114
+ const chain = chains.get(agentId);
115
+ if (chain)
116
+ chain.busy = false;
117
+ drain(agentId);
118
+ }
119
+ };
120
+ function drain(agentId) {
121
+ const chain = chains.get(agentId);
122
+ if (!chain)
123
+ return;
124
+ if (chain.busy)
125
+ return;
126
+ const next = chain.queue.shift();
127
+ if (!next) {
128
+ chains.delete(agentId);
129
+ return;
130
+ }
131
+ chain.busy = true;
132
+ runQueuedWrite(agentId, next);
133
+ }
134
+ const writeToActiveAgentRun = (workspaceId, agentId, text, input = {}) => {
135
+ const thunk = prepareWrite(workspaceId, agentId, text, input);
136
+ const chain = getChain(agentId);
137
+ if (chain.busy) {
138
+ return new Promise((resolve, reject) => {
139
+ chain.queue.push({ reject, resolve, run: thunk });
140
+ });
141
+ }
142
+ chain.busy = true;
143
+ try {
144
+ return settle(agentId, thunk()); // uncontended: run now; immediate failures still throw
69
145
  }
70
146
  catch (error) {
71
- throw new PtyInactiveError(error instanceof Error ? error.message : String(error));
147
+ chain.busy = false;
148
+ drain(agentId);
149
+ throw error;
72
150
  }
73
151
  };
152
+ const swallowQueuedFailure = (promise) => {
153
+ void promise.catch(() => {
154
+ // Deferred prompt writes can fail if the PTY exits while queued. Calls
155
+ // that require foreground error reporting use writeSendPrompt's promise.
156
+ });
157
+ };
74
158
  return {
75
159
  writeReportPrompt(workspaceId, workerName, text, artifacts, input = {}) {
76
- writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts), input);
160
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts, flags()), input));
77
161
  },
78
162
  writeStatusPrompt(workspaceId, workerName, text, artifacts, input = {}) {
79
- writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts), input);
163
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts, flags()), input));
80
164
  },
81
165
  writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
82
- writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
166
+ return writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
83
167
  },
84
168
  writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
85
- writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input);
169
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input));
86
170
  },
87
171
  writeUserInputPrompt(workspaceId, text) {
88
- writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text));
172
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text, flags())));
173
+ },
174
+ /** Generic: deliver an opaque text block to a specific agent's PTY.
175
+ * Used by the workflow runner to notify the triggering orchestrator
176
+ * when a run finishes (mirrors Claude Code's <task-notification>). */
177
+ writeSystemMessageToAgent(workspaceId, agentId, text) {
178
+ swallowQueuedFailure(writeToActiveAgentRun(workspaceId, agentId, text));
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);
89
190
  },
90
191
  };
91
192
  };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Validate a 5-field cron string and return its next fire time (ms-epoch).
3
+ * Throws BadRequestError on an unparseable expression. Shared by the UI
4
+ * schedule PATCH route and the agent `team workflow schedule` route so cron
5
+ * validation behaves identically on both paths. UTC, like the scheduler.
6
+ */
7
+ export declare const validateCronNextRunAt: (cron: string) => number;
@@ -0,0 +1,19 @@
1
+ import { CronExpressionParser } from 'cron-parser';
2
+ import { BadRequestError } from './http-errors.js';
3
+ /**
4
+ * Validate a 5-field cron string and return its next fire time (ms-epoch).
5
+ * Throws BadRequestError on an unparseable expression. Shared by the UI
6
+ * schedule PATCH route and the agent `team workflow schedule` route so cron
7
+ * validation behaves identically on both paths. UTC, like the scheduler.
8
+ */
9
+ export const validateCronNextRunAt = (cron) => {
10
+ try {
11
+ return CronExpressionParser.parse(cron, { currentDate: new Date(), tz: 'UTC' })
12
+ .next()
13
+ .toDate()
14
+ .getTime();
15
+ }
16
+ catch (error) {
17
+ throw new BadRequestError(`Invalid cron expression: ${error instanceof Error ? error.message : String(error)}`);
18
+ }
19
+ };
@@ -6,19 +6,27 @@ export interface DispatchRecord {
6
6
  deliveredAt: number | null;
7
7
  fromAgentId: string | null;
8
8
  id: string;
9
+ label: string | null;
10
+ phase: string | null;
9
11
  reportedAt: number | null;
10
12
  reportText: string | null;
11
13
  sequence: number | null;
12
14
  status: DispatchStatus;
15
+ stepIndex: number | null;
13
16
  submittedAt: number | null;
14
17
  text: string;
15
18
  toAgentId: string;
19
+ workflowRunId: string | null;
16
20
  workspaceId: string;
17
21
  }
18
22
  interface CreateDispatchInput {
19
23
  fromAgentId?: string;
24
+ label?: string;
25
+ phase?: string;
26
+ stepIndex?: number;
20
27
  text: string;
21
28
  toAgentId: string;
29
+ workflowRunId?: string;
22
30
  workspaceId: string;
23
31
  }
24
32
  interface ReportDispatchInput {
@@ -50,6 +58,12 @@ export declare const createDispatchLedgerStore: (db: Database) => {
50
58
  worker_id: string;
51
59
  workspace_id: string;
52
60
  }>;
61
+ listOpenDispatchIdsForRun: (runId: string) => string[];
62
+ listOpenWorkflowDispatchesForWorker: (workspaceId: string, workerId: string) => Array<{
63
+ dispatchId: string;
64
+ runId: string;
65
+ }>;
66
+ listWorkflowRunDispatches: (runId: string) => DispatchRecord[];
53
67
  listWorkspaceDispatches: (workspaceId: string, options?: ListDispatchesOptions) => DispatchRecord[];
54
68
  markCancelled: (input: CancelDispatchInput) => {
55
69
  reportedAt: number;
@@ -60,10 +74,14 @@ export declare const createDispatchLedgerStore: (db: Database) => {
60
74
  deliveredAt: number | null;
61
75
  fromAgentId: string | null;
62
76
  id: string;
77
+ label: string | null;
78
+ phase: string | null;
63
79
  sequence: number | null;
80
+ stepIndex: number | null;
64
81
  submittedAt: number | null;
65
82
  text: string;
66
83
  toAgentId: string;
84
+ workflowRunId: string | null;
67
85
  workspaceId: string;
68
86
  } | undefined;
69
87
  markReportedByWorker: (input: ReportDispatchInput) => {
@@ -75,10 +93,14 @@ export declare const createDispatchLedgerStore: (db: Database) => {
75
93
  deliveredAt: number | null;
76
94
  fromAgentId: string | null;
77
95
  id: string;
96
+ label: string | null;
97
+ phase: string | null;
78
98
  sequence: number | null;
99
+ stepIndex: number | null;
79
100
  submittedAt: number | null;
80
101
  text: string;
81
102
  toAgentId: string;
103
+ workflowRunId: string | null;
82
104
  workspaceId: string;
83
105
  } | undefined;
84
106
  markSubmitted: (dispatchId: string) => void;