stageflow 0.19.0 → 0.25.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/README.md +16 -3
- package/dist/a2a/configDiscovery.d.ts +9 -0
- package/dist/a2a/configDiscovery.js +18 -0
- package/dist/a2a/contracts.d.ts +93 -0
- package/dist/a2a/contracts.js +163 -0
- package/dist/a2a/limits.d.ts +14 -0
- package/dist/a2a/limits.js +29 -0
- package/dist/a2a/registry.d.ts +44 -0
- package/dist/a2a/registry.js +159 -0
- package/dist/a2a/server.d.ts +29 -0
- package/dist/a2a/server.js +341 -0
- package/dist/a2a/service.d.ts +97 -0
- package/dist/a2a/service.js +496 -0
- package/dist/a2a/store.d.ts +106 -0
- package/dist/a2a/store.js +245 -0
- package/dist/agent/activity.d.ts +5 -0
- package/dist/agent/activityObserver.d.ts +3 -0
- package/dist/agent/activityObserver.js +6 -1
- package/dist/agent/piAdapter.js +7 -3
- package/dist/agent/port.d.ts +2 -0
- package/dist/agent/providerInspect.d.ts +19 -0
- package/dist/agent/providerInspect.js +35 -0
- package/dist/agent/streamLogRedact.d.ts +2 -0
- package/dist/agent/streamLogRedact.js +13 -0
- package/dist/cli/a2aCommand.d.ts +8 -0
- package/dist/cli/a2aCommand.js +131 -0
- package/dist/cli/artifactCommand.js +2 -2
- package/dist/cli/envelopeCommand.js +2 -2
- package/dist/cli/exportRunCommand.js +2 -2
- package/dist/cli/hostClient.d.ts +43 -0
- package/dist/cli/hostClient.js +182 -0
- package/dist/cli/providersCommand.js +5 -3
- package/dist/cli/runCommand.d.ts +6 -5
- package/dist/cli/runCommand.js +23 -31
- package/dist/cli/runOutput.d.ts +1 -1
- package/dist/cli/runStageCommand.d.ts +33 -0
- package/dist/cli/runStageCommand.js +407 -0
- package/dist/cli/runsCommand.d.ts +3 -7
- package/dist/cli/runsCommand.js +33 -94
- package/dist/cli.js +20 -5
- package/dist/config/describePipeline.d.ts +26 -0
- package/dist/config/describePipeline.js +37 -0
- package/dist/config/loadPipeline.d.ts +13 -1
- package/dist/config/loadPipeline.js +34 -4
- package/dist/config/mergePipelineIncludes.d.ts +11 -0
- package/dist/config/mergePipelineIncludes.js +75 -0
- package/dist/config/validateCatalog.d.ts +2 -2
- package/dist/config/validateCatalog.js +24 -17
- package/dist/mcp/catalogTools.js +285 -52
- package/dist/mcp/controlTools.js +77 -19
- package/dist/mcp/deps.d.ts +3 -0
- package/dist/mcp/projectMcpTools.d.ts +3 -0
- package/dist/mcp/projectMcpTools.js +25 -0
- package/dist/mcp/providerTools.d.ts +3 -0
- package/dist/mcp/providerTools.js +17 -0
- package/dist/mcp/readArtifact.d.ts +9 -0
- package/dist/mcp/readArtifact.js +11 -0
- package/dist/mcp/server.js +9 -1
- package/dist/mcp/tailStreamLog.d.ts +8 -0
- package/dist/mcp/tailStreamLog.js +28 -0
- package/dist/mcp/toolResults.d.ts +17 -0
- package/dist/mcp/toolResults.js +15 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/mcp/waitRun.js +4 -4
- package/dist/mcp/waitingGates.d.ts +1 -0
- package/dist/mcp/waitingGates.js +3 -2
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/projection/projectRun.d.ts +3 -0
- package/dist/projection/projectRun.js +7 -0
- package/dist/runstore/createStore.d.ts +10 -0
- package/dist/runstore/createStore.js +13 -4
- package/dist/runstore/port.d.ts +17 -2
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +11 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +81 -26
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +6 -0
- package/dist/runstore/submission.d.ts +11 -0
- package/dist/runstore/submission.js +7 -0
- package/dist/runstore/workspaceLayout.d.ts +1 -0
- package/dist/runstore/workspaceLayout.js +3 -0
- package/dist/runtime/feedbackLoopCoordinator.d.ts +9 -1
- package/dist/runtime/feedbackLoopCoordinator.js +50 -20
- package/dist/runtime/feedbackLoopDecision.js +33 -1
- package/dist/runtime/pipelineRunner.d.ts +5 -3
- package/dist/runtime/pipelineRunner.js +6 -1
- package/dist/runtime/pipelineScheduler.js +32 -15
- package/dist/runtime/reloadRunCatalog.js +7 -1
- package/dist/runtime/resolveEnvelopeRef.d.ts +30 -0
- package/dist/runtime/resolveEnvelopeRef.js +79 -0
- package/dist/runtime/resumeReconstruct.js +2 -2
- package/dist/runtime/runManager.d.ts +24 -2
- package/dist/runtime/runManager.js +83 -19
- package/dist/runtime/settingsFile.d.ts +2 -0
- package/dist/runtime/settingsFile.js +19 -0
- package/dist/runtime/stageAttemptBootstrap.d.ts +3 -0
- package/dist/runtime/stageAttemptBootstrap.js +8 -2
- package/dist/runtime/stageStreamLog.d.ts +17 -0
- package/dist/runtime/stageStreamLog.js +89 -0
- package/dist/runtime/stageWorker.js +2 -1
- package/dist/server/bootstrap.d.ts +2 -0
- package/dist/server/bootstrap.js +22 -4
- package/dist/server/createHttpHost.js +6 -0
- package/dist/server/ensureGlobalService.d.ts +35 -0
- package/dist/server/ensureGlobalService.js +138 -0
- package/dist/server/http.d.ts +20 -1
- package/dist/server/http.js +450 -402
- package/dist/server/mcpHost.js +7 -8
- package/dist/server/operatorResults.d.ts +10 -0
- package/dist/server/operatorResults.js +24 -0
- package/dist/server/providerRoutes.d.ts +0 -6
- package/dist/server/providerRoutes.js +10 -18
- package/dist/types/pipeline.d.ts +8 -0
- package/dist/ui/assets/{index-DMVdl1qB.js → index-Da5EHU6M.js} +5 -5
- package/dist/ui/index.html +1 -1
- package/package.json +2 -1
- package/skills/stageflow/references/control-surface.md +2 -2
- package/skills/stageflow-run/SKILL.md +27 -9
- package/skills/stageflow-run/references/mcp-call.md +1 -1
- package/skills/stageflow-run/scripts/mcp-call.mjs +9 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { inspectProviderReadiness, mapProviderAuthError, } from "../agent/providerInspect.js";
|
|
3
|
+
import { textResult } from "./toolResults.js";
|
|
4
|
+
export function registerProviderTools(server, deps) {
|
|
5
|
+
server.registerTool("list_providers", {
|
|
6
|
+
description: "List login-capable model providers with auth readiness and a Pi-home detect summary. Read-only; does not log in or return secrets.",
|
|
7
|
+
inputSchema: z.object({}),
|
|
8
|
+
}, async () => {
|
|
9
|
+
try {
|
|
10
|
+
return textResult(await inspectProviderReadiness(deps.cwd, deps.providerAuthContext));
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
const mapped = mapProviderAuthError(err);
|
|
14
|
+
return textResult({ error: mapped.body.error, status: mapped.status }, true);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { RunStore } from "../runstore/port.js";
|
|
2
2
|
export declare function artifactMediaType(relativePath: string): string | undefined;
|
|
3
|
+
export type ClassifiedArtifactContent = {
|
|
4
|
+
kind: "image";
|
|
5
|
+
mimeType: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "utf8";
|
|
8
|
+
} | {
|
|
9
|
+
kind: "binary";
|
|
10
|
+
};
|
|
11
|
+
export declare function classifyArtifactContent(relativePath: string, bytes: Buffer): ClassifiedArtifactContent;
|
|
3
12
|
export declare function readRunArtifact(store: RunStore, runId: string, relativePath: string): Promise<string>;
|
|
4
13
|
export declare function readRunArtifactBytes(store: RunStore, runId: string, relativePath: string): Promise<Buffer>;
|
package/dist/mcp/readArtifact.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isUtf8 } from "node:buffer";
|
|
1
2
|
import { readFile, realpath } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { isInsideDir } from "../runstore/workspaceLayout.js";
|
|
@@ -28,6 +29,16 @@ export function artifactMediaType(relativePath) {
|
|
|
28
29
|
return undefined;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
export function classifyArtifactContent(relativePath, bytes) {
|
|
33
|
+
const mimeType = artifactMediaType(relativePath);
|
|
34
|
+
if (mimeType !== undefined) {
|
|
35
|
+
return { kind: "image", mimeType };
|
|
36
|
+
}
|
|
37
|
+
if (isUtf8(bytes)) {
|
|
38
|
+
return { kind: "utf8" };
|
|
39
|
+
}
|
|
40
|
+
return { kind: "binary" };
|
|
41
|
+
}
|
|
31
42
|
async function resolveRunArtifactFile(store, runId, relativePath) {
|
|
32
43
|
assertSafeRunId(runId);
|
|
33
44
|
if (typeof relativePath !== "string" || relativePath.trim().length === 0) {
|
package/dist/mcp/server.js
CHANGED
|
@@ -34,7 +34,15 @@ function sessionIdFromRequest(req) {
|
|
|
34
34
|
return undefined;
|
|
35
35
|
}
|
|
36
36
|
function toolDepsFrom(deps) {
|
|
37
|
-
return {
|
|
37
|
+
return {
|
|
38
|
+
manager: deps.manager,
|
|
39
|
+
store: deps.store,
|
|
40
|
+
cwd: deps.cwd,
|
|
41
|
+
...(deps.providerAuthContext !== undefined
|
|
42
|
+
? { providerAuthContext: deps.providerAuthContext }
|
|
43
|
+
: {}),
|
|
44
|
+
...(deps.projectRoot !== undefined ? { projectRoot: deps.projectRoot } : {}),
|
|
45
|
+
};
|
|
38
46
|
}
|
|
39
47
|
function attachBusNotifications(server, bus) {
|
|
40
48
|
return bus.on((event) => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type StreamLogTail = {
|
|
2
|
+
text: string;
|
|
3
|
+
nextOffset: number;
|
|
4
|
+
truncated?: boolean;
|
|
5
|
+
earliestOffset?: number;
|
|
6
|
+
};
|
|
7
|
+
/** Read new content from a stage's stream.log since a caller's last cursor. */
|
|
8
|
+
export declare function readStreamLogTail(streamLogPath: string, sinceOffset: number | undefined): Promise<StreamLogTail>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { parseStreamLogHeader } from "../runtime/stageStreamLog.js";
|
|
3
|
+
/** Read new content from a stage's stream.log since a caller's last cursor. */
|
|
4
|
+
export async function readStreamLogTail(streamLogPath, sinceOffset) {
|
|
5
|
+
let raw;
|
|
6
|
+
try {
|
|
7
|
+
raw = await readFile(streamLogPath);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return { text: "", nextOffset: 0 };
|
|
11
|
+
}
|
|
12
|
+
const { base, headerLength } = parseStreamLogHeader(raw);
|
|
13
|
+
const contentBytes = raw.subarray(headerLength);
|
|
14
|
+
const eof = base + contentBytes.length;
|
|
15
|
+
if (sinceOffset === undefined || sinceOffset < base) {
|
|
16
|
+
const truncated = sinceOffset !== undefined && sinceOffset < base;
|
|
17
|
+
return {
|
|
18
|
+
text: contentBytes.toString("utf8"),
|
|
19
|
+
nextOffset: eof,
|
|
20
|
+
...(truncated ? { truncated: true, earliestOffset: base } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (sinceOffset >= eof) {
|
|
24
|
+
return { text: "", nextOffset: eof };
|
|
25
|
+
}
|
|
26
|
+
const slice = contentBytes.subarray(sinceOffset - base);
|
|
27
|
+
return { text: slice.toString("utf8"), nextOffset: eof };
|
|
28
|
+
}
|
|
@@ -5,3 +5,20 @@ export declare function textResult(data: unknown, isError?: boolean): {
|
|
|
5
5
|
}[];
|
|
6
6
|
isError?: boolean | undefined;
|
|
7
7
|
};
|
|
8
|
+
export declare function imageResult(mimeType: string, bytes: Buffer, identity: {
|
|
9
|
+
runId: string;
|
|
10
|
+
path: string;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
}): {
|
|
13
|
+
content: ({
|
|
14
|
+
type: "image";
|
|
15
|
+
mimeType: string;
|
|
16
|
+
data: string;
|
|
17
|
+
text?: undefined;
|
|
18
|
+
} | {
|
|
19
|
+
mimeType?: undefined;
|
|
20
|
+
data?: undefined;
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
})[];
|
|
24
|
+
};
|
package/dist/mcp/toolResults.js
CHANGED
|
@@ -4,3 +4,18 @@ export function textResult(data, isError = false) {
|
|
|
4
4
|
...(isError ? { isError: true } : {}),
|
|
5
5
|
};
|
|
6
6
|
}
|
|
7
|
+
export function imageResult(mimeType, bytes, identity) {
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "image",
|
|
12
|
+
mimeType,
|
|
13
|
+
data: bytes.toString("base64"),
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: "text",
|
|
17
|
+
text: JSON.stringify(identity, null, 2),
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
package/dist/mcp/tools.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { registerCatalogTools } from "./catalogTools.js";
|
|
3
3
|
import { registerControlTools } from "./controlTools.js";
|
|
4
|
+
import { registerProjectMcpTools } from "./projectMcpTools.js";
|
|
5
|
+
import { registerProviderTools } from "./providerTools.js";
|
|
4
6
|
import { textResult } from "./toolResults.js";
|
|
5
7
|
import { DEFAULT_TIMEOUT_MS, waitRun } from "./waitRun.js";
|
|
6
8
|
export function registerMcpTools(server, deps) {
|
|
7
9
|
const { store } = deps;
|
|
8
10
|
registerCatalogTools(server, deps);
|
|
9
11
|
registerControlTools(server, deps);
|
|
12
|
+
registerProviderTools(server, deps);
|
|
13
|
+
registerProjectMcpTools(server, deps);
|
|
10
14
|
server.registerTool("wait_run", {
|
|
11
15
|
description: "Long-poll until a run is waiting for HITL input and/or terminal (succeeded/failed), or until timeout_ms. Default until=any wakes on waiting OR terminal. Abort cancels only this wait (not the run). Optional notifications/progress when the client supplies _meta.progressToken. Compose: wait_run → answer_gate → wait_run.",
|
|
12
16
|
inputSchema: z.object({
|
package/dist/mcp/waitRun.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapStoreLookupError } from "../server/operatorResults.js";
|
|
1
2
|
import { projectRunForMcp } from "./projectRun.js";
|
|
2
3
|
export const DEFAULT_TIMEOUT_MS = 60_000;
|
|
3
4
|
export const MAX_TIMEOUT_MS = 240_000;
|
|
@@ -90,12 +91,11 @@ export async function waitRun(opts) {
|
|
|
90
91
|
detail = await opts.store.readRun(opts.runId);
|
|
91
92
|
}
|
|
92
93
|
catch (err) {
|
|
93
|
-
const
|
|
94
|
-
const notFound = /not found|no such|unknown run/i.test(message);
|
|
94
|
+
const mapped = mapStoreLookupError(err, { policy: "run" });
|
|
95
95
|
return {
|
|
96
96
|
ok: false,
|
|
97
|
-
error:
|
|
98
|
-
status:
|
|
97
|
+
error: mapped.error,
|
|
98
|
+
status: mapped.status,
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
const run = projectRunForMcp(detail);
|
package/dist/mcp/waitingGates.js
CHANGED
|
@@ -83,8 +83,9 @@ export async function projectWaitingGates(store, opts) {
|
|
|
83
83
|
return projectGatesForRun(detail, detail);
|
|
84
84
|
}
|
|
85
85
|
const summaries = await store.listRuns();
|
|
86
|
-
const waiting = summaries.filter((r) => (
|
|
87
|
-
r.
|
|
86
|
+
const waiting = summaries.filter((r) => (opts?.projectRoot === undefined || r.project_root === opts.projectRoot) &&
|
|
87
|
+
((r.waiting_stage_ids !== undefined && r.waiting_stage_ids.length > 0) ||
|
|
88
|
+
r.waiting_stage_id !== undefined));
|
|
88
89
|
const perRun = await Promise.all(waiting.map(async (summary) => {
|
|
89
90
|
let detail;
|
|
90
91
|
try {
|
package/dist/package-meta.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME = "stageflow";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.
|
|
2
|
+
export declare const PACKAGE_VERSION = "0.25.0";
|
package/dist/package-meta.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const PACKAGE_NAME = "stageflow";
|
|
2
|
-
export const PACKAGE_VERSION = "0.
|
|
2
|
+
export const PACKAGE_VERSION = "0.25.0";
|
|
@@ -16,6 +16,8 @@ export type StageProjection = {
|
|
|
16
16
|
artifacts: string[];
|
|
17
17
|
last_at?: string;
|
|
18
18
|
pending_prompt?: AskOperatorPrompt;
|
|
19
|
+
definition_id?: string;
|
|
20
|
+
cost_usd?: number;
|
|
19
21
|
};
|
|
20
22
|
export type RunProjection = {
|
|
21
23
|
run_id: string;
|
|
@@ -40,6 +42,7 @@ export type RunProjection = {
|
|
|
40
42
|
failed_reason?: RunSummary["failed_reason"];
|
|
41
43
|
active_feedback_loop?: FeedbackLoopRecord;
|
|
42
44
|
feedback_loops: FeedbackLoopHistory[];
|
|
45
|
+
total_cost_usd?: number;
|
|
43
46
|
};
|
|
44
47
|
export declare function projectRun(detail: RunDetail): RunProjection;
|
|
45
48
|
export { projectRun as projectRunForMcp };
|
|
@@ -44,6 +44,9 @@ export function projectRun(detail) {
|
|
|
44
44
|
...(detail.active_feedback_loop !== undefined
|
|
45
45
|
? { active_feedback_loop: detail.active_feedback_loop }
|
|
46
46
|
: {}),
|
|
47
|
+
...(detail.total_cost_usd !== undefined
|
|
48
|
+
? { total_cost_usd: detail.total_cost_usd }
|
|
49
|
+
: {}),
|
|
47
50
|
feedback_loops: detail.feedback_loops ?? [],
|
|
48
51
|
stages: detail.stages.map((stage) => ({
|
|
49
52
|
stage_id: stage.stage_id,
|
|
@@ -69,6 +72,10 @@ export function projectRun(detail) {
|
|
|
69
72
|
...(stage.pending_prompt
|
|
70
73
|
? { pending_prompt: stage.pending_prompt }
|
|
71
74
|
: {}),
|
|
75
|
+
...(stage.definition_id !== undefined
|
|
76
|
+
? { definition_id: stage.definition_id }
|
|
77
|
+
: {}),
|
|
78
|
+
...(stage.cost_usd !== undefined ? { cost_usd: stage.cost_usd } : {}),
|
|
72
79
|
})),
|
|
73
80
|
};
|
|
74
81
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
1
2
|
import type { RunStore } from "./port.js";
|
|
2
3
|
export type RunStoreKind = "sqlite";
|
|
3
4
|
export type RunStoreConfig = {
|
|
@@ -7,6 +8,15 @@ export type RunStoreConfig = {
|
|
|
7
8
|
kind?: RunStoreKind | "disk";
|
|
8
9
|
};
|
|
9
10
|
export declare const DISK_STORE_REJECTED = "SF_STORE=disk is no longer a live RunStore. SQLite is the only adapter. Disk-era .stageflow/runs trees import automatically when the SQLite store is empty.";
|
|
11
|
+
/**
|
|
12
|
+
* Composition-root factory: hands back the concrete SQLite connection alongside the `RunStore`,
|
|
13
|
+
* for the one caller wiring a second, colocated store (A2A's tables) into the same `state.db`
|
|
14
|
+
* file. Ordinary call sites use `createRunStore` below and never see this.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createRunStoreWithConnection(config: RunStoreConfig): {
|
|
17
|
+
store: RunStore;
|
|
18
|
+
connection: Database.Database;
|
|
19
|
+
};
|
|
10
20
|
/**
|
|
11
21
|
* Factory at the application edge. Call sites should receive the returned `RunStore`
|
|
12
22
|
* and must not branch on backend kind.
|
|
@@ -11,13 +11,22 @@ function resolveKind(kind) {
|
|
|
11
11
|
return "sqlite";
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Composition-root factory: hands back the concrete SQLite connection alongside the `RunStore`,
|
|
15
|
+
* for the one caller wiring a second, colocated store (A2A's tables) into the same `state.db`
|
|
16
|
+
* file. Ordinary call sites use `createRunStore` below and never see this.
|
|
16
17
|
*/
|
|
17
|
-
export function
|
|
18
|
+
export function createRunStoreWithConnection(config) {
|
|
18
19
|
resolveKind(config.kind);
|
|
19
20
|
migrateLegacyStoreRoot(config.rootDir);
|
|
20
21
|
const storeRoot = storeRootFor(config.rootDir);
|
|
21
22
|
mkdirSync(storeRoot, { recursive: true });
|
|
22
|
-
|
|
23
|
+
const store = new SqliteRunStore(storeRoot);
|
|
24
|
+
return { store, connection: store.connection };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Factory at the application edge. Call sites should receive the returned `RunStore`
|
|
28
|
+
* and must not branch on backend kind.
|
|
29
|
+
*/
|
|
30
|
+
export function createRunStore(config) {
|
|
31
|
+
return createRunStoreWithConnection(config).store;
|
|
23
32
|
}
|
package/dist/runstore/port.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { StageLogLine } from "../agent/activity.js";
|
|
2
|
+
import type { RunSubmission, RunSubmissionRecord } from "./submission.js";
|
|
2
3
|
import type { AskOperatorPrompt } from "../tools/askOperator.js";
|
|
3
4
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
4
|
-
import type { FeedbackLoopConfig, ResolvedPipelineDag } from "../types/pipeline.js";
|
|
5
|
+
import type { FeedbackLoopConfig, InlinePipelineDefinition, ResolvedPipelineDag } from "../types/pipeline.js";
|
|
5
6
|
import type { CompletionCheck } from "../types/completion.js";
|
|
6
7
|
import type { StageGateKind } from "../types/stage.js";
|
|
7
8
|
import type { StageUsage } from "../types/usage.js";
|
|
@@ -51,6 +52,14 @@ export type RunMeta = {
|
|
|
51
52
|
pipeline_path?: string;
|
|
52
53
|
task_path?: string;
|
|
53
54
|
project_root?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The raw pipeline body for a run started from an inline pipeline
|
|
57
|
+
* (no pipeline_path). Lets a fresh stage-worker process — which has no
|
|
58
|
+
* memory of the original in-process call — reconstruct the pipeline
|
|
59
|
+
* without needing a catalog file, mirroring how task_yaml already lets
|
|
60
|
+
* task reconstruction work without a task_path.
|
|
61
|
+
*/
|
|
62
|
+
inline_pipeline?: InlinePipelineDefinition;
|
|
54
63
|
};
|
|
55
64
|
export type CreatedRun = {
|
|
56
65
|
runId: string;
|
|
@@ -275,6 +284,7 @@ export type FeedbackLoopHistory = {
|
|
|
275
284
|
fork_generations: ForkGenerationRecord[];
|
|
276
285
|
};
|
|
277
286
|
export type CreateRunInput = {
|
|
287
|
+
submission?: RunSubmission;
|
|
278
288
|
pipelineId: string;
|
|
279
289
|
taskYaml: string;
|
|
280
290
|
taskId?: string;
|
|
@@ -286,6 +296,8 @@ export type CreateRunInput = {
|
|
|
286
296
|
pipelinePath?: string;
|
|
287
297
|
taskPath?: string;
|
|
288
298
|
projectRoot?: string;
|
|
299
|
+
/** Raw inline pipeline body, persisted only when pipelinePath is absent. */
|
|
300
|
+
inlinePipeline?: InlinePipelineDefinition;
|
|
289
301
|
};
|
|
290
302
|
export type ListRunsFilter = {
|
|
291
303
|
status?: RunStatus;
|
|
@@ -301,6 +313,7 @@ export type ListRunsFilter = {
|
|
|
301
313
|
* run id is all you have (catalog / rehydrate).
|
|
302
314
|
*/
|
|
303
315
|
export interface RunStore {
|
|
316
|
+
getRunBySubmission(key: string): Promise<RunSubmissionRecord | null>;
|
|
304
317
|
createRun(input: CreateRunInput): Promise<CreatedRun>;
|
|
305
318
|
updateRunStatus(runId: string, status: RunStatus): Promise<void>;
|
|
306
319
|
readRunMeta(runId: string): Promise<RunMeta>;
|
|
@@ -327,12 +340,14 @@ export interface RunStore {
|
|
|
327
340
|
writeEnvelope(runId: string, stageId: string, envelope: StageEnvelope, options?: {
|
|
328
341
|
attempt?: number;
|
|
329
342
|
}): Promise<void>;
|
|
330
|
-
readEnvelope(runId: string, stageId: string): Promise<StageEnvelope>;
|
|
343
|
+
readEnvelope(runId: string, stageId: string, attempt?: number): Promise<StageEnvelope>;
|
|
331
344
|
appendStageEvent(runId: string, stageId: string, event: StageLogLine, options?: {
|
|
332
345
|
attempt?: number;
|
|
333
346
|
}): Promise<void>;
|
|
334
347
|
listStageEvents(runId: string, stageId: string, attempt?: number): Promise<StageLogEvent[]>;
|
|
335
348
|
listRuns(filter?: ListRunsFilter): Promise<RunSummary[]>;
|
|
349
|
+
/** Every distinct non-empty project_root recorded across all runs. */
|
|
350
|
+
listProjectRoots(): Promise<string[]>;
|
|
336
351
|
readRun(runId: string): Promise<RunDetail>;
|
|
337
352
|
updatePipelineDag(runId: string, dag: RunPipelineDagSnapshot): Promise<void>;
|
|
338
353
|
createFeedbackLoop(runId: string, input: CreateFeedbackLoopInput): Promise<FeedbackLoopRecord>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
1
2
|
import type { StageEnvelope } from "../../types/envelope.js";
|
|
2
3
|
import type { StageLogLine } from "../../agent/activity.js";
|
|
3
4
|
import { type CreateFeedbackLoopInput, type CreateFeedbackReplayInput, type CreateFeedbackReplayStagePassInput, type CreateForkGenerationInput, type CreateRunInput, type CreatedRun, type FeedbackLoopPatch, type FeedbackLoopRecord, type FeedbackLoopState, type FeedbackReplayPatch, type FeedbackReplayRecord, type FeedbackReplayStagePassPatch, type FeedbackReplayStagePassRecord, type ForkGenerationPatch, type ForkGenerationRecord, type ListRunsFilter, type RunDetail, type RunMeta, type RunPipelineDagSnapshot, type RunStatus, type RunStore, type RunSummary, type StageExecution, type StageExecutionPatch, type StageLogEvent, type VerificationCheckResult, type VerificationCheckResultPatch } from "../port.js";
|
|
5
|
+
import { type RunSubmissionRecord } from "../submission.js";
|
|
4
6
|
export declare class SqliteRunStore implements RunStore {
|
|
5
7
|
private readonly storeRoot;
|
|
6
8
|
private readonly db;
|
|
@@ -8,8 +10,15 @@ export declare class SqliteRunStore implements RunStore {
|
|
|
8
10
|
constructor(storeRoot: string);
|
|
9
11
|
/** Await one-shot disk import before catalog reads (create paths also wait). */
|
|
10
12
|
ready(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* The connection this store owns, for the one caller allowed to share it: the composition root
|
|
15
|
+
* wiring the A2A tables into the same `state.db` file. Not part of the `RunStore` interface.
|
|
16
|
+
*/
|
|
17
|
+
get connection(): Database.Database;
|
|
11
18
|
getWorkspaceDir(runId: string): string;
|
|
12
19
|
createRun(input: CreateRunInput): Promise<CreatedRun>;
|
|
20
|
+
private readSubmission;
|
|
21
|
+
getRunBySubmission(key: string): Promise<RunSubmissionRecord | null>;
|
|
13
22
|
updateRunStatus(runId: string, status: RunStatus): Promise<void>;
|
|
14
23
|
updatePipelineDag(runId: string, dag: RunPipelineDagSnapshot): Promise<void>;
|
|
15
24
|
readRunMeta(runId: string): Promise<RunMeta>;
|
|
@@ -29,7 +38,7 @@ export declare class SqliteRunStore implements RunStore {
|
|
|
29
38
|
writeEnvelope(runId: string, stageId: string, envelope: StageEnvelope, options?: {
|
|
30
39
|
attempt?: number;
|
|
31
40
|
}): Promise<void>;
|
|
32
|
-
readEnvelope(runId: string, stageId: string): Promise<StageEnvelope>;
|
|
41
|
+
readEnvelope(runId: string, stageId: string, attempt?: number): Promise<StageEnvelope>;
|
|
33
42
|
private readEnvelopeFromDb;
|
|
34
43
|
appendStageEvent(runId: string, stageId: string, event: StageLogLine, options?: {
|
|
35
44
|
attempt?: number;
|
|
@@ -43,6 +52,7 @@ export declare class SqliteRunStore implements RunStore {
|
|
|
43
52
|
private updateStageStatusDenorm;
|
|
44
53
|
listStageEvents(runId: string, stageId: string, attempt?: number): Promise<StageLogEvent[]>;
|
|
45
54
|
listRuns(filter?: ListRunsFilter): Promise<RunSummary[]>;
|
|
55
|
+
listProjectRoots(): Promise<string[]>;
|
|
46
56
|
readRun(runId: string): Promise<RunDetail>;
|
|
47
57
|
createFeedbackLoop(runId: string, input: CreateFeedbackLoopInput): Promise<FeedbackLoopRecord>;
|
|
48
58
|
getFeedbackLoop(runId: string, loopId: string): Promise<FeedbackLoopRecord>;
|
|
@@ -9,6 +9,7 @@ import { newRunId, runWorkspaceDir } from "../paths.js";
|
|
|
9
9
|
import { attemptAgentDir, attemptArtifactsDir, stageDir, } from "../workspaceLayout.js";
|
|
10
10
|
import { importDiskRunsIfEmpty } from "./migrateFromDisk.js";
|
|
11
11
|
import { SCHEMA_SQL } from "./schema.js";
|
|
12
|
+
import { RunSubmissionExistsError } from "../submission.js";
|
|
12
13
|
const ensuredStageDirs = new Set();
|
|
13
14
|
const DEFAULT_SQLITE_BUSY_TIMEOUT_MS = 5000;
|
|
14
15
|
function readSqliteBusyTimeoutMs() {
|
|
@@ -52,6 +53,12 @@ function ensureRunLocatorColumns(db) {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
}
|
|
56
|
+
function ensureInlinePipelineColumn(db) {
|
|
57
|
+
const cols = db.prepare(`PRAGMA table_info(runs)`).all();
|
|
58
|
+
if (!cols.some((c) => c.name === "inline_pipeline_json")) {
|
|
59
|
+
db.exec(`ALTER TABLE runs ADD COLUMN inline_pipeline_json TEXT`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
55
62
|
function ensureStageExecutionsTable(db) {
|
|
56
63
|
db.exec(`
|
|
57
64
|
CREATE TABLE IF NOT EXISTS stage_executions (
|
|
@@ -304,6 +311,7 @@ export class SqliteRunStore {
|
|
|
304
311
|
ensureCiIdentityColumns(this.db);
|
|
305
312
|
ensurePipelineDagColumn(this.db);
|
|
306
313
|
ensureRunLocatorColumns(this.db);
|
|
314
|
+
ensureInlinePipelineColumn(this.db);
|
|
307
315
|
ensureStageExecutionsTable(this.db);
|
|
308
316
|
ensureStageExecutionVerificationOutcomeColumn(this.db);
|
|
309
317
|
ensureStageExecutionCostColumns(this.db);
|
|
@@ -319,6 +327,13 @@ export class SqliteRunStore {
|
|
|
319
327
|
async ready() {
|
|
320
328
|
await this.migratePromise;
|
|
321
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* The connection this store owns, for the one caller allowed to share it: the composition root
|
|
332
|
+
* wiring the A2A tables into the same `state.db` file. Not part of the `RunStore` interface.
|
|
333
|
+
*/
|
|
334
|
+
get connection() {
|
|
335
|
+
return this.db;
|
|
336
|
+
}
|
|
322
337
|
getWorkspaceDir(runId) {
|
|
323
338
|
return runWorkspaceDir(this.storeRoot, runId);
|
|
324
339
|
}
|
|
@@ -337,32 +352,55 @@ export class SqliteRunStore {
|
|
|
337
352
|
const projectRoot = input.projectRoot
|
|
338
353
|
? normalizeCatalogPath(input.projectRoot)
|
|
339
354
|
: null;
|
|
340
|
-
this.db
|
|
341
|
-
.
|
|
342
|
-
|
|
355
|
+
this.db.transaction(() => {
|
|
356
|
+
if (input.submission) {
|
|
357
|
+
const existing = this.readSubmission(input.submission.key);
|
|
358
|
+
if (existing)
|
|
359
|
+
throw new RunSubmissionExistsError(existing);
|
|
360
|
+
}
|
|
361
|
+
this.db
|
|
362
|
+
.prepare(`INSERT INTO runs
|
|
363
|
+
(run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json)
|
|
343
364
|
VALUES
|
|
344
|
-
(@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root)`)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
365
|
+
(@run_id, @pipeline_id, @task_id, @task_yaml, @status, @created_at, @updated_at, @checkout_root, @pipeline_dag_json, @git_sha, @ci_pr_url, @ci_job_url, @pipeline_path, @task_path, @project_root, @inline_pipeline_json)`)
|
|
366
|
+
.run({
|
|
367
|
+
run_id: runId,
|
|
368
|
+
pipeline_id: input.pipelineId,
|
|
369
|
+
task_id: input.taskId ?? null,
|
|
370
|
+
task_yaml: input.taskYaml,
|
|
371
|
+
status: "running",
|
|
372
|
+
created_at: now,
|
|
373
|
+
updated_at: now,
|
|
374
|
+
checkout_root: input.checkoutRoot ?? null,
|
|
375
|
+
pipeline_dag_json: input.pipelineDag
|
|
376
|
+
? JSON.stringify(input.pipelineDag)
|
|
377
|
+
: null,
|
|
378
|
+
git_sha: input.gitSha ?? null,
|
|
379
|
+
ci_pr_url: input.ciPrUrl ?? null,
|
|
380
|
+
ci_job_url: input.ciJobUrl ?? null,
|
|
381
|
+
pipeline_path: pipelinePath,
|
|
382
|
+
task_path: taskPath,
|
|
383
|
+
project_root: projectRoot,
|
|
384
|
+
inline_pipeline_json: input.inlinePipeline
|
|
385
|
+
? JSON.stringify(input.inlinePipeline)
|
|
386
|
+
: null,
|
|
387
|
+
});
|
|
388
|
+
if (input.submission) {
|
|
389
|
+
this.db.prepare("INSERT INTO run_submissions (submission_key, request_hash, run_id) VALUES (?, ?, ?)")
|
|
390
|
+
.run(input.submission.key, input.submission.requestHash, runId);
|
|
391
|
+
}
|
|
392
|
+
})();
|
|
364
393
|
return { runId, workspaceDir };
|
|
365
394
|
}
|
|
395
|
+
readSubmission(key) {
|
|
396
|
+
const row = this.db.prepare("SELECT submission_key AS key, request_hash AS requestHash, run_id AS runId FROM run_submissions WHERE submission_key = ?")
|
|
397
|
+
.get(key);
|
|
398
|
+
return row ?? null;
|
|
399
|
+
}
|
|
400
|
+
async getRunBySubmission(key) {
|
|
401
|
+
await this.ready();
|
|
402
|
+
return this.readSubmission(key);
|
|
403
|
+
}
|
|
366
404
|
async updateRunStatus(runId, status) {
|
|
367
405
|
await this.ready();
|
|
368
406
|
const result = this.db
|
|
@@ -606,8 +644,15 @@ export class SqliteRunStore {
|
|
|
606
644
|
});
|
|
607
645
|
await this.updateStageExecution(runId, stageId, attempt, { envelope });
|
|
608
646
|
}
|
|
609
|
-
async readEnvelope(runId, stageId) {
|
|
647
|
+
async readEnvelope(runId, stageId, attempt) {
|
|
610
648
|
await this.ready();
|
|
649
|
+
if (attempt !== undefined) {
|
|
650
|
+
const execution = await this.getStageExecution(runId, stageId, attempt);
|
|
651
|
+
if (execution.envelope != null) {
|
|
652
|
+
return execution.envelope;
|
|
653
|
+
}
|
|
654
|
+
throw new Error(`Envelope not found: ${runId}/${stageId}`);
|
|
655
|
+
}
|
|
611
656
|
const execution = await this.getLatestStageExecution(runId, stageId);
|
|
612
657
|
if (execution?.envelope != null) {
|
|
613
658
|
return execution.envelope;
|
|
@@ -703,7 +748,7 @@ export class SqliteRunStore {
|
|
|
703
748
|
}
|
|
704
749
|
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
705
750
|
const rows = this.db
|
|
706
|
-
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root
|
|
751
|
+
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json
|
|
707
752
|
FROM runs ${where} ORDER BY created_at DESC`)
|
|
708
753
|
.all(...params);
|
|
709
754
|
const summaries = [];
|
|
@@ -717,6 +762,13 @@ export class SqliteRunStore {
|
|
|
717
762
|
}
|
|
718
763
|
return summaries;
|
|
719
764
|
}
|
|
765
|
+
async listProjectRoots() {
|
|
766
|
+
await this.ready();
|
|
767
|
+
const rows = this.db
|
|
768
|
+
.prepare(`SELECT DISTINCT project_root FROM runs WHERE project_root IS NOT NULL AND project_root != ''`)
|
|
769
|
+
.all();
|
|
770
|
+
return rows.map((row) => row.project_root);
|
|
771
|
+
}
|
|
720
772
|
async readRun(runId) {
|
|
721
773
|
await this.ready();
|
|
722
774
|
const row = this.getRunRow(runId);
|
|
@@ -1125,11 +1177,14 @@ export class SqliteRunStore {
|
|
|
1125
1177
|
...(row.task_path != null ? { task_path: row.task_path } : {}),
|
|
1126
1178
|
...(row.project_root != null ? { project_root: row.project_root } : {}),
|
|
1127
1179
|
...(pipeline_dag ? { pipeline_dag } : {}),
|
|
1180
|
+
...(row.inline_pipeline_json != null
|
|
1181
|
+
? { inline_pipeline: JSON.parse(row.inline_pipeline_json) }
|
|
1182
|
+
: {}),
|
|
1128
1183
|
};
|
|
1129
1184
|
}
|
|
1130
1185
|
getRunRow(runId) {
|
|
1131
1186
|
const row = this.db
|
|
1132
|
-
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root
|
|
1187
|
+
.prepare(`SELECT run_id, pipeline_id, task_id, task_yaml, status, created_at, updated_at, checkout_root, pipeline_dag_json, git_sha, ci_pr_url, ci_job_url, pipeline_path, task_path, project_root, inline_pipeline_json
|
|
1133
1188
|
FROM runs WHERE run_id = ?`)
|
|
1134
1189
|
.get(runId);
|
|
1135
1190
|
if (!row)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS runs (\n run_id TEXT PRIMARY KEY,\n pipeline_id TEXT NOT NULL,\n task_id TEXT,\n task_yaml TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n checkout_root TEXT,\n pipeline_dag_json TEXT,\n git_sha TEXT,\n ci_pr_url TEXT,\n ci_job_url TEXT,\n pipeline_path TEXT,\n task_path TEXT,\n project_root TEXT\n);\n\nCREATE TABLE IF NOT EXISTS stages (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n status TEXT,\n summary TEXT,\n envelope_json TEXT,\n started_at TEXT,\n finished_at TEXT,\n PRIMARY KEY (run_id, stage_id),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE TABLE IF NOT EXISTS stage_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n at TEXT NOT NULL,\n event TEXT NOT NULL,\n payload_json TEXT,\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_runs_status_created\n ON runs (status, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS idx_runs_pipeline_created\n ON runs (pipeline_id, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS idx_stage_events_run_stage_at\n ON stage_events (run_id, stage_id, at);\n\nCREATE TABLE IF NOT EXISTS stage_executions (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n attempt INTEGER NOT NULL,\n status TEXT NOT NULL,\n verification_outcome TEXT NOT NULL DEFAULT 'not_run',\n started_at TEXT,\n finished_at TEXT,\n envelope_json TEXT,\n cost_usd REAL,\n usage_json TEXT,\n PRIMARY KEY (run_id, stage_id, attempt),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_stage_executions_run_stage\n ON stage_executions (run_id, stage_id, attempt);\n\nCREATE TABLE IF NOT EXISTS verification_check_results (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n attempt INTEGER NOT NULL,\n check_id TEXT NOT NULL,\n check_type TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT,\n evidence_json TEXT,\n PRIMARY KEY (run_id, stage_id, attempt, check_id),\n FOREIGN KEY (run_id, stage_id, attempt)\n REFERENCES stage_executions(run_id, stage_id, attempt)\n);\n\nCREATE INDEX IF NOT EXISTS idx_verification_check_results_execution\n ON verification_check_results (run_id, stage_id, attempt, check_id);\n\nCREATE TABLE IF NOT EXISTS feedback_loops (\n run_id TEXT NOT NULL,\n loop_id TEXT NOT NULL,\n source_stage_id TEXT NOT NULL,\n source_attempt INTEGER NOT NULL,\n policy_json TEXT NOT NULL,\n state TEXT NOT NULL,\n current_replay_id TEXT,\n current_replay_number INTEGER,\n deferred_send_back_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, loop_id),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_feedback_loops_run_state\n ON feedback_loops (run_id, state, created_at);\n\nCREATE TABLE IF NOT EXISTS feedback_replays (\n run_id TEXT NOT NULL,\n replay_id TEXT NOT NULL,\n loop_id TEXT NOT NULL,\n source_stage_id TEXT NOT NULL,\n source_attempt INTEGER NOT NULL,\n target_stage_id TEXT NOT NULL,\n replay_number INTEGER NOT NULL,\n max_replays INTEGER NOT NULL,\n replay_session TEXT NOT NULL,\n route_stage_ids_json TEXT NOT NULL,\n feedback_envelope_json TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, replay_id),\n FOREIGN KEY (run_id, loop_id) REFERENCES feedback_loops(run_id, loop_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_feedback_replays_loop_number\n ON feedback_replays (run_id, loop_id, replay_number);\nCREATE INDEX IF NOT EXISTS idx_feedback_replays_run_loop\n ON feedback_replays (run_id, loop_id, created_at);\n\nCREATE TABLE IF NOT EXISTS feedback_replay_stage_passes (\n run_id TEXT NOT NULL,\n replay_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n stage_attempt INTEGER NOT NULL,\n session_origin_attempt INTEGER,\n session_mode TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT,\n emitted_envelope_json TEXT,\n PRIMARY KEY (run_id, replay_id, stage_id),\n FOREIGN KEY (run_id, replay_id) REFERENCES feedback_replays(run_id, replay_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_feedback_replay_stage_passes_replay\n ON feedback_replay_stage_passes (run_id, replay_id, stage_id);\n\nCREATE TABLE IF NOT EXISTS fork_generations (\n run_id TEXT NOT NULL,\n generation_id TEXT NOT NULL,\n replay_id TEXT,\n fork_parent_stage_id TEXT NOT NULL,\n generation_number INTEGER NOT NULL,\n clone_stage_ids_json TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, generation_id),\n FOREIGN KEY (run_id, replay_id) REFERENCES feedback_replays(run_id, replay_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_fork_generations_parent_number\n ON fork_generations (run_id, fork_parent_stage_id, generation_number);\nCREATE INDEX IF NOT EXISTS idx_fork_generations_run_replay\n ON fork_generations (run_id, replay_id, created_at);\n";
|
|
1
|
+
export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS runs (\n run_id TEXT PRIMARY KEY,\n pipeline_id TEXT NOT NULL,\n task_id TEXT,\n task_yaml TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n checkout_root TEXT,\n pipeline_dag_json TEXT,\n git_sha TEXT,\n ci_pr_url TEXT,\n ci_job_url TEXT,\n pipeline_path TEXT,\n task_path TEXT,\n project_root TEXT\n);\n\nCREATE TABLE IF NOT EXISTS run_submissions (\n submission_key TEXT PRIMARY KEY,\n request_hash TEXT NOT NULL,\n run_id TEXT NOT NULL UNIQUE REFERENCES runs(run_id)\n);\n\nCREATE TABLE IF NOT EXISTS stages (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n status TEXT,\n summary TEXT,\n envelope_json TEXT,\n started_at TEXT,\n finished_at TEXT,\n PRIMARY KEY (run_id, stage_id),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE TABLE IF NOT EXISTS stage_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n at TEXT NOT NULL,\n event TEXT NOT NULL,\n payload_json TEXT,\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_runs_status_created\n ON runs (status, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS idx_runs_pipeline_created\n ON runs (pipeline_id, created_at DESC);\n\nCREATE INDEX IF NOT EXISTS idx_stage_events_run_stage_at\n ON stage_events (run_id, stage_id, at);\n\nCREATE TABLE IF NOT EXISTS stage_executions (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n attempt INTEGER NOT NULL,\n status TEXT NOT NULL,\n verification_outcome TEXT NOT NULL DEFAULT 'not_run',\n started_at TEXT,\n finished_at TEXT,\n envelope_json TEXT,\n cost_usd REAL,\n usage_json TEXT,\n PRIMARY KEY (run_id, stage_id, attempt),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_stage_executions_run_stage\n ON stage_executions (run_id, stage_id, attempt);\n\nCREATE TABLE IF NOT EXISTS verification_check_results (\n run_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n attempt INTEGER NOT NULL,\n check_id TEXT NOT NULL,\n check_type TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT,\n evidence_json TEXT,\n PRIMARY KEY (run_id, stage_id, attempt, check_id),\n FOREIGN KEY (run_id, stage_id, attempt)\n REFERENCES stage_executions(run_id, stage_id, attempt)\n);\n\nCREATE INDEX IF NOT EXISTS idx_verification_check_results_execution\n ON verification_check_results (run_id, stage_id, attempt, check_id);\n\nCREATE TABLE IF NOT EXISTS feedback_loops (\n run_id TEXT NOT NULL,\n loop_id TEXT NOT NULL,\n source_stage_id TEXT NOT NULL,\n source_attempt INTEGER NOT NULL,\n policy_json TEXT NOT NULL,\n state TEXT NOT NULL,\n current_replay_id TEXT,\n current_replay_number INTEGER,\n deferred_send_back_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, loop_id),\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_feedback_loops_run_state\n ON feedback_loops (run_id, state, created_at);\n\nCREATE TABLE IF NOT EXISTS feedback_replays (\n run_id TEXT NOT NULL,\n replay_id TEXT NOT NULL,\n loop_id TEXT NOT NULL,\n source_stage_id TEXT NOT NULL,\n source_attempt INTEGER NOT NULL,\n target_stage_id TEXT NOT NULL,\n replay_number INTEGER NOT NULL,\n max_replays INTEGER NOT NULL,\n replay_session TEXT NOT NULL,\n route_stage_ids_json TEXT NOT NULL,\n feedback_envelope_json TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, replay_id),\n FOREIGN KEY (run_id, loop_id) REFERENCES feedback_loops(run_id, loop_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_feedback_replays_loop_number\n ON feedback_replays (run_id, loop_id, replay_number);\nCREATE INDEX IF NOT EXISTS idx_feedback_replays_run_loop\n ON feedback_replays (run_id, loop_id, created_at);\n\nCREATE TABLE IF NOT EXISTS feedback_replay_stage_passes (\n run_id TEXT NOT NULL,\n replay_id TEXT NOT NULL,\n stage_id TEXT NOT NULL,\n stage_attempt INTEGER NOT NULL,\n session_origin_attempt INTEGER,\n session_mode TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT,\n emitted_envelope_json TEXT,\n PRIMARY KEY (run_id, replay_id, stage_id),\n FOREIGN KEY (run_id, replay_id) REFERENCES feedback_replays(run_id, replay_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_feedback_replay_stage_passes_replay\n ON feedback_replay_stage_passes (run_id, replay_id, stage_id);\n\nCREATE TABLE IF NOT EXISTS fork_generations (\n run_id TEXT NOT NULL,\n generation_id TEXT NOT NULL,\n replay_id TEXT,\n fork_parent_stage_id TEXT NOT NULL,\n generation_number INTEGER NOT NULL,\n clone_stage_ids_json TEXT NOT NULL,\n status TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (run_id, generation_id),\n FOREIGN KEY (run_id, replay_id) REFERENCES feedback_replays(run_id, replay_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_fork_generations_parent_number\n ON fork_generations (run_id, fork_parent_stage_id, generation_number);\nCREATE INDEX IF NOT EXISTS idx_fork_generations_run_replay\n ON fork_generations (run_id, replay_id, created_at);\n";
|
|
@@ -17,6 +17,12 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
17
17
|
project_root TEXT
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
+
CREATE TABLE IF NOT EXISTS run_submissions (
|
|
21
|
+
submission_key TEXT PRIMARY KEY,
|
|
22
|
+
request_hash TEXT NOT NULL,
|
|
23
|
+
run_id TEXT NOT NULL UNIQUE REFERENCES runs(run_id)
|
|
24
|
+
);
|
|
25
|
+
|
|
20
26
|
CREATE TABLE IF NOT EXISTS stages (
|
|
21
27
|
run_id TEXT NOT NULL,
|
|
22
28
|
stage_id TEXT NOT NULL,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type RunSubmission = {
|
|
2
|
+
key: string;
|
|
3
|
+
requestHash: string;
|
|
4
|
+
};
|
|
5
|
+
export type RunSubmissionRecord = RunSubmission & {
|
|
6
|
+
runId: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class RunSubmissionExistsError extends Error {
|
|
9
|
+
readonly submission: RunSubmissionRecord;
|
|
10
|
+
constructor(submission: RunSubmissionRecord);
|
|
11
|
+
}
|