@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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const serializeLiveAgentRun = (run) => ({
|
|
2
|
+
agent_id: run.agentId,
|
|
3
|
+
exit_code: run.exitCode,
|
|
4
|
+
output: run.output,
|
|
5
|
+
pid: run.pid,
|
|
6
|
+
run_id: run.runId,
|
|
7
|
+
started_at: run.startedAt,
|
|
8
|
+
status: run.status,
|
|
9
|
+
});
|
|
10
|
+
export const serializeWorkflowRun = (run) => ({
|
|
11
|
+
agent_count: run.agentCount,
|
|
12
|
+
args: run.args,
|
|
13
|
+
created_at: run.createdAt,
|
|
14
|
+
error: run.error,
|
|
15
|
+
finished_at: run.finishedAt,
|
|
16
|
+
id: run.id,
|
|
17
|
+
name: run.name,
|
|
18
|
+
parent_run_id: run.parentRunId,
|
|
19
|
+
phase: run.phase,
|
|
20
|
+
result: run.result,
|
|
21
|
+
script_hash: run.scriptHash,
|
|
22
|
+
script_path: run.scriptPath,
|
|
23
|
+
started_at: run.startedAt,
|
|
24
|
+
status: run.status,
|
|
25
|
+
workspace_id: run.workspaceId,
|
|
26
|
+
});
|
|
27
|
+
export const serializeWorkflowDispatch = (dispatch) => ({
|
|
28
|
+
artifacts: dispatch.artifacts,
|
|
29
|
+
created_at: dispatch.createdAt,
|
|
30
|
+
delivered_at: dispatch.deliveredAt,
|
|
31
|
+
from_agent_id: dispatch.fromAgentId,
|
|
32
|
+
id: dispatch.id,
|
|
33
|
+
label: dispatch.label,
|
|
34
|
+
last_pty_line: dispatch.lastPtyLine ?? null,
|
|
35
|
+
phase: dispatch.phase,
|
|
36
|
+
reported_at: dispatch.reportedAt,
|
|
37
|
+
report_text: dispatch.reportText,
|
|
38
|
+
sequence: dispatch.sequence,
|
|
39
|
+
status: dispatch.status,
|
|
40
|
+
step_index: dispatch.stepIndex,
|
|
41
|
+
submitted_at: dispatch.submittedAt,
|
|
42
|
+
text: dispatch.text,
|
|
43
|
+
to_agent_id: dispatch.toAgentId,
|
|
44
|
+
workflow_run_id: dispatch.workflowRunId,
|
|
45
|
+
workspace_id: dispatch.workspaceId,
|
|
46
|
+
});
|
|
47
|
+
export const serializeWorkflowSchedule = (schedule) => ({
|
|
48
|
+
args: schedule.args,
|
|
49
|
+
created_at: schedule.createdAt,
|
|
50
|
+
cron: schedule.cron,
|
|
51
|
+
enabled: schedule.enabled,
|
|
52
|
+
id: schedule.id,
|
|
53
|
+
last_run_at: schedule.lastRunAt,
|
|
54
|
+
next_run_at: schedule.nextRunAt,
|
|
55
|
+
script_path: schedule.scriptPath,
|
|
56
|
+
updated_at: schedule.updatedAt,
|
|
57
|
+
workspace_id: schedule.workspaceId,
|
|
58
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface WorkflowRunLogRecord {
|
|
3
|
+
id: number;
|
|
4
|
+
runId: string;
|
|
5
|
+
ts: number;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const createWorkflowRunLogStore: (db: Database) => {
|
|
9
|
+
append(runId: string, message: string, ts?: number): void;
|
|
10
|
+
listForRun(runId: string): WorkflowRunLogRecord[];
|
|
11
|
+
/** Last `n` log messages for the run, oldest-first. Used by the
|
|
12
|
+
* onRunFinished reminder to include a short narrator tail in the
|
|
13
|
+
* orchestrator's completion notification without overwhelming it. */
|
|
14
|
+
tailForRun(runId: string, n: number): string[];
|
|
15
|
+
deleteForRun(runId: string): void;
|
|
16
|
+
/** Cascade hook: deleted alongside workflow_runs when a workspace
|
|
17
|
+
* is removed (TIER 1 #4 cascade). */
|
|
18
|
+
deleteForWorkspace(workspaceId: string): void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* TIER 2 #3 — narrator lane storage. `log()` calls from a workflow script
|
|
2
|
+
* append here; the Drawer polls listForRun(runId) alongside the dispatch
|
|
3
|
+
* timeline; the orchestrator's completion reminder splices in the last
|
|
4
|
+
* few lines so a run that finished with a long sequence of `log()` calls
|
|
5
|
+
* can be summarised back to the user.
|
|
6
|
+
*
|
|
7
|
+
* Append-only. No retention policy yet — TIER 3 work if log volume grows
|
|
8
|
+
* to where it matters; CC's Workflow tool keeps logs for the run's
|
|
9
|
+
* lifetime so we mirror that. */
|
|
10
|
+
export const createWorkflowRunLogStore = (db) => {
|
|
11
|
+
const insert = db.prepare('INSERT INTO workflow_run_logs (run_id, ts, message) VALUES (?, ?, ?)');
|
|
12
|
+
const listStmt = db.prepare('SELECT id, run_id, ts, message FROM workflow_run_logs WHERE run_id = ? ORDER BY id');
|
|
13
|
+
const tailStmt = db.prepare('SELECT message FROM workflow_run_logs WHERE run_id = ? ORDER BY id DESC LIMIT ?');
|
|
14
|
+
const deleteForRunStmt = db.prepare('DELETE FROM workflow_run_logs WHERE run_id = ?');
|
|
15
|
+
const deleteForWorkspaceStmt = db.prepare(`DELETE FROM workflow_run_logs
|
|
16
|
+
WHERE run_id IN (SELECT id FROM workflow_runs WHERE workspace_id = ?)`);
|
|
17
|
+
return {
|
|
18
|
+
append(runId, message, ts = Date.now()) {
|
|
19
|
+
insert.run(runId, ts, message);
|
|
20
|
+
},
|
|
21
|
+
listForRun(runId) {
|
|
22
|
+
return listStmt.all(runId).map((row) => ({
|
|
23
|
+
id: row.id,
|
|
24
|
+
runId: row.run_id,
|
|
25
|
+
ts: row.ts,
|
|
26
|
+
message: row.message,
|
|
27
|
+
}));
|
|
28
|
+
},
|
|
29
|
+
/** Last `n` log messages for the run, oldest-first. Used by the
|
|
30
|
+
* onRunFinished reminder to include a short narrator tail in the
|
|
31
|
+
* orchestrator's completion notification without overwhelming it. */
|
|
32
|
+
tailForRun(runId, n) {
|
|
33
|
+
const rows = tailStmt.all(runId, n);
|
|
34
|
+
return rows.map((r) => r.message).reverse();
|
|
35
|
+
},
|
|
36
|
+
deleteForRun(runId) {
|
|
37
|
+
deleteForRunStmt.run(runId);
|
|
38
|
+
},
|
|
39
|
+
/** Cascade hook: deleted alongside workflow_runs when a workspace
|
|
40
|
+
* is removed (TIER 1 #4 cascade). */
|
|
41
|
+
deleteForWorkspace(workspaceId) {
|
|
42
|
+
deleteForWorkspaceStmt.run(workspaceId);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export type WorkflowRunStatus = 'running' | 'completed' | 'failed' | 'interrupted' | 'stopped';
|
|
3
|
+
export interface WorkflowRunRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
workspaceId: string;
|
|
6
|
+
scriptPath: string;
|
|
7
|
+
scriptHash: string | null;
|
|
8
|
+
name: string;
|
|
9
|
+
status: WorkflowRunStatus;
|
|
10
|
+
phase: string | null;
|
|
11
|
+
args: unknown;
|
|
12
|
+
result: unknown;
|
|
13
|
+
startedAt: number;
|
|
14
|
+
finishedAt: number | null;
|
|
15
|
+
error: string | null;
|
|
16
|
+
createdAt: number;
|
|
17
|
+
/** Count of `agent()` calls dispatched by this run. TIER 1 #14 — lets the
|
|
18
|
+
* Drawer show "12 agents" on the row without an extra round-trip per
|
|
19
|
+
* expand. Cheap subquery against the indexed workflow_run_id column. */
|
|
20
|
+
agentCount: number;
|
|
21
|
+
/** TIER 2 #5: parent workflow run id for nested workflow() calls.
|
|
22
|
+
* Null on top-level runs. The Drawer uses this to render a child run
|
|
23
|
+
* indented under its parent (and to collapse/expand together). */
|
|
24
|
+
parentRunId: string | null;
|
|
25
|
+
}
|
|
26
|
+
interface CreateRunInput {
|
|
27
|
+
workspaceId: string;
|
|
28
|
+
scriptPath: string;
|
|
29
|
+
name: string;
|
|
30
|
+
scriptHash?: string;
|
|
31
|
+
args?: unknown;
|
|
32
|
+
/** TIER 2 #5 — set when this run is being created from a nested
|
|
33
|
+
* workflow() call. Null/omitted for top-level runs. */
|
|
34
|
+
parentRunId?: string | null;
|
|
35
|
+
}
|
|
36
|
+
interface UpdateRunInput {
|
|
37
|
+
status?: WorkflowRunStatus;
|
|
38
|
+
phase?: string;
|
|
39
|
+
finishedAt?: number;
|
|
40
|
+
error?: string;
|
|
41
|
+
result?: unknown;
|
|
42
|
+
}
|
|
43
|
+
export declare const createWorkflowRunStore: (db: Database) => {
|
|
44
|
+
createRun: (input: CreateRunInput) => WorkflowRunRecord;
|
|
45
|
+
updateRun: (id: string, input: UpdateRunInput) => void;
|
|
46
|
+
getRun: (id: string) => WorkflowRunRecord | undefined;
|
|
47
|
+
listWorkspaceRuns: (workspaceId: string) => WorkflowRunRecord[];
|
|
48
|
+
markUnfinishedRunsInterrupted: () => void;
|
|
49
|
+
};
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
const parseArgs = (value) => {
|
|
3
|
+
if (!value)
|
|
4
|
+
return null;
|
|
5
|
+
try {
|
|
6
|
+
return JSON.parse(value);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const toRecord = (row) => ({
|
|
13
|
+
id: row.id,
|
|
14
|
+
workspaceId: row.workspace_id,
|
|
15
|
+
scriptPath: row.script_path,
|
|
16
|
+
scriptHash: row.script_hash,
|
|
17
|
+
name: row.name,
|
|
18
|
+
status: row.status,
|
|
19
|
+
phase: row.phase,
|
|
20
|
+
args: parseArgs(row.args),
|
|
21
|
+
result: parseArgs(row.result),
|
|
22
|
+
startedAt: row.started_at,
|
|
23
|
+
finishedAt: row.finished_at,
|
|
24
|
+
error: row.error,
|
|
25
|
+
createdAt: row.created_at,
|
|
26
|
+
agentCount: Number(row.agent_count ?? 0),
|
|
27
|
+
parentRunId: row.parent_run_id ?? null,
|
|
28
|
+
});
|
|
29
|
+
// Selects every workflow_runs column plus the agent_count subquery; used by
|
|
30
|
+
// both getRun and listWorkspaceRuns so the WorkflowRunRecord shape is
|
|
31
|
+
// uniform regardless of which path produced it.
|
|
32
|
+
const SELECT_RUN_COLUMNS = 'workflow_runs.*, ' +
|
|
33
|
+
'(SELECT COUNT(*) FROM dispatches WHERE dispatches.workflow_run_id = workflow_runs.id) AS agent_count';
|
|
34
|
+
export const createWorkflowRunStore = (db) => {
|
|
35
|
+
const createRun = (input) => {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const record = {
|
|
38
|
+
id: randomUUID(),
|
|
39
|
+
workspaceId: input.workspaceId,
|
|
40
|
+
scriptPath: input.scriptPath,
|
|
41
|
+
scriptHash: input.scriptHash ?? null,
|
|
42
|
+
name: input.name,
|
|
43
|
+
status: 'running',
|
|
44
|
+
phase: null,
|
|
45
|
+
args: input.args ?? null,
|
|
46
|
+
result: null,
|
|
47
|
+
startedAt: now,
|
|
48
|
+
finishedAt: null,
|
|
49
|
+
error: null,
|
|
50
|
+
createdAt: now,
|
|
51
|
+
agentCount: 0,
|
|
52
|
+
parentRunId: input.parentRunId ?? null,
|
|
53
|
+
};
|
|
54
|
+
db.prepare(`INSERT INTO workflow_runs (
|
|
55
|
+
id, workspace_id, script_path, script_hash, name, status, phase, args,
|
|
56
|
+
started_at, finished_at, error, created_at, parent_run_id
|
|
57
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(record.id, record.workspaceId, record.scriptPath, record.scriptHash, record.name, record.status, record.phase, record.args === null ? null : JSON.stringify(record.args), record.startedAt, record.finishedAt, record.error, record.createdAt, record.parentRunId);
|
|
58
|
+
return record;
|
|
59
|
+
};
|
|
60
|
+
const updateRun = (id, input) => {
|
|
61
|
+
const sets = [];
|
|
62
|
+
const values = [];
|
|
63
|
+
if (input.status !== undefined) {
|
|
64
|
+
sets.push('status = ?');
|
|
65
|
+
values.push(input.status);
|
|
66
|
+
}
|
|
67
|
+
if (input.phase !== undefined) {
|
|
68
|
+
sets.push('phase = ?');
|
|
69
|
+
values.push(input.phase);
|
|
70
|
+
}
|
|
71
|
+
if (input.finishedAt !== undefined) {
|
|
72
|
+
sets.push('finished_at = ?');
|
|
73
|
+
values.push(input.finishedAt);
|
|
74
|
+
}
|
|
75
|
+
if (input.error !== undefined) {
|
|
76
|
+
sets.push('error = ?');
|
|
77
|
+
values.push(input.error);
|
|
78
|
+
}
|
|
79
|
+
if (input.result !== undefined) {
|
|
80
|
+
sets.push('result = ?');
|
|
81
|
+
values.push(input.result === null ? null : JSON.stringify(input.result));
|
|
82
|
+
}
|
|
83
|
+
if (sets.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
values.push(id);
|
|
86
|
+
db.prepare(`UPDATE workflow_runs SET ${sets.join(', ')} WHERE id = ?`).run(...values);
|
|
87
|
+
};
|
|
88
|
+
const getRun = (id) => {
|
|
89
|
+
const row = db
|
|
90
|
+
.prepare(`SELECT ${SELECT_RUN_COLUMNS} FROM workflow_runs WHERE id = ?`)
|
|
91
|
+
.get(id);
|
|
92
|
+
return row ? toRecord(row) : undefined;
|
|
93
|
+
};
|
|
94
|
+
const listWorkspaceRuns = (workspaceId) => db
|
|
95
|
+
.prepare(`SELECT ${SELECT_RUN_COLUMNS} FROM workflow_runs WHERE workspace_id = ? ORDER BY created_at DESC, id DESC`)
|
|
96
|
+
.all(workspaceId).map(toRecord);
|
|
97
|
+
// Boot sweep: a run still 'running' after a restart can never resume, so mark
|
|
98
|
+
// it interrupted (spec §13 — the UI offers Resume; we never auto-resume).
|
|
99
|
+
const markUnfinishedRunsInterrupted = () => {
|
|
100
|
+
db.prepare("UPDATE workflow_runs SET status = 'interrupted', finished_at = ? WHERE status = 'running'").run(Date.now());
|
|
101
|
+
};
|
|
102
|
+
return { createRun, updateRun, getRun, listWorkspaceRuns, markUnfinishedRunsInterrupted };
|
|
103
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { WorkerRole } from '../shared/types.js';
|
|
2
|
+
import type { AgentLaunchConfigInput } from './agent-run-store.js';
|
|
3
|
+
import { type WorkflowCliPolicy } from './workflow-cli-policy.js';
|
|
4
|
+
import type { WorkflowDispatchAwaiter } from './workflow-dispatch-awaiter.js';
|
|
5
|
+
import type { WorkflowRunRecord, WorkflowRunStatus } from './workflow-run-store.js';
|
|
6
|
+
export interface RunWorkflowInput {
|
|
7
|
+
workspaceId: string;
|
|
8
|
+
scriptPath: string;
|
|
9
|
+
hivePort: string;
|
|
10
|
+
args?: unknown;
|
|
11
|
+
/** Agent (usually the orchestrator) that fired this workflow; the runner
|
|
12
|
+
* notifies its PTY when the run finishes. Optional — workflows fired by
|
|
13
|
+
* cron / UI have no triggering agent. */
|
|
14
|
+
triggeredByAgentId?: string;
|
|
15
|
+
/** TIER 2 #5 — set internally when the runner is spawning a nested
|
|
16
|
+
* workflow() from inside another run. External callers leave it
|
|
17
|
+
* undefined; the row goes in as a top-level run. */
|
|
18
|
+
parentRunId?: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface RunInlineWorkflowInput {
|
|
21
|
+
workspaceId: string;
|
|
22
|
+
source: string;
|
|
23
|
+
/** Synthetic path stamped into workflow_runs.script_path for display only;
|
|
24
|
+
* no file is read or written. Defaults to `<inline>` if omitted. */
|
|
25
|
+
scriptPath?: string;
|
|
26
|
+
hivePort: string;
|
|
27
|
+
args?: unknown;
|
|
28
|
+
triggeredByAgentId?: string;
|
|
29
|
+
}
|
|
30
|
+
/** TIER 2 #4 — narrow port the runner needs to clone a custom role
|
|
31
|
+
* into an ephemeral worker. Returns `undefined` if the name doesn't
|
|
32
|
+
* match any template (built-in or custom); the runner falls back to
|
|
33
|
+
* built-in-role semantics in that case. */
|
|
34
|
+
export interface RoleTemplateResolver {
|
|
35
|
+
findByName(name: string): {
|
|
36
|
+
name: string;
|
|
37
|
+
roleType: WorkerRole | 'orchestrator';
|
|
38
|
+
defaultCommand: string;
|
|
39
|
+
defaultArgs: string[];
|
|
40
|
+
} | undefined;
|
|
41
|
+
}
|
|
42
|
+
interface RunnerStorePort {
|
|
43
|
+
addWorkerWithLaunch: (workspaceId: string, input: {
|
|
44
|
+
name: string;
|
|
45
|
+
role: WorkerRole;
|
|
46
|
+
ephemeral: true;
|
|
47
|
+
spawnedBy: 'workflow';
|
|
48
|
+
}, launchConfig: AgentLaunchConfigInput) => {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
};
|
|
52
|
+
startAgent: (workspaceId: string, agentId: string, input: {
|
|
53
|
+
hivePort: string;
|
|
54
|
+
}) => Promise<unknown>;
|
|
55
|
+
dispatchTaskByWorkerName: (workspaceId: string, workerName: string, text: string, input: {
|
|
56
|
+
fromAgentId: string;
|
|
57
|
+
hivePort: string;
|
|
58
|
+
workflowRunId: string;
|
|
59
|
+
stepIndex: number;
|
|
60
|
+
phase?: string;
|
|
61
|
+
label?: string;
|
|
62
|
+
}) => Promise<{
|
|
63
|
+
id: string;
|
|
64
|
+
}>;
|
|
65
|
+
deleteWorker: (workspaceId: string, workerId: string) => void;
|
|
66
|
+
}
|
|
67
|
+
/** TIER 2 #3 — narrator lane sink. The runner calls append(runId, message)
|
|
68
|
+
* every time the script invokes log(). Implementation lives in
|
|
69
|
+
* workflow-run-log-store; the port keeps the runner free of DB types. */
|
|
70
|
+
export interface WorkflowRunLogPort {
|
|
71
|
+
append(runId: string, message: string, ts?: number): void;
|
|
72
|
+
}
|
|
73
|
+
interface WorkflowRunStorePort {
|
|
74
|
+
createRun: (input: {
|
|
75
|
+
workspaceId: string;
|
|
76
|
+
scriptPath: string;
|
|
77
|
+
name: string;
|
|
78
|
+
scriptHash?: string;
|
|
79
|
+
args?: unknown;
|
|
80
|
+
parentRunId?: string | null;
|
|
81
|
+
}) => WorkflowRunRecord;
|
|
82
|
+
updateRun: (id: string, input: {
|
|
83
|
+
status?: WorkflowRunStatus;
|
|
84
|
+
phase?: string;
|
|
85
|
+
finishedAt?: number;
|
|
86
|
+
error?: string;
|
|
87
|
+
result?: unknown;
|
|
88
|
+
}) => void;
|
|
89
|
+
getRun: (id: string) => WorkflowRunRecord | undefined;
|
|
90
|
+
}
|
|
91
|
+
export interface WorkflowRunner {
|
|
92
|
+
/** Runs the script to completion; returns the FINAL record. Used by tests
|
|
93
|
+
* and any caller that wants to wait synchronously. */
|
|
94
|
+
runWorkflow: (input: RunWorkflowInput) => Promise<WorkflowRunRecord>;
|
|
95
|
+
/** Creates the run row + kicks off execution in the background; returns the
|
|
96
|
+
* INITIAL ('running') record. Used by the HTTP route so the response is
|
|
97
|
+
* fast — clients poll `getWorkflowRun(id)` for progress. */
|
|
98
|
+
startWorkflow: (input: RunWorkflowInput) => Promise<WorkflowRunRecord>;
|
|
99
|
+
/** Like startWorkflow but takes raw source (no file). Used by `team workflow
|
|
100
|
+
* run --stdin/--inline` so the orchestrator can fire workflows from a PTY
|
|
101
|
+
* without writing a file first — matches Claude Code's Workflow tool
|
|
102
|
+
* invocation model. */
|
|
103
|
+
startWorkflowInline: (input: RunInlineWorkflowInput) => Promise<WorkflowRunRecord>;
|
|
104
|
+
/** Cancel any in-flight `agent()` calls for `runId` (rejects their awaiters)
|
|
105
|
+
* and mark the next executeWorkflow catch as 'stopped' instead of 'failed'.
|
|
106
|
+
* Returns true if the run was running and got stopped, false otherwise. */
|
|
107
|
+
stopRun: (runId: string) => boolean;
|
|
108
|
+
}
|
|
109
|
+
interface ListDispatchesForStopPort {
|
|
110
|
+
listOpenDispatchIdsForRun: (runId: string) => string[];
|
|
111
|
+
}
|
|
112
|
+
export declare const createWorkflowRunner: (deps: {
|
|
113
|
+
store: RunnerStorePort;
|
|
114
|
+
workflowRunStore: WorkflowRunStorePort;
|
|
115
|
+
awaiter: WorkflowDispatchAwaiter;
|
|
116
|
+
dispatchPort: ListDispatchesForStopPort;
|
|
117
|
+
/** Resolves the workspace's on-disk path. The nested `workflow(name)` DSL
|
|
118
|
+
* call needs it to locate sibling scripts when the parent run was fired
|
|
119
|
+
* inline via `team workflow run --stdin` (TIER 1 #7) — its scriptPath is
|
|
120
|
+
* a synthetic `<inline>` token that dirname() can't traverse. */
|
|
121
|
+
resolveWorkspacePath: (workspaceId: string) => string;
|
|
122
|
+
/** TIER 2 #4 — used when agent() opts.agentType isn't a built-in role.
|
|
123
|
+
* The runner asks the resolver for a matching custom template; on hit
|
|
124
|
+
* the template's command + args replace the defaults, on miss the
|
|
125
|
+
* runner throws a clear error rather than silently spawning claude. */
|
|
126
|
+
roleTemplateResolver: RoleTemplateResolver;
|
|
127
|
+
/** TIER 2 #3 — sink for the script's `log()` calls. The runner used
|
|
128
|
+
* to drop them on server stdout; routing through this port lets the
|
|
129
|
+
* Drawer render them as a narrator lane and the completion
|
|
130
|
+
* reminder splice the tail into the orchestrator's notification. */
|
|
131
|
+
logStore: WorkflowRunLogPort;
|
|
132
|
+
/** Global workflow CLI policy (default + allowlist). Replaces the old
|
|
133
|
+
* hard-coded `claude` default: an `agent()` that omits `cli` now uses
|
|
134
|
+
* the user's configured default, and an explicit `cli` outside the
|
|
135
|
+
* allowlist fails the call with a clear, fixable error. */
|
|
136
|
+
getWorkflowCliPolicy: () => WorkflowCliPolicy;
|
|
137
|
+
/** Called when a run reaches a terminal state (completed/failed/stopped).
|
|
138
|
+
* The runtime uses this to inject a `<hive-system-reminder>` into the
|
|
139
|
+
* triggering agent's PTY so the orchestrator picks the result back up,
|
|
140
|
+
* mirroring Claude Code's `<task-notification>` flow. */
|
|
141
|
+
onRunFinished?: (input: {
|
|
142
|
+
runId: string;
|
|
143
|
+
triggeredByAgentId: string;
|
|
144
|
+
finalRecord: WorkflowRunRecord;
|
|
145
|
+
}) => void;
|
|
146
|
+
}) => WorkflowRunner;
|
|
147
|
+
export {};
|