stageflow 0.27.0 → 0.30.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 +4 -0
- package/builtin-skills/browser/SKILL.md +42 -0
- package/dist/agent/claudeAdapter.js +2 -2
- package/dist/agent/cursorProvider.d.ts +2 -0
- package/dist/agent/cursorProvider.js +30 -5
- package/dist/agent/fakeAgent.d.ts +1 -0
- package/dist/agent/fakeAgent.js +13 -0
- package/dist/agent/piAdapter.d.ts +3 -24
- package/dist/agent/piAdapter.js +49 -47
- package/dist/agent/piSessionFactory.d.ts +38 -0
- package/dist/agent/piSessionFactory.js +60 -0
- package/dist/agent/port.d.ts +2 -0
- package/dist/agent/streamLogRedact.d.ts +6 -0
- package/dist/agent/streamLogRedact.js +23 -1
- package/dist/browser/anchor.d.ts +27 -0
- package/dist/browser/anchor.js +127 -0
- package/dist/browser/auditSink.d.ts +38 -0
- package/dist/browser/auditSink.js +34 -0
- package/dist/browser/browserHost.d.ts +86 -0
- package/dist/browser/browserHost.js +7 -0
- package/dist/browser/browserSweep.d.ts +14 -0
- package/dist/browser/browserSweep.js +54 -0
- package/dist/browser/browserTeardown.d.ts +56 -0
- package/dist/browser/browserTeardown.js +235 -0
- package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -0
- package/dist/browser/fakeRemoteBrowserHost.js +34 -0
- package/dist/browser/gateHandoff.d.ts +25 -0
- package/dist/browser/gateHandoff.js +83 -0
- package/dist/browser/humanLogin.d.ts +18 -0
- package/dist/browser/humanLogin.js +34 -0
- package/dist/browser/keyProvider.d.ts +10 -0
- package/dist/browser/keyProvider.js +39 -0
- package/dist/browser/localBrowserHost.d.ts +10 -0
- package/dist/browser/localBrowserHost.js +152 -0
- package/dist/browser/localProfileLock.d.ts +2 -0
- package/dist/browser/localProfileLock.js +218 -0
- package/dist/browser/localProfileStore.d.ts +5 -0
- package/dist/browser/localProfileStore.js +91 -0
- package/dist/browser/loginCheck.d.ts +53 -0
- package/dist/browser/loginCheck.js +147 -0
- package/dist/browser/memoryProfileLock.d.ts +2 -0
- package/dist/browser/memoryProfileLock.js +53 -0
- package/dist/browser/memoryProfileStore.d.ts +2 -0
- package/dist/browser/memoryProfileStore.js +31 -0
- package/dist/browser/navigationAudit.d.ts +16 -0
- package/dist/browser/navigationAudit.js +53 -0
- package/dist/browser/persistedEnv.d.ts +3 -0
- package/dist/browser/persistedEnv.js +15 -0
- package/dist/browser/profileLock.d.ts +40 -0
- package/dist/browser/profileLock.js +10 -0
- package/dist/browser/profileStore.d.ts +23 -0
- package/dist/browser/profileStore.js +39 -0
- package/dist/browser/runLiveness.d.ts +13 -0
- package/dist/browser/runLiveness.js +39 -0
- package/dist/browser/sitePolicy.d.ts +10 -0
- package/dist/browser/sitePolicy.js +61 -0
- package/dist/browser/stageBrowserEnv.d.ts +22 -0
- package/dist/browser/stageBrowserEnv.js +147 -0
- package/dist/browser/stageProfileLock.d.ts +17 -0
- package/dist/browser/stageProfileLock.js +39 -0
- package/dist/cli/browserCommand.d.ts +44 -0
- package/dist/cli/browserCommand.js +472 -0
- package/dist/cli/hostClient.d.ts +20 -0
- package/dist/cli/hostClient.js +36 -2
- package/dist/cli/initCommand.d.ts +1 -0
- package/dist/cli/initCommand.js +23 -7
- package/dist/cli/initTemplates.d.ts +5 -2
- package/dist/cli/initTemplates.js +25 -2
- package/dist/cli/runsCommand.js +6 -2
- package/dist/cli/triggerCommand.d.ts +12 -0
- package/dist/cli/triggerCommand.js +183 -0
- package/dist/cli/validateCommand.d.ts +1 -1
- package/dist/cli/validateCommand.js +23 -6
- package/dist/cli.js +31 -2
- package/dist/config/browseCatalog.d.ts +1 -0
- package/dist/config/browseCatalog.js +5 -4
- package/dist/config/builtinSkills.d.ts +4 -0
- package/dist/config/builtinSkills.js +23 -0
- package/dist/config/catalogRelativePath.d.ts +1 -0
- package/dist/config/catalogRelativePath.js +10 -2
- package/dist/config/createTrigger.d.ts +27 -0
- package/dist/config/createTrigger.js +232 -0
- package/dist/config/draftPackage.d.ts +117 -0
- package/dist/config/draftPackage.js +550 -0
- package/dist/config/ensureCatalogScanRoot.d.ts +16 -0
- package/dist/config/ensureCatalogScanRoot.js +73 -0
- package/dist/config/hostConfig.d.ts +2 -0
- package/dist/config/hostConfig.js +27 -0
- package/dist/config/listSkills.d.ts +2 -2
- package/dist/config/listSkills.js +17 -3
- package/dist/config/loadOutcome.d.ts +6 -0
- package/dist/config/loadPipeline.js +16 -0
- package/dist/config/loadStage.js +7 -0
- package/dist/config/loadStageflowManifest.js +25 -0
- package/dist/config/loadTrigger.d.ts +9 -0
- package/dist/config/loadTrigger.js +120 -0
- package/dist/config/multiProjectCatalog.d.ts +2 -0
- package/dist/config/multiProjectCatalog.js +26 -18
- package/dist/config/normalizePipelineStageEntry.js +8 -1
- package/dist/config/parseCompletionContract.js +6 -0
- package/dist/config/pipelineStageKeys.js +1 -0
- package/dist/config/publishDraftPackage.d.ts +7 -0
- package/dist/config/publishDraftPackage.js +25 -0
- package/dist/config/resolveCatalogContext.js +1 -1
- package/dist/config/resolvePipelineDag.js +1 -1
- package/dist/config/scanCatalogPaths.d.ts +1 -1
- package/dist/config/scanCatalogPaths.js +6 -2
- package/dist/config/stageBrowser.d.ts +12 -0
- package/dist/config/stageBrowser.js +118 -0
- package/dist/config/triggerCatalog.d.ts +10 -0
- package/dist/config/triggerCatalog.js +37 -0
- package/dist/config/validateCatalog.d.ts +13 -3
- package/dist/config/validateCatalog.js +83 -2
- package/dist/config/validateCompletionContract.js +8 -0
- package/dist/envelope/preEmitChecks.d.ts +1 -1
- package/dist/envelope/preEmitChecks.js +8 -0
- package/dist/logging/redact.d.ts +4 -0
- package/dist/logging/redact.js +17 -0
- package/dist/mcp/catalogTools.js +43 -8
- package/dist/mcp/controlTools.js +3 -1
- package/dist/mcp/deps.d.ts +2 -0
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/triggerTools.d.ts +3 -0
- package/dist/mcp/triggerTools.js +176 -0
- package/dist/operatorAgent/docsRetrieval.d.ts +40 -0
- package/dist/operatorAgent/docsRetrieval.js +269 -0
- package/dist/operatorAgent/draftContext.d.ts +16 -0
- package/dist/operatorAgent/draftContext.js +68 -0
- package/dist/operatorAgent/fakeHost.d.ts +39 -0
- package/dist/operatorAgent/fakeHost.js +92 -0
- package/dist/operatorAgent/host.d.ts +40 -0
- package/dist/operatorAgent/host.js +179 -0
- package/dist/operatorAgent/index.d.ts +9 -0
- package/dist/operatorAgent/index.js +8 -0
- package/dist/operatorAgent/piModel.d.ts +80 -0
- package/dist/operatorAgent/piModel.js +528 -0
- package/dist/operatorAgent/profiles/workshopAuthor.d.ts +23 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +338 -0
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +6 -0
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +103 -0
- package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +57 -0
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +623 -0
- package/dist/operatorAgent/proposals.d.ts +32 -0
- package/dist/operatorAgent/proposals.js +144 -0
- package/dist/operatorAgent/types.d.ts +128 -0
- package/dist/operatorAgent/types.js +1 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/project/findManifestRoot.d.ts +3 -0
- package/dist/project/findManifestRoot.js +35 -0
- package/dist/project/resolveStageflowContext.d.ts +7 -0
- package/dist/project/resolveStageflowContext.js +44 -28
- package/dist/runstore/assertTmpdir.js +6 -2
- package/dist/runstore/port.d.ts +28 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +90 -0
- package/dist/runstore/sqlite/migrations/008-triggers-table.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/008-triggers-table.js +19 -0
- package/dist/runstore/sqlite/migrations/009-trigger-next-run.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/009-trigger-next-run.js +19 -0
- package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.js +17 -0
- package/dist/runstore/sqlite/migrations/index.js +6 -0
- package/dist/runtime/answerResume.d.ts +1 -0
- package/dist/runtime/answerResume.js +3 -1
- package/dist/runtime/completionCheckRunner.d.ts +12 -1
- package/dist/runtime/completionCheckRunner.js +22 -0
- package/dist/runtime/credentialBinding.d.ts +2 -0
- package/dist/runtime/credentialBinding.js +3 -0
- package/dist/runtime/emailSource.d.ts +72 -0
- package/dist/runtime/emailSource.js +304 -0
- package/dist/runtime/githubPollSource.d.ts +86 -0
- package/dist/runtime/githubPollSource.js +284 -0
- package/dist/runtime/pipelineRunner.d.ts +4 -0
- package/dist/runtime/pipelineRunner.js +3 -0
- package/dist/runtime/pipelineScheduler.d.ts +2 -0
- package/dist/runtime/pipelineScheduler.js +85 -1
- package/dist/runtime/repositoryMaterialize.d.ts +1 -1
- package/dist/runtime/runManager.d.ts +11 -0
- package/dist/runtime/runManager.js +149 -1
- package/dist/runtime/runRetryCoordinator.d.ts +2 -0
- package/dist/runtime/runRetryCoordinator.js +1 -0
- package/dist/runtime/scheduleSource.d.ts +38 -0
- package/dist/runtime/scheduleSource.js +119 -0
- package/dist/runtime/settingsFile.d.ts +5 -0
- package/dist/runtime/settingsFile.js +61 -54
- package/dist/runtime/stageAttemptBootstrap.js +55 -3
- package/dist/runtime/stageEnvironment.js +1 -0
- package/dist/runtime/stageHitl.d.ts +1 -0
- package/dist/runtime/stageHitl.js +5 -1
- package/dist/runtime/stageProcessLauncher.d.ts +2 -0
- package/dist/runtime/stageProcessLauncher.js +44 -5
- package/dist/runtime/stageRunner.d.ts +5 -0
- package/dist/runtime/stageRunner.js +30 -6
- package/dist/runtime/stageStreamLog.d.ts +1 -0
- package/dist/runtime/stageStreamLog.js +2 -1
- package/dist/runtime/triggerCatalog.d.ts +6 -0
- package/dist/runtime/triggerCatalog.js +24 -0
- package/dist/runtime/triggerEventMatch.d.ts +2 -0
- package/dist/runtime/triggerEventMatch.js +6 -0
- package/dist/runtime/triggerPort.d.ts +14 -0
- package/dist/runtime/triggerPort.js +1 -0
- package/dist/runtime/triggerRunner.d.ts +17 -0
- package/dist/runtime/triggerRunner.js +89 -0
- package/dist/runtime/verifiedStageExecution.d.ts +7 -0
- package/dist/runtime/verifiedStageExecution.js +14 -0
- package/dist/runtime/webhookSignature.d.ts +1 -0
- package/dist/runtime/webhookSignature.js +12 -0
- package/dist/server/bootstrap.d.ts +6 -0
- package/dist/server/bootstrap.js +64 -0
- package/dist/server/controlToken.js +13 -0
- package/dist/server/createHttpHost.js +3 -0
- package/dist/server/healthSurfaces.js +31 -6
- package/dist/server/http.d.ts +15 -0
- package/dist/server/http.js +1251 -74
- package/dist/server/requestAuthContext.d.ts +1 -1
- package/dist/server/triggerRoutes.d.ts +15 -0
- package/dist/server/triggerRoutes.js +268 -0
- package/dist/tools/askOperator.d.ts +3 -2
- package/dist/types/completion.d.ts +3 -0
- package/dist/types/pipeline.d.ts +3 -1
- package/dist/types/preEmitCheck.d.ts +7 -0
- package/dist/types/stage.d.ts +14 -0
- package/dist/types/stageflowManifest.d.ts +3 -0
- package/dist/types/trigger.d.ts +18 -0
- package/dist/types/trigger.js +1 -0
- package/dist/ui/assets/{index-CSsDued1.css → index-Bv4p1aPK.css} +1 -1
- package/dist/ui/assets/index-CntB4bZR.js +133 -0
- package/dist/ui/index.html +2 -2
- package/dist/workshop/autosave.d.ts +58 -0
- package/dist/workshop/autosave.js +222 -0
- package/dist/workshop/buildStore.d.ts +79 -0
- package/dist/workshop/buildStore.js +326 -0
- package/dist/workshop/chatTurn.d.ts +232 -0
- package/dist/workshop/chatTurn.js +475 -0
- package/dist/workshop/modelSettings.d.ts +18 -0
- package/dist/workshop/modelSettings.js +44 -0
- package/dist/workshop/sessionStore.d.ts +61 -0
- package/dist/workshop/sessionStore.js +254 -0
- package/dist/workshop/workshopPin.d.ts +72 -0
- package/dist/workshop/workshopPin.js +193 -0
- package/examples/README.md +2 -1
- package/examples/browser-session/README.md +77 -0
- package/examples/browser-session/browser-session.pipeline.yaml +50 -0
- package/examples/browser-session/browser-session.task.yaml +6 -0
- package/examples/browser-session/check-login.yaml +22 -0
- package/examples/browser-session/fixture-server.mjs +64 -0
- package/examples/browser-session/human-login.yaml +31 -0
- package/examples/browser-session/merge.yaml +36 -0
- package/examples/browser-session/work-a.yaml +41 -0
- package/examples/browser-session/work-b.yaml +41 -0
- package/examples/stage-mcp/README.md +3 -2
- package/examples/stageflow.yaml +51 -0
- package/package.json +5 -1
- package/skills/stageflow/references/control-surface.md +3 -1
- package/skills/stageflow-author/references/stage-prompt-template.md +4 -4
- package/skills/stageflow-run/SKILL.md +2 -0
- package/skills/stageflow-run/references/task-and-pipeline-selection.md +3 -1
- package/skills/stageflow-setup/SKILL.md +11 -0
- package/dist/ui/assets/index-B6hlSXXn.js +0 -120
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BearerAuth, ControlScope } from "./controlToken.js";
|
|
2
|
-
export type CallerSurface = "mcp" | "rest" | "cli" | "a2a";
|
|
2
|
+
export type CallerSurface = "mcp" | "rest" | "cli" | "a2a" | "webhook";
|
|
3
3
|
export type RequestAuthContext = {
|
|
4
4
|
scope: ControlScope;
|
|
5
5
|
caller_id: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { Logger } from "../logging/logger.js";
|
|
3
|
+
import type { RunManager } from "../runtime/runManager.js";
|
|
4
|
+
import type { RunStore } from "../runstore/port.js";
|
|
5
|
+
export type { TriggerListItem } from "../config/triggerCatalog.js";
|
|
6
|
+
export type TriggerRoutesCtx = {
|
|
7
|
+
cwd: string;
|
|
8
|
+
manager: RunManager;
|
|
9
|
+
store: RunStore;
|
|
10
|
+
json: (res: ServerResponse, status: number, body: unknown) => void;
|
|
11
|
+
readJsonBody: (req: IncomingMessage) => Promise<unknown>;
|
|
12
|
+
readRawBody: (req: IncomingMessage) => Promise<Buffer>;
|
|
13
|
+
auditLog: Logger;
|
|
14
|
+
};
|
|
15
|
+
export declare function handleTriggerRoutes(req: IncomingMessage, res: ServerResponse, ctx: TriggerRoutesCtx): Promise<boolean>;
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { fireTrigger } from "../runtime/triggerRunner.js";
|
|
2
|
+
import { findTriggerDefinition } from "../runtime/triggerCatalog.js";
|
|
3
|
+
import { matchesEventFilter } from "../runtime/triggerEventMatch.js";
|
|
4
|
+
import { verifyHmacSignature } from "../runtime/webhookSignature.js";
|
|
5
|
+
import { mapStartFailure } from "./operatorResults.js";
|
|
6
|
+
import { writeAudit } from "../logging/audit.js";
|
|
7
|
+
import { callerIdFromRequestAuth, getRequestAuth, } from "./requestAuthContext.js";
|
|
8
|
+
import { loadCatalogTriggers } from "../config/triggerCatalog.js";
|
|
9
|
+
import { createTrigger, parseCreateTriggerBody } from "../config/createTrigger.js";
|
|
10
|
+
import { CatalogPathError, catalogPathErrorBody, resolveWritableCatalogRoot, } from "../config/catalogRelativePath.js";
|
|
11
|
+
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
12
|
+
import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
|
|
13
|
+
import { getCatalogScanPaths } from "../config/browseCatalog.js";
|
|
14
|
+
import { readSecretFromEnvOrFile } from "../config/secretFromEnvOrFile.js";
|
|
15
|
+
import { coerceTaskFile } from "../config/loadTask.js";
|
|
16
|
+
export async function handleTriggerRoutes(req, res, ctx) {
|
|
17
|
+
const { cwd, manager, store, json, readJsonBody, readRawBody, auditLog } = ctx;
|
|
18
|
+
const method = req.method ?? "GET";
|
|
19
|
+
const pathname = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
20
|
+
if (method === "POST" && pathname === "/api/triggers") {
|
|
21
|
+
let body;
|
|
22
|
+
try {
|
|
23
|
+
body = await readJsonBody(req);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
json(res, 400, { error: "Invalid JSON body" });
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const writeRoot = body !== null &&
|
|
30
|
+
typeof body === "object" &&
|
|
31
|
+
!Array.isArray(body) &&
|
|
32
|
+
typeof body.project_root === "string"
|
|
33
|
+
? body.project_root
|
|
34
|
+
: undefined;
|
|
35
|
+
let triggerWriteRoot;
|
|
36
|
+
try {
|
|
37
|
+
const { wireRoot: selected } = await resolveWritableCatalogRoot({ store, bootCwd: cwd }, writeRoot);
|
|
38
|
+
triggerWriteRoot = selected.path;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (err instanceof CatalogPathError) {
|
|
42
|
+
json(res, err.code === "catalog_root_read_only" ? 403 : 400, catalogPathErrorBody(err));
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
const parsed = parseCreateTriggerBody(body);
|
|
48
|
+
if ("ok" in parsed) {
|
|
49
|
+
json(res, parsed.status, { error: parsed.error });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
const stageflowCtx = await resolveStageflowContext(triggerWriteRoot);
|
|
53
|
+
if (stageflowCtx.manifestStatus !== "ok") {
|
|
54
|
+
json(res, 400, {
|
|
55
|
+
error: "Project root not found; initialize stageflow.yaml",
|
|
56
|
+
});
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
const callerId = callerIdFromRequestAuth();
|
|
60
|
+
const result = await createTrigger(stageflowCtx.projectRoot, parsed);
|
|
61
|
+
if (!result.ok) {
|
|
62
|
+
writeAudit(auditLog, {
|
|
63
|
+
caller_id: callerId,
|
|
64
|
+
surface: getRequestAuth()?.surface ?? "rest",
|
|
65
|
+
action: "trigger_create",
|
|
66
|
+
outcome: "error",
|
|
67
|
+
});
|
|
68
|
+
json(res, result.status, { error: result.error });
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
writeAudit(auditLog, {
|
|
72
|
+
caller_id: callerId,
|
|
73
|
+
surface: getRequestAuth()?.surface ?? "rest",
|
|
74
|
+
action: "trigger_create",
|
|
75
|
+
outcome: "ok",
|
|
76
|
+
});
|
|
77
|
+
json(res, 201, result.trigger);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (method === "GET" && pathname === "/api/triggers") {
|
|
81
|
+
const items = await loadCatalogTriggers(cwd, store);
|
|
82
|
+
if (items === undefined) {
|
|
83
|
+
json(res, 404, { error: "No Stageflow catalog found" });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
json(res, 200, { triggers: items });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
const fireMatch = pathname.match(/^\/api\/triggers\/([^/]+)\/fire$/);
|
|
90
|
+
if (method === "POST" && fireMatch) {
|
|
91
|
+
let body;
|
|
92
|
+
try {
|
|
93
|
+
body = await readJsonBody(req);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// empty/invalid body ok
|
|
97
|
+
}
|
|
98
|
+
const rawTask = body !== null && typeof body === "object" && !Array.isArray(body)
|
|
99
|
+
? body.task
|
|
100
|
+
: undefined;
|
|
101
|
+
let task;
|
|
102
|
+
if (rawTask !== undefined) {
|
|
103
|
+
task = coerceTaskFile(rawTask);
|
|
104
|
+
if (task === undefined) {
|
|
105
|
+
json(res, 400, { error: "Invalid task: id and goal are required strings" });
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const id = decodeURIComponent(fireMatch[1] ?? "");
|
|
110
|
+
const callerId = callerIdFromRequestAuth();
|
|
111
|
+
const result = await fireTrigger(id, store, manager, { cwd, task });
|
|
112
|
+
if (!result.ok) {
|
|
113
|
+
writeAudit(auditLog, {
|
|
114
|
+
caller_id: callerId,
|
|
115
|
+
surface: getRequestAuth()?.surface ?? "rest",
|
|
116
|
+
action: "trigger_fire",
|
|
117
|
+
outcome: "error",
|
|
118
|
+
error_code: result.code,
|
|
119
|
+
});
|
|
120
|
+
json(res, result.status ?? 500, mapStartFailure(result));
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
writeAudit(auditLog, {
|
|
124
|
+
caller_id: callerId,
|
|
125
|
+
surface: getRequestAuth()?.surface ?? "rest",
|
|
126
|
+
action: "trigger_fire",
|
|
127
|
+
target_run_id: result.runId,
|
|
128
|
+
outcome: "ok",
|
|
129
|
+
});
|
|
130
|
+
json(res, 202, {
|
|
131
|
+
runId: result.runId,
|
|
132
|
+
...(result.queued === true
|
|
133
|
+
? {
|
|
134
|
+
queued: true,
|
|
135
|
+
queuePosition: result.queuePosition,
|
|
136
|
+
...(result.queuedCode !== undefined
|
|
137
|
+
? { queuedCode: result.queuedCode }
|
|
138
|
+
: {}),
|
|
139
|
+
}
|
|
140
|
+
: {}),
|
|
141
|
+
});
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
const webhookMatch = pathname.match(/^\/api\/triggers\/([^/]+)\/webhook$/);
|
|
145
|
+
if (method === "POST" && webhookMatch) {
|
|
146
|
+
const id = decodeURIComponent(webhookMatch[1] ?? "");
|
|
147
|
+
const callerId = callerIdFromRequestAuth();
|
|
148
|
+
const catalogCtx = catalogContextFromStageflow(await resolveStageflowContext(cwd));
|
|
149
|
+
const scanPaths = await getCatalogScanPaths(catalogCtx);
|
|
150
|
+
const found = scanPaths
|
|
151
|
+
? await findTriggerDefinition(scanPaths.triggerPaths, id)
|
|
152
|
+
: undefined;
|
|
153
|
+
if (!found) {
|
|
154
|
+
json(res, 404, { error: `Trigger not found: ${id}` });
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
const { definition: trigger } = found;
|
|
158
|
+
const config = trigger.event?.config;
|
|
159
|
+
const secretRef = typeof config?.secretRef === "string" ? config.secretRef : undefined;
|
|
160
|
+
const header = typeof config?.header === "string" ? config.header : undefined;
|
|
161
|
+
if (secretRef === undefined || header === undefined) {
|
|
162
|
+
json(res, 400, { error: "this trigger has no webhook signing configured" });
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
const scheme = config?.scheme === "base64" ? "base64" : "hex";
|
|
166
|
+
let secret;
|
|
167
|
+
try {
|
|
168
|
+
secret = readSecretFromEnvOrFile(process.env, secretRef);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
secret = undefined;
|
|
172
|
+
}
|
|
173
|
+
if (secret === undefined) {
|
|
174
|
+
json(res, 400, { error: "this trigger has no webhook signing configured" });
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
const rawBody = await readRawBody(req);
|
|
178
|
+
const headerValue = req.headers[header.toLowerCase()];
|
|
179
|
+
const signature = Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
180
|
+
if (typeof signature !== "string" ||
|
|
181
|
+
signature.length === 0 ||
|
|
182
|
+
!verifyHmacSignature(rawBody, signature, secret, scheme)) {
|
|
183
|
+
writeAudit(auditLog, {
|
|
184
|
+
caller_id: callerId,
|
|
185
|
+
surface: "webhook",
|
|
186
|
+
action: "trigger_webhook",
|
|
187
|
+
outcome: "error",
|
|
188
|
+
error_code: "webhook.signature_invalid",
|
|
189
|
+
});
|
|
190
|
+
json(res, 401, { error: "Invalid webhook signature" });
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
let payload;
|
|
194
|
+
try {
|
|
195
|
+
payload = rawBody.length === 0 ? {} : JSON.parse(rawBody.toString("utf8"));
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
json(res, 400, { error: "Invalid JSON body" });
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
202
|
+
json(res, 400, { error: "Invalid JSON body: expected an object" });
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
const payloadRecord = payload;
|
|
206
|
+
if (!matchesEventFilter(trigger.event?.match, payloadRecord)) {
|
|
207
|
+
json(res, 200, { fired: false });
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
const task = trigger.task === undefined
|
|
211
|
+
? {
|
|
212
|
+
id: `${id}-webhook-${Date.now()}`,
|
|
213
|
+
goal: `Handle webhook event for trigger "${id}"`,
|
|
214
|
+
input: payloadRecord,
|
|
215
|
+
}
|
|
216
|
+
: undefined;
|
|
217
|
+
const result = await fireTrigger(id, store, manager, { cwd, task });
|
|
218
|
+
if (!result.ok) {
|
|
219
|
+
writeAudit(auditLog, {
|
|
220
|
+
caller_id: callerId,
|
|
221
|
+
surface: "webhook",
|
|
222
|
+
action: "trigger_webhook",
|
|
223
|
+
outcome: "error",
|
|
224
|
+
error_code: result.code,
|
|
225
|
+
});
|
|
226
|
+
json(res, result.status ?? 500, mapStartFailure(result));
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
writeAudit(auditLog, {
|
|
230
|
+
caller_id: callerId,
|
|
231
|
+
surface: "webhook",
|
|
232
|
+
action: "trigger_webhook",
|
|
233
|
+
target_run_id: result.runId,
|
|
234
|
+
outcome: "ok",
|
|
235
|
+
});
|
|
236
|
+
json(res, 201, {
|
|
237
|
+
fired: true,
|
|
238
|
+
runId: result.runId,
|
|
239
|
+
...(result.queued === true
|
|
240
|
+
? {
|
|
241
|
+
queued: true,
|
|
242
|
+
queuePosition: result.queuePosition,
|
|
243
|
+
...(result.queuedCode !== undefined
|
|
244
|
+
? { queuedCode: result.queuedCode }
|
|
245
|
+
: {}),
|
|
246
|
+
}
|
|
247
|
+
: {}),
|
|
248
|
+
});
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
const idMatch = pathname.match(/^\/api\/triggers\/([^/]+)$/);
|
|
252
|
+
if (method === "GET" && idMatch) {
|
|
253
|
+
const id = decodeURIComponent(idMatch[1] ?? "");
|
|
254
|
+
const items = await loadCatalogTriggers(cwd, store);
|
|
255
|
+
if (items === undefined) {
|
|
256
|
+
json(res, 404, { error: "No Stageflow catalog found" });
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
const found = items.find((item) => item.id === id);
|
|
260
|
+
if (!found) {
|
|
261
|
+
json(res, 404, { error: `Trigger not found: ${id}` });
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
json(res, 200, found);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
+
import type { HostGateContext } from "../browser/gateHandoff.js";
|
|
2
3
|
export declare class AskOperatorError extends Error {
|
|
3
4
|
constructor(message: string);
|
|
4
5
|
}
|
|
@@ -37,7 +38,7 @@ export type MultiQuestionItem = {
|
|
|
37
38
|
message: string;
|
|
38
39
|
id: string;
|
|
39
40
|
};
|
|
40
|
-
export type AskOperatorPrompt = {
|
|
41
|
+
export type AskOperatorPrompt = ({
|
|
41
42
|
kind: "free_text";
|
|
42
43
|
message: string;
|
|
43
44
|
id: string;
|
|
@@ -54,7 +55,7 @@ export type AskOperatorPrompt = {
|
|
|
54
55
|
message: string;
|
|
55
56
|
artifacts: string[];
|
|
56
57
|
id: string;
|
|
57
|
-
};
|
|
58
|
+
}) & HostGateContext;
|
|
58
59
|
export type Decision = "accept" | "reject";
|
|
59
60
|
export type FreeTextAnswerPayload = {
|
|
60
61
|
kind: "free_text";
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LoadedStageConfig, StageGateKind, StageIoYaml } from "./stage.js";
|
|
1
|
+
import type { LoadedStageConfig, StageBrowserConfig, StageGateKind, StageIoYaml } from "./stage.js";
|
|
2
2
|
import type { CompletionContract, RecoveryPolicy } from "./completion.js";
|
|
3
3
|
import type { StageSecretDecl } from "../runtime/stageSecretDecl.js";
|
|
4
4
|
import type { ToolRequirement } from "../config/toolRequires.js";
|
|
@@ -134,6 +134,7 @@ export type PipelineStageYamlEntry = {
|
|
|
134
134
|
timeout_ms?: number;
|
|
135
135
|
skill?: string;
|
|
136
136
|
mcp?: string[];
|
|
137
|
+
browser?: StageBrowserConfig;
|
|
137
138
|
replay_safe?: boolean;
|
|
138
139
|
route?: PipelineRouteEntry[];
|
|
139
140
|
entry?: boolean;
|
|
@@ -162,6 +163,7 @@ export type NormalizedPipelineStageEntry = {
|
|
|
162
163
|
mcp?: string[];
|
|
163
164
|
secrets?: StageSecretDecl[];
|
|
164
165
|
requires?: ToolRequirement[];
|
|
166
|
+
browser?: StageBrowserConfig;
|
|
165
167
|
clone_cap?: number;
|
|
166
168
|
clone_mode?: CloneMode;
|
|
167
169
|
body: {
|
|
@@ -13,4 +13,11 @@ export type PreEmitCheck = {
|
|
|
13
13
|
id: string;
|
|
14
14
|
type: "artifact_declared";
|
|
15
15
|
basename: string;
|
|
16
|
+
} | {
|
|
17
|
+
/** Host-injected for `browser.check` stages; never authored in YAML. */
|
|
18
|
+
id: string;
|
|
19
|
+
type: "browser_login_check";
|
|
20
|
+
state: "logged_in" | "logged_out" | "unknown";
|
|
21
|
+
logged_in: boolean | null;
|
|
22
|
+
url: string;
|
|
16
23
|
};
|
package/dist/types/stage.d.ts
CHANGED
|
@@ -24,6 +24,18 @@ export type StageIoYaml = {
|
|
|
24
24
|
* in `src/config/yamlDialect.ts`. Do not add new catalog keys here — add them on
|
|
25
25
|
* the YAML dialect and map them in compileTargetContract.
|
|
26
26
|
*/
|
|
27
|
+
export type StageBrowserConfig = {
|
|
28
|
+
profile?: string;
|
|
29
|
+
headed?: boolean;
|
|
30
|
+
allow_domains?: string[];
|
|
31
|
+
/** Page the Host opens for a human login stage; defaults to `check.url`. */
|
|
32
|
+
login_url?: string;
|
|
33
|
+
check?: {
|
|
34
|
+
url: string;
|
|
35
|
+
logged_in_url?: string;
|
|
36
|
+
logged_out_url?: string | string[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
27
39
|
export type StageConfig = {
|
|
28
40
|
id: string;
|
|
29
41
|
system_prompt: string;
|
|
@@ -44,6 +56,8 @@ export type StageConfig = {
|
|
|
44
56
|
secrets?: StageSecretDecl[];
|
|
45
57
|
/** Declared toolchain binaries this stage needs (Slot 9). */
|
|
46
58
|
requires?: ToolRequirement[];
|
|
59
|
+
/** Browser session settings for this stage; adds the agent-browser requirement. */
|
|
60
|
+
browser?: StageBrowserConfig;
|
|
47
61
|
/**
|
|
48
62
|
* Selects the AgentPort backend for this stage, overriding pipeline/global.
|
|
49
63
|
* Parsed but not yet consulted — see STAGE_LEVEL_AGENT_OVERRIDE_ENABLED.
|
|
@@ -2,9 +2,11 @@ export type StageflowManifestVersion = 1;
|
|
|
2
2
|
export type StageflowManifestCatalog = {
|
|
3
3
|
pipelines: string[];
|
|
4
4
|
tasks: string[];
|
|
5
|
+
triggers?: string[];
|
|
5
6
|
patterns?: {
|
|
6
7
|
pipeline?: string;
|
|
7
8
|
task?: string;
|
|
9
|
+
trigger?: string;
|
|
8
10
|
};
|
|
9
11
|
exclude?: string[];
|
|
10
12
|
};
|
|
@@ -23,5 +25,6 @@ export type LoadedManifest = {
|
|
|
23
25
|
patterns: {
|
|
24
26
|
pipeline: string;
|
|
25
27
|
task: string;
|
|
28
|
+
trigger: string;
|
|
26
29
|
};
|
|
27
30
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type TriggerSchedule = {
|
|
2
|
+
cron: string;
|
|
3
|
+
timezone?: string;
|
|
4
|
+
};
|
|
5
|
+
export type TriggerEvent = {
|
|
6
|
+
source: string;
|
|
7
|
+
match?: Record<string, unknown>;
|
|
8
|
+
config?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
export type TriggerFile = {
|
|
11
|
+
id: string;
|
|
12
|
+
pipeline: string;
|
|
13
|
+
task?: string;
|
|
14
|
+
kind: "manual" | "schedule" | "event";
|
|
15
|
+
schedule?: TriggerSchedule;
|
|
16
|
+
event?: TriggerEvent;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|