@tt-a1i/hive 1.4.3 → 1.5.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.
- package/CHANGELOG.md +44 -0
- package/README.en.md +5 -4
- package/README.md +9 -1
- package/assets/qq-group.jpg +0 -0
- package/dist/bin/team.cmd +1 -0
- package/dist/src/cli/hive-update.d.ts +57 -0
- package/dist/src/cli/hive-update.js +92 -15
- package/dist/src/cli/hive.d.ts +57 -0
- package/dist/src/cli/hive.js +113 -20
- package/dist/src/cli/team.d.ts +1 -0
- package/dist/src/cli/team.js +215 -7
- package/dist/src/server/agent-command-resolver.d.ts +10 -1
- package/dist/src/server/agent-command-resolver.js +32 -4
- package/dist/src/server/agent-launch-resolver.js +9 -3
- package/dist/src/server/agent-manager-support.d.ts +28 -0
- package/dist/src/server/agent-manager-support.js +138 -10
- package/dist/src/server/agent-run-bootstrap.d.ts +17 -1
- package/dist/src/server/agent-run-bootstrap.js +30 -2
- package/dist/src/server/agent-run-starter.d.ts +7 -1
- package/dist/src/server/agent-run-starter.js +9 -2
- package/dist/src/server/agent-run-store.d.ts +1 -1
- package/dist/src/server/agent-runtime-close.d.ts +1 -0
- package/dist/src/server/agent-runtime-close.js +25 -1
- package/dist/src/server/agent-runtime-contract.d.ts +2 -1
- package/dist/src/server/agent-runtime.d.ts +1 -1
- package/dist/src/server/agent-runtime.js +8 -2
- package/dist/src/server/agent-startup-instructions.d.ts +8 -1
- package/dist/src/server/agent-startup-instructions.js +15 -9
- package/dist/src/server/agent-stdin-dispatcher.d.ts +12 -5
- package/dist/src/server/agent-stdin-dispatcher.js +129 -40
- package/dist/src/server/app.d.ts +1 -0
- package/dist/src/server/app.js +12 -2
- package/dist/src/server/cron-util.d.ts +7 -0
- package/dist/src/server/cron-util.js +19 -0
- package/dist/src/server/dispatch-ledger-store.d.ts +22 -0
- package/dist/src/server/dispatch-ledger-store.js +51 -3
- package/dist/src/server/env-sync-message.js +9 -9
- package/dist/src/server/fs-browse.d.ts +14 -1
- package/dist/src/server/fs-browse.js +48 -5
- package/dist/src/server/fs-pick-folder.js +58 -11
- package/dist/src/server/fs-sandbox.js +36 -7
- package/dist/src/server/hive-team-guidance.d.ts +11 -6
- package/dist/src/server/hive-team-guidance.js +252 -70
- package/dist/src/server/live-run-registry.d.ts +1 -0
- package/dist/src/server/live-run-registry.js +1 -1
- package/dist/src/server/open-target-commands.js +29 -4
- package/dist/src/server/orchestrator-autostart.d.ts +12 -0
- package/dist/src/server/orchestrator-autostart.js +15 -13
- package/dist/src/server/path-canonicalization.d.ts +3 -0
- package/dist/src/server/path-canonicalization.js +29 -0
- package/dist/src/server/platform-path.d.ts +3 -0
- package/dist/src/server/platform-path.js +13 -0
- package/dist/src/server/post-start-input-writer.d.ts +1 -1
- package/dist/src/server/post-start-input-writer.js +116 -16
- package/dist/src/server/preset-launch-support.d.ts +1 -1
- package/dist/src/server/preset-launch-support.js +33 -2
- package/dist/src/server/recovery-summary.d.ts +6 -1
- package/dist/src/server/recovery-summary.js +17 -17
- package/dist/src/server/restart-policy-support.d.ts +6 -1
- package/dist/src/server/restart-policy-support.js +9 -1
- package/dist/src/server/restart-policy.d.ts +2 -2
- package/dist/src/server/restart-policy.js +3 -1
- package/dist/src/server/role-template-store.d.ts +1 -0
- package/dist/src/server/role-template-store.js +11 -1
- package/dist/src/server/route-types.d.ts +43 -0
- package/dist/src/server/routes-runtime.js +2 -1
- package/dist/src/server/routes-settings.js +76 -0
- package/dist/src/server/routes-team.js +221 -2
- package/dist/src/server/routes-workflow-schedules.d.ts +2 -0
- package/dist/src/server/routes-workflow-schedules.js +58 -0
- package/dist/src/server/routes-workflows.d.ts +2 -0
- package/dist/src/server/routes-workflows.js +83 -0
- package/dist/src/server/routes.js +4 -0
- package/dist/src/server/runtime-restart-policy.d.ts +3 -1
- package/dist/src/server/runtime-restart-policy.js +3 -1
- package/dist/src/server/runtime-store-contract.d.ts +122 -0
- package/dist/src/server/runtime-store-contract.js +1 -0
- package/dist/src/server/runtime-store-helpers.d.ts +9 -0
- package/dist/src/server/runtime-store-helpers.js +101 -2
- package/dist/src/server/runtime-store-workflows.d.ts +6 -0
- package/dist/src/server/runtime-store-workflows.js +100 -0
- package/dist/src/server/runtime-store.d.ts +3 -70
- package/dist/src/server/runtime-store.js +70 -4
- package/dist/src/server/session-capture-claude.d.ts +23 -0
- package/dist/src/server/session-capture-claude.js +24 -1
- package/dist/src/server/session-capture-codex.d.ts +3 -3
- package/dist/src/server/session-capture-codex.js +9 -7
- package/dist/src/server/session-capture-gemini.d.ts +1 -1
- package/dist/src/server/session-capture-gemini.js +6 -3
- package/dist/src/server/session-capture-opencode.d.ts +18 -0
- package/dist/src/server/session-capture-opencode.js +27 -2
- package/dist/src/server/settings-store.d.ts +3 -0
- package/dist/src/server/settings-store.js +1 -0
- package/dist/src/server/sqlite-schema-v19.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v19.js +17 -0
- package/dist/src/server/sqlite-schema-v20.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v20.js +20 -0
- package/dist/src/server/sqlite-schema-v21.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v21.js +20 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +97 -1
- package/dist/src/server/startup-command-parser.d.ts +15 -0
- package/dist/src/server/startup-command-parser.js +33 -2
- package/dist/src/server/system-message.d.ts +7 -0
- package/dist/src/server/system-message.js +8 -1
- package/dist/src/server/tasks-file-watcher.d.ts +39 -1
- package/dist/src/server/tasks-file-watcher.js +155 -25
- package/dist/src/server/tasks-file.d.ts +2 -1
- package/dist/src/server/tasks-file.js +32 -9
- package/dist/src/server/tasks-websocket-server.js +13 -14
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +9 -1
- package/dist/src/server/team-autostaff.d.ts +16 -0
- package/dist/src/server/team-autostaff.js +16 -0
- package/dist/src/server/team-list-serializer.d.ts +1 -1
- package/dist/src/server/team-list-serializer.js +3 -1
- package/dist/src/server/team-operations.d.ts +20 -2
- package/dist/src/server/team-operations.js +160 -14
- package/dist/src/server/terminal-input-profile.js +2 -8
- package/dist/src/server/terminal-protocol.js +9 -3
- package/dist/src/server/terminal-stream-hub.js +16 -10
- package/dist/src/server/terminal-ws-server.js +36 -16
- package/dist/src/server/websocket-upgrade-safety.d.ts +10 -0
- package/dist/src/server/websocket-upgrade-safety.js +35 -0
- package/dist/src/server/windows-command-line.d.ts +3 -0
- package/dist/src/server/windows-command-line.js +9 -0
- package/dist/src/server/windows-filename.d.ts +2 -0
- package/dist/src/server/windows-filename.js +33 -0
- package/dist/src/server/workflow-cli-policy.d.ts +60 -0
- package/dist/src/server/workflow-cli-policy.js +110 -0
- package/dist/src/server/workflow-dispatch-awaiter.d.ts +12 -0
- package/dist/src/server/workflow-dispatch-awaiter.js +80 -0
- package/dist/src/server/workflow-feature.d.ts +15 -0
- package/dist/src/server/workflow-feature.js +15 -0
- package/dist/src/server/workflow-http-serializers.d.ts +64 -0
- package/dist/src/server/workflow-http-serializers.js +58 -0
- package/dist/src/server/workflow-run-log-store.d.ts +19 -0
- package/dist/src/server/workflow-run-log-store.js +45 -0
- package/dist/src/server/workflow-run-store.d.ts +50 -0
- package/dist/src/server/workflow-run-store.js +103 -0
- package/dist/src/server/workflow-runner.d.ts +147 -0
- package/dist/src/server/workflow-runner.js +401 -0
- package/dist/src/server/workflow-schedule-create.d.ts +14 -0
- package/dist/src/server/workflow-schedule-create.js +41 -0
- package/dist/src/server/workflow-schedule-store.d.ts +43 -0
- package/dist/src/server/workflow-schedule-store.js +112 -0
- package/dist/src/server/workflow-scheduler.d.ts +36 -0
- package/dist/src/server/workflow-scheduler.js +97 -0
- package/dist/src/server/workflow-script-loader.d.ts +34 -0
- package/dist/src/server/workflow-script-loader.js +106 -0
- package/dist/src/server/workspace-path-validation.js +16 -4
- package/dist/src/server/workspace-shell-runtime.d.ts +5 -0
- package/dist/src/server/workspace-shell-runtime.js +24 -2
- package/dist/src/server/workspace-store-contract.d.ts +4 -1
- package/dist/src/server/workspace-store-hydration.js +23 -7
- package/dist/src/server/workspace-store-mutations.js +2 -5
- package/dist/src/server/workspace-store-support.d.ts +4 -0
- package/dist/src/server/workspace-store-support.js +13 -1
- package/dist/src/server/workspace-store.js +38 -4
- package/dist/src/shared/types.d.ts +16 -1
- package/package.json +4 -2
- package/web/dist/assets/{AddWorkerDialog-DmkDOdp6.js → AddWorkerDialog-CcC-7kgG.js} +2 -2
- package/web/dist/assets/AddWorkspaceDialog-BDpOTfmt.js +1 -0
- package/web/dist/assets/{FirstRunWizard-SAd1wsH4.js → FirstRunWizard-BYX_ocQn.js} +1 -1
- package/web/dist/assets/{MarketplaceDrawer-B_8aG2uT.js → MarketplaceDrawer-DUxSk7db.js} +1 -1
- package/web/dist/assets/WhatsNewDialog-B_RlCXcV.js +1 -0
- package/web/dist/assets/WorkerModal-D9-7YfZZ.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-BCKoF7qc.js +1 -0
- package/web/dist/assets/{WorkspaceTerminalPanels-BReWh1YL.js → WorkspaceTerminalPanels-Dq8y91t2.js} +1 -1
- package/web/dist/assets/index-BiOvKIVw.css +1 -0
- package/web/dist/assets/index-DMRUklT3.js +73 -0
- package/web/dist/assets/path-join-7MR1s7b1.js +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/sw.js +1 -1
- package/web/dist/assets/AddWorkspaceDialog-BsVnH3Xe.js +0 -1
- package/web/dist/assets/WorkerModal-CQmjiPme.js +0 -1
- package/web/dist/assets/WorkspaceTaskDrawer-B0DmCWcV.js +0 -1
- package/web/dist/assets/chevron-right-CtLjVEl7.js +0 -1
- package/web/dist/assets/index-BEsTmfrO.css +0 -1
- package/web/dist/assets/index-Cn8X3get.js +0 -76
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dirname, posix, resolve, sep, win32 } from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { buildAgentLegacyIdentityMarker, buildAgentSessionBindingMarker, } from './agent-startup-instructions.js';
|
|
4
4
|
import { withPresetResumeArgs } from './preset-launch-support.js';
|
|
@@ -12,6 +12,34 @@ const resolveHiveBinDir = () => {
|
|
|
12
12
|
};
|
|
13
13
|
const HIVE_BIN_DIR = resolveHiveBinDir();
|
|
14
14
|
const SESSION_CAPTURE_TIMEOUT_MS = 30_000;
|
|
15
|
+
/**
|
|
16
|
+
* Builds a `{ <PATH-key>: <new-value> }` object for the spawn env override.
|
|
17
|
+
* Critical on Windows: the OS env block reports PATH under its native casing
|
|
18
|
+
* (typically `Path`). Writing to a literal `PATH` key would, after spread
|
|
19
|
+
* with `process.env`, leave two entries — `Path` carrying the original value
|
|
20
|
+
* and `PATH` carrying our prepend. CreateProcess then sees both and the
|
|
21
|
+
* effective lookup order is undefined; in practice the child PTY often falls
|
|
22
|
+
* back to the original `Path` and never sees `HIVE_BIN_DIR`, breaking every
|
|
23
|
+
* `team` shim resolution.
|
|
24
|
+
*
|
|
25
|
+
* We detect the existing key (case-insensitive on Windows) and overwrite IT,
|
|
26
|
+
* so the merge produces exactly one PATH entry.
|
|
27
|
+
*
|
|
28
|
+
* Exported for unit testing — `buildAgentRunBootstrap` is the only in-tree
|
|
29
|
+
* caller.
|
|
30
|
+
*/
|
|
31
|
+
export const buildSpawnPathEnvEntry = (parentEnv, hiveBinDir, platform) => {
|
|
32
|
+
const existingKey = platform === 'win32'
|
|
33
|
+
? Object.keys(parentEnv).find((key) => key.toLowerCase() === 'path')
|
|
34
|
+
: undefined;
|
|
35
|
+
const key = existingKey ?? 'PATH';
|
|
36
|
+
const existingValue = existingKey ? parentEnv[existingKey] : parentEnv.PATH;
|
|
37
|
+
// Target platform's delimiter — Windows uses `;`, POSIX `:` — independent
|
|
38
|
+
// of where this function is running (tests on macOS verify the win32 path).
|
|
39
|
+
const platformDelimiter = platform === 'win32' ? win32.delimiter : posix.delimiter;
|
|
40
|
+
const value = existingValue ? `${hiveBinDir}${platformDelimiter}${existingValue}` : hiveBinDir;
|
|
41
|
+
return { [key]: value };
|
|
42
|
+
};
|
|
15
43
|
const resolveLaunchPreset = (config, getCommandPreset) => {
|
|
16
44
|
if (config.presetAugmentationDisabled)
|
|
17
45
|
return undefined;
|
|
@@ -52,7 +80,7 @@ export const buildAgentRunBootstrap = (workspace, agentId, config, sessionStore,
|
|
|
52
80
|
HIVE_PROJECT_ID: workspace.id,
|
|
53
81
|
HIVE_AGENT_ID: agentId,
|
|
54
82
|
HIVE_AGENT_TOKEN: '',
|
|
55
|
-
|
|
83
|
+
...buildSpawnPathEnvEntry(process.env, HIVE_BIN_DIR, process.platform),
|
|
56
84
|
},
|
|
57
85
|
};
|
|
58
86
|
};
|
|
@@ -18,6 +18,12 @@ interface AgentRunStarterInput {
|
|
|
18
18
|
getCommandPreset: (id: string) => CommandPresetRecord | undefined;
|
|
19
19
|
getAgent: ((workspaceId: string, agentId: string) => AgentSummary | undefined) | undefined;
|
|
20
20
|
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;
|
|
21
27
|
}
|
|
22
|
-
export declare const createAgentRunStarter: ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, }: AgentRunStarterInput) => (workspace: WorkspaceSummary, agentId: string, config: AgentLaunchConfigInput, hivePort: string) => Promise<LiveAgentRun>;
|
|
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>;
|
|
23
29
|
export {};
|
|
@@ -2,7 +2,7 @@ import { buildAgentRunBootstrap, startAgentRunCapture } from './agent-run-bootst
|
|
|
2
2
|
import { handleAgentRunExit } from './agent-run-exit-handler.js';
|
|
3
3
|
import { buildAgentStartupInstructions } from './agent-startup-instructions.js';
|
|
4
4
|
import { createPostStartInputWriter, isInteractiveAgentCommand } from './post-start-input-writer.js';
|
|
5
|
-
export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, }) => async (workspace, agentId, config, hivePort) => {
|
|
5
|
+
export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, store, sessionStore, tokenRegistry, getCommandPreset, getAgent, restartPolicy, getWorkflowsEnabled, getAutostaffEnabled, }) => async (workspace, agentId, config, hivePort) => {
|
|
6
6
|
if (!agentManager)
|
|
7
7
|
throw new Error('Agent manager is required to start agents');
|
|
8
8
|
const agent = getAgent?.(workspace.id, agentId);
|
|
@@ -99,7 +99,14 @@ export const createAgentRunStarter = ({ agentManager, registry, onAgentExit, sto
|
|
|
99
99
|
!injectedRestartMessage &&
|
|
100
100
|
agent &&
|
|
101
101
|
isInteractiveAgentCommand(startConfig.interactiveCommand ?? startConfig.command)) {
|
|
102
|
-
postStartWriter(run.runId, buildAgentStartupInstructions({
|
|
102
|
+
void postStartWriter(run.runId, buildAgentStartupInstructions({
|
|
103
|
+
agent,
|
|
104
|
+
workspace,
|
|
105
|
+
workflowsEnabled: getWorkflowsEnabled?.() ?? false,
|
|
106
|
+
autostaffEnabled: getAutostaffEnabled?.() ?? false,
|
|
107
|
+
})).catch(() => {
|
|
108
|
+
// The agent may have exited before post-start guidance could be written.
|
|
109
|
+
});
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
112
|
catch {
|
|
@@ -27,7 +27,7 @@ export declare const createAgentRunStore: (db: Database) => {
|
|
|
27
27
|
runId: string;
|
|
28
28
|
agentId: string;
|
|
29
29
|
pid: number | null;
|
|
30
|
-
status: "
|
|
30
|
+
status: "starting" | "running" | "exited" | "error";
|
|
31
31
|
exitCode: number | null;
|
|
32
32
|
startedAt: number;
|
|
33
33
|
endedAt: number | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
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 AGENT_RUNTIME_CLOSE_TIMEOUT_MS = 5000;
|
|
4
5
|
export declare const closeAgentRuntime: (agentManager: AgentManager | undefined, registry: LiveRunRegistry, syncRun: (run: LiveAgentRun) => LiveAgentRun) => Promise<void>;
|
|
@@ -1,10 +1,34 @@
|
|
|
1
|
+
export const AGENT_RUNTIME_CLOSE_TIMEOUT_MS = 5000;
|
|
2
|
+
const waitForExitEntries = async (entries, timeoutMs = AGENT_RUNTIME_CLOSE_TIMEOUT_MS) => {
|
|
3
|
+
if (entries.length === 0)
|
|
4
|
+
return;
|
|
5
|
+
let timer;
|
|
6
|
+
const timeout = new Promise((resolve) => {
|
|
7
|
+
timer = setTimeout(() => resolve('timeout'), timeoutMs);
|
|
8
|
+
timer.unref?.();
|
|
9
|
+
});
|
|
10
|
+
try {
|
|
11
|
+
const result = await Promise.race([
|
|
12
|
+
Promise.all(entries.map((entry) => entry.promise)).then(() => 'done'),
|
|
13
|
+
timeout,
|
|
14
|
+
]);
|
|
15
|
+
if (result === 'timeout') {
|
|
16
|
+
const runIds = entries.map((entry) => entry.runId).join(', ');
|
|
17
|
+
console.error(`[hive] timed out waiting for agent exit during shutdown: ${runIds}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
if (timer)
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
1
25
|
export const closeAgentRuntime = async (agentManager, registry, syncRun) => {
|
|
2
26
|
const runs = registry.list();
|
|
3
27
|
for (const run of runs) {
|
|
4
28
|
syncRun(run);
|
|
5
29
|
agentManager?.stopRun(run.runId);
|
|
6
30
|
}
|
|
7
|
-
await
|
|
31
|
+
await waitForExitEntries(registry.listExitEntries());
|
|
8
32
|
for (const run of registry.list()) {
|
|
9
33
|
agentManager?.removeRun(run.runId);
|
|
10
34
|
registry.remove(run.runId);
|
|
@@ -28,10 +28,11 @@ export interface AgentRuntime {
|
|
|
28
28
|
writeStatusPrompt: (workspaceId: string, workerName: string, workerId: string, text: string, artifacts: string[], input?: {
|
|
29
29
|
requireActiveRun?: boolean;
|
|
30
30
|
}) => void;
|
|
31
|
-
writeSendPrompt: (workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string) => void
|
|
31
|
+
writeSendPrompt: (workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string) => Promise<void>;
|
|
32
32
|
writeCancelPrompt: (workspaceId: string, workerId: string, dispatchId: string, reason: string, input?: {
|
|
33
33
|
requireActiveRun?: boolean;
|
|
34
34
|
}) => void;
|
|
35
35
|
writeUserInputPrompt: (workspaceId: string, text: string) => void;
|
|
36
|
+
writeSystemMessageToAgent: (workspaceId: string, agentId: string, text: string) => void;
|
|
36
37
|
}
|
|
37
38
|
export type { StartAgentOptions };
|
|
@@ -4,5 +4,5 @@ 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
6
|
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;
|
|
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
8
|
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, getWorkflowsEnabled, getAutostaffEnabled) => {
|
|
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
|
+
...(getWorkflowsEnabled ? { getWorkflowsEnabled } : {}),
|
|
32
33
|
});
|
|
33
34
|
const startLiveRun = createAgentRunStarter({
|
|
34
35
|
agentManager,
|
|
@@ -40,6 +41,8 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
|
|
|
40
41
|
getCommandPreset,
|
|
41
42
|
getAgent,
|
|
42
43
|
restartPolicy,
|
|
44
|
+
...(getWorkflowsEnabled ? { getWorkflowsEnabled } : {}),
|
|
45
|
+
...(getAutostaffEnabled ? { getAutostaffEnabled } : {}),
|
|
43
46
|
});
|
|
44
47
|
return {
|
|
45
48
|
async close() {
|
|
@@ -113,7 +116,7 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
|
|
|
113
116
|
stdinDispatcher.writeStatusPrompt(workspaceId, workerName, text, artifacts, input);
|
|
114
117
|
},
|
|
115
118
|
writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
|
|
116
|
-
stdinDispatcher.writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text);
|
|
119
|
+
return stdinDispatcher.writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text);
|
|
117
120
|
},
|
|
118
121
|
writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
|
|
119
122
|
stdinDispatcher.writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input);
|
|
@@ -121,5 +124,8 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
|
|
|
121
124
|
writeUserInputPrompt(workspaceId, text) {
|
|
122
125
|
stdinDispatcher.writeUserInputPrompt(workspaceId, text);
|
|
123
126
|
},
|
|
127
|
+
writeSystemMessageToAgent(workspaceId, agentId, text) {
|
|
128
|
+
stdinDispatcher.writeSystemMessageToAgent(workspaceId, agentId, text);
|
|
129
|
+
},
|
|
124
130
|
};
|
|
125
131
|
};
|
|
@@ -7,7 +7,14 @@ export declare const buildAgentLegacyIdentityMarker: ({ agent, workspace, }: {
|
|
|
7
7
|
agent: AgentSummary;
|
|
8
8
|
workspace: WorkspaceSummary;
|
|
9
9
|
}) => string;
|
|
10
|
-
export declare const buildAgentStartupInstructions: ({ agent, workspace, }: {
|
|
10
|
+
export declare const buildAgentStartupInstructions: ({ agent, workspace, workflowsEnabled, autostaffEnabled, }: {
|
|
11
11
|
agent: AgentSummary;
|
|
12
12
|
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;
|
|
13
20
|
}) => string;
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import { getHiveTeamRules } from './hive-team-guidance.js';
|
|
2
2
|
import { TASKS_RELATIVE_PATH } from './tasks-file.js';
|
|
3
3
|
export const buildAgentSessionBindingMarker = ({ agent, workspace, }) => `Hive session binding: workspace_id=${workspace.id}; agent_id=${agent.id}`;
|
|
4
|
-
export const buildAgentLegacyIdentityMarker = ({ agent, workspace, }) =>
|
|
5
|
-
export const buildAgentStartupInstructions = ({ agent, workspace, }) => {
|
|
4
|
+
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
6
|
const lines = [
|
|
7
|
-
'
|
|
7
|
+
'<hive-message kind="startup">',
|
|
8
8
|
'',
|
|
9
9
|
buildAgentLegacyIdentityMarker({ agent, workspace }),
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
`Current workspace: ${workspace.name}`,
|
|
11
|
+
`Project path: ${workspace.path}`,
|
|
12
12
|
buildAgentSessionBindingMarker({ agent, workspace }),
|
|
13
13
|
'',
|
|
14
|
-
|
|
14
|
+
// agent.description is the role contract — it follows the user's chosen
|
|
15
|
+
// language / custom edit and is intentionally left as authored.
|
|
16
|
+
`Your role: ${agent.description}`,
|
|
15
17
|
'',
|
|
16
18
|
];
|
|
17
19
|
if (agent.role === 'orchestrator') {
|
|
18
|
-
lines.push('
|
|
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
|
|
21
|
+
? [
|
|
22
|
+
'- team workflow run --stdin (fan-out / staged work — see .hive/PROTOCOL.md for the DSL)',
|
|
23
|
+
]
|
|
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));
|
|
19
25
|
}
|
|
20
26
|
else {
|
|
21
|
-
lines.push('
|
|
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));
|
|
22
28
|
}
|
|
23
|
-
lines.push('');
|
|
29
|
+
lines.push('', '</hive-message>', '');
|
|
24
30
|
return lines.join('\n');
|
|
25
31
|
};
|
|
@@ -8,23 +8,30 @@ interface AgentStdinDispatcherInput {
|
|
|
8
8
|
getWorkspaceId: (agentId: string) => string | undefined;
|
|
9
9
|
registry: LiveRunRegistry;
|
|
10
10
|
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;
|
|
11
14
|
}
|
|
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;
|
|
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;
|
|
15
18
|
export declare const buildWorkerDispatchPayload: (fromAgentName: string, workerDescription: string, dispatchId: string, text: string) => string;
|
|
16
19
|
export declare const buildWorkerCancelPayload: (dispatchId: string, reason: string) => string;
|
|
17
|
-
export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }: AgentStdinDispatcherInput) => {
|
|
20
|
+
export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getWorkflowsEnabled, }: AgentStdinDispatcherInput) => {
|
|
18
21
|
writeReportPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
|
|
19
22
|
requireActiveRun?: boolean;
|
|
20
23
|
}): void;
|
|
21
24
|
writeStatusPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
|
|
22
25
|
requireActiveRun?: boolean;
|
|
23
26
|
}): void;
|
|
24
|
-
writeSendPrompt(workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string): void
|
|
27
|
+
writeSendPrompt(workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string): Promise<void>;
|
|
25
28
|
writeCancelPrompt(workspaceId: string, workerId: string, dispatchId: string, reason: string, input?: {
|
|
26
29
|
requireActiveRun?: boolean;
|
|
27
30
|
}): void;
|
|
28
31
|
writeUserInputPrompt(workspaceId: string, text: string): void;
|
|
32
|
+
/** Generic: deliver an opaque text block to a specific agent's PTY.
|
|
33
|
+
* Used by the workflow runner to notify the triggering orchestrator
|
|
34
|
+
* when a run finishes (mirrors Claude Code's <task-notification>). */
|
|
35
|
+
writeSystemMessageToAgent(workspaceId: string, agentId: string, text: string): void;
|
|
29
36
|
};
|
|
30
37
|
export {};
|
|
@@ -1,91 +1,180 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildOrchestratorReminderTail, buildWorkerReminderTail } from './hive-team-guidance.js';
|
|
2
2
|
import { PtyInactiveError } from './http-errors.js';
|
|
3
3
|
import { createPostStartInputWriter } from './post-start-input-writer.js';
|
|
4
|
-
export const buildOrchestratorReportPayload = (workerName, text, artifacts) => {
|
|
5
|
-
const lines = [
|
|
4
|
+
export const buildOrchestratorReportPayload = (workerName, text, artifacts, workflowsEnabled = false) => {
|
|
5
|
+
const lines = [`<hive-message kind="report" from="@${workerName}">`, text];
|
|
6
6
|
for (const artifact of artifacts)
|
|
7
7
|
lines.push(`artifact: ${artifact}`);
|
|
8
|
-
lines.push('',
|
|
8
|
+
lines.push('</hive-message>', '', buildOrchestratorReminderTail(workflowsEnabled), '');
|
|
9
9
|
return lines.join('\n');
|
|
10
10
|
};
|
|
11
|
-
export const buildOrchestratorStatusPayload = (workerName, text, artifacts) => {
|
|
12
|
-
const lines = [
|
|
11
|
+
export const buildOrchestratorStatusPayload = (workerName, text, artifacts, workflowsEnabled = false) => {
|
|
12
|
+
const lines = [`<hive-message kind="status" from="@${workerName}">`, text];
|
|
13
13
|
for (const artifact of artifacts)
|
|
14
14
|
lines.push(`artifact: ${artifact}`);
|
|
15
|
-
lines.push('',
|
|
15
|
+
lines.push('</hive-message>', '', buildOrchestratorReminderTail(workflowsEnabled), '');
|
|
16
16
|
return lines.join('\n');
|
|
17
17
|
};
|
|
18
|
-
export const buildOrchestratorUserInputPayload = (text) => [text, '',
|
|
18
|
+
export const buildOrchestratorUserInputPayload = (text, workflowsEnabled = false) => [text, '', buildOrchestratorReminderTail(workflowsEnabled), ''].join('\n');
|
|
19
19
|
export const buildWorkerDispatchPayload = (fromAgentName, workerDescription, dispatchId, text) => [
|
|
20
|
-
|
|
20
|
+
`<hive-message kind="dispatch" from="@${fromAgentName}">`,
|
|
21
21
|
'',
|
|
22
|
-
|
|
22
|
+
`Your role: ${workerDescription}`,
|
|
23
23
|
'',
|
|
24
|
-
'
|
|
25
|
-
`-
|
|
26
|
-
'-
|
|
24
|
+
'You must:',
|
|
25
|
+
`- When the task is done, failed, blocked, or partially done, run \`team report "<result>" --dispatch ${dispatchId}\``,
|
|
26
|
+
'- Do not do unrelated work; report as soon as you are done',
|
|
27
27
|
'',
|
|
28
28
|
`dispatch_id: ${dispatchId}`,
|
|
29
29
|
'',
|
|
30
|
-
'
|
|
30
|
+
'Task:',
|
|
31
31
|
text,
|
|
32
|
+
'</hive-message>',
|
|
32
33
|
'',
|
|
33
34
|
buildWorkerReminderTail(dispatchId),
|
|
34
35
|
'',
|
|
35
36
|
].join('\n');
|
|
36
37
|
export const buildWorkerCancelPayload = (dispatchId, reason) => [
|
|
37
|
-
|
|
38
|
+
`<hive-message kind="cancel" dispatch="${dispatchId}">`,
|
|
38
39
|
'',
|
|
39
|
-
'
|
|
40
|
+
'Stop working on this dispatch and do not call team report for it.',
|
|
40
41
|
'',
|
|
41
|
-
'
|
|
42
|
+
'Cancellation reason:',
|
|
42
43
|
reason,
|
|
44
|
+
'</hive-message>',
|
|
43
45
|
'',
|
|
44
46
|
].join('\n');
|
|
45
|
-
export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }) => {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, getWorkflowsEnabled, }) => {
|
|
48
|
+
const workflowsEnabled = () => getWorkflowsEnabled?.() ?? false;
|
|
49
|
+
const chains = new Map();
|
|
50
|
+
const getChain = (agentId) => {
|
|
51
|
+
let chain = chains.get(agentId);
|
|
52
|
+
if (!chain) {
|
|
53
|
+
chain = { busy: false, queue: [] };
|
|
54
|
+
chains.set(agentId, chain);
|
|
55
|
+
}
|
|
56
|
+
return chain;
|
|
57
|
+
};
|
|
58
|
+
const resolveActiveRun = (workspaceId, agentId) => registry
|
|
59
|
+
.list()
|
|
60
|
+
.filter((item) => item.agentId === agentId && getWorkspaceId(item.agentId) === workspaceId)
|
|
61
|
+
.sort((left, right) => right.startedAt - left.startedAt)
|
|
62
|
+
.find((item) => {
|
|
63
|
+
const status = syncRun(item).status;
|
|
64
|
+
return status === 'starting' || status === 'running';
|
|
65
|
+
});
|
|
66
|
+
// Synchronously enforce requireActiveRun (so writeSendPrompt still throws in
|
|
67
|
+
// the caller's stack when there is no live run), then return a thunk that
|
|
68
|
+
// re-resolves the run at EXECUTION time and performs the actual write,
|
|
69
|
+
// returning a promise that settles when the paste→submit sequence is done.
|
|
70
|
+
const prepareWrite = (workspaceId, agentId, text, input) => {
|
|
71
|
+
if (!resolveActiveRun(workspaceId, agentId)) {
|
|
56
72
|
if (input.requireActiveRun) {
|
|
57
73
|
throw new PtyInactiveError(`No active run for agent: ${agentId}`);
|
|
58
74
|
}
|
|
59
|
-
return;
|
|
75
|
+
return () => Promise.resolve();
|
|
60
76
|
}
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
77
|
+
return () => {
|
|
78
|
+
const run = resolveActiveRun(workspaceId, agentId);
|
|
79
|
+
if (!run) {
|
|
80
|
+
if (input.requireActiveRun) {
|
|
81
|
+
throw new PtyInactiveError(`No active run for agent: ${agentId}`);
|
|
82
|
+
}
|
|
83
|
+
return Promise.resolve();
|
|
65
84
|
}
|
|
66
|
-
|
|
85
|
+
try {
|
|
86
|
+
const config = getLaunchConfig(workspaceId, agentId);
|
|
87
|
+
if (agentManager && config) {
|
|
88
|
+
return (createPostStartInputWriter(agentManager, config.interactiveCommand ?? config.command)(run.runId, text).catch((error) => {
|
|
89
|
+
throw new PtyInactiveError(error instanceof Error ? error.message : String(error));
|
|
90
|
+
}) ?? Promise.resolve());
|
|
91
|
+
}
|
|
67
92
|
agentManager?.writeInput(run.runId, text);
|
|
93
|
+
return Promise.resolve();
|
|
68
94
|
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw new PtyInactiveError(error instanceof Error ? error.message : String(error));
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
const settle = (agentId, promise) => promise.finally(() => {
|
|
101
|
+
const chain = chains.get(agentId);
|
|
102
|
+
if (!chain)
|
|
103
|
+
return;
|
|
104
|
+
chain.busy = false;
|
|
105
|
+
drain(agentId);
|
|
106
|
+
});
|
|
107
|
+
const runQueuedWrite = (agentId, write) => {
|
|
108
|
+
try {
|
|
109
|
+
void settle(agentId, write.run()).then(write.resolve, write.reject);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
write.reject(error);
|
|
113
|
+
const chain = chains.get(agentId);
|
|
114
|
+
if (chain)
|
|
115
|
+
chain.busy = false;
|
|
116
|
+
drain(agentId);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function drain(agentId) {
|
|
120
|
+
const chain = chains.get(agentId);
|
|
121
|
+
if (!chain)
|
|
122
|
+
return;
|
|
123
|
+
if (chain.busy)
|
|
124
|
+
return;
|
|
125
|
+
const next = chain.queue.shift();
|
|
126
|
+
if (!next) {
|
|
127
|
+
chains.delete(agentId);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
chain.busy = true;
|
|
131
|
+
runQueuedWrite(agentId, next);
|
|
132
|
+
}
|
|
133
|
+
const writeToActiveAgentRun = (workspaceId, agentId, text, input = {}) => {
|
|
134
|
+
const thunk = prepareWrite(workspaceId, agentId, text, input);
|
|
135
|
+
const chain = getChain(agentId);
|
|
136
|
+
if (chain.busy) {
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
chain.queue.push({ reject, resolve, run: thunk });
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
chain.busy = true;
|
|
142
|
+
try {
|
|
143
|
+
return settle(agentId, thunk()); // uncontended: run now; immediate failures still throw
|
|
69
144
|
}
|
|
70
145
|
catch (error) {
|
|
71
|
-
|
|
146
|
+
chain.busy = false;
|
|
147
|
+
drain(agentId);
|
|
148
|
+
throw error;
|
|
72
149
|
}
|
|
73
150
|
};
|
|
151
|
+
const swallowQueuedFailure = (promise) => {
|
|
152
|
+
void promise.catch(() => {
|
|
153
|
+
// Deferred prompt writes can fail if the PTY exits while queued. Calls
|
|
154
|
+
// that require foreground error reporting use writeSendPrompt's promise.
|
|
155
|
+
});
|
|
156
|
+
};
|
|
74
157
|
return {
|
|
75
158
|
writeReportPrompt(workspaceId, workerName, text, artifacts, input = {}) {
|
|
76
|
-
writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts), input);
|
|
159
|
+
swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorReportPayload(workerName, text, artifacts, workflowsEnabled()), input));
|
|
77
160
|
},
|
|
78
161
|
writeStatusPrompt(workspaceId, workerName, text, artifacts, input = {}) {
|
|
79
|
-
writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts), input);
|
|
162
|
+
swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorStatusPayload(workerName, text, artifacts, workflowsEnabled()), input));
|
|
80
163
|
},
|
|
81
164
|
writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
|
|
82
|
-
writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
|
|
165
|
+
return writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
|
|
83
166
|
},
|
|
84
167
|
writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
|
|
85
|
-
writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input);
|
|
168
|
+
swallowQueuedFailure(writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input));
|
|
86
169
|
},
|
|
87
170
|
writeUserInputPrompt(workspaceId, text) {
|
|
88
|
-
writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text));
|
|
171
|
+
swallowQueuedFailure(writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text, workflowsEnabled())));
|
|
172
|
+
},
|
|
173
|
+
/** Generic: deliver an opaque text block to a specific agent's PTY.
|
|
174
|
+
* Used by the workflow runner to notify the triggering orchestrator
|
|
175
|
+
* when a run finishes (mirrors Claude Code's <task-notification>). */
|
|
176
|
+
writeSystemMessageToAgent(workspaceId, agentId, text) {
|
|
177
|
+
swallowQueuedFailure(writeToActiveAgentRun(workspaceId, agentId, text));
|
|
89
178
|
},
|
|
90
179
|
};
|
|
91
180
|
};
|
package/dist/src/server/app.d.ts
CHANGED
|
@@ -15,5 +15,6 @@ interface CreateAppOptions {
|
|
|
15
15
|
export declare const createApp: ({ store, pickFolderService, openWorkspaceService, packageVersionReader, tasksFileService, versionService, }: CreateAppOptions) => {
|
|
16
16
|
server: import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
17
17
|
store: RuntimeStore;
|
|
18
|
+
closeWebSockets: () => void;
|
|
18
19
|
};
|
|
19
20
|
export type { CreateAppOptions };
|
package/dist/src/server/app.js
CHANGED
|
@@ -196,6 +196,16 @@ export const createApp = ({ store, pickFolderService = pickFolder, openWorkspace
|
|
|
196
196
|
sendJson(response, 500, { error: message });
|
|
197
197
|
}
|
|
198
198
|
});
|
|
199
|
-
createTerminalWebSocketServer(server, store, tasksFileService);
|
|
200
|
-
return {
|
|
199
|
+
const wsServer = createTerminalWebSocketServer(server, store, tasksFileService);
|
|
200
|
+
return {
|
|
201
|
+
server,
|
|
202
|
+
store,
|
|
203
|
+
// Tear-down for the WebSocket layer. Callers must invoke this
|
|
204
|
+
// BEFORE awaiting `server.close()` if they want a prompt return:
|
|
205
|
+
// `server.close()` waits on every existing socket, and Node's
|
|
206
|
+
// `closeAllConnections()` does NOT terminate already-upgraded
|
|
207
|
+
// WebSocket clients. Without this hook a Ctrl+C in the Hive
|
|
208
|
+
// runtime hangs as long as any browser tab is connected.
|
|
209
|
+
closeWebSockets: wsServer.close,
|
|
210
|
+
};
|
|
201
211
|
};
|
|
@@ -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
|
+
};
|