stageflow 0.27.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/README.md +4 -0
  2. package/builtin-skills/browser/SKILL.md +42 -0
  3. package/dist/agent/claudeAdapter.js +2 -2
  4. package/dist/agent/cursorProvider.d.ts +10 -0
  5. package/dist/agent/cursorProvider.js +83 -8
  6. package/dist/agent/fakeAgent.d.ts +1 -0
  7. package/dist/agent/fakeAgent.js +13 -0
  8. package/dist/agent/piAdapter.d.ts +3 -24
  9. package/dist/agent/piAdapter.js +49 -47
  10. package/dist/agent/piSessionFactory.d.ts +38 -0
  11. package/dist/agent/piSessionFactory.js +60 -0
  12. package/dist/agent/port.d.ts +2 -0
  13. package/dist/agent/providerAuth.d.ts +7 -3
  14. package/dist/agent/providerAuth.js +5 -3
  15. package/dist/agent/streamLogRedact.d.ts +6 -0
  16. package/dist/agent/streamLogRedact.js +23 -1
  17. package/dist/browser/anchor.d.ts +27 -0
  18. package/dist/browser/anchor.js +127 -0
  19. package/dist/browser/auditSink.d.ts +38 -0
  20. package/dist/browser/auditSink.js +34 -0
  21. package/dist/browser/browserHost.d.ts +86 -0
  22. package/dist/browser/browserHost.js +7 -0
  23. package/dist/browser/browserSweep.d.ts +14 -0
  24. package/dist/browser/browserSweep.js +54 -0
  25. package/dist/browser/browserTeardown.d.ts +56 -0
  26. package/dist/browser/browserTeardown.js +235 -0
  27. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -0
  28. package/dist/browser/fakeRemoteBrowserHost.js +34 -0
  29. package/dist/browser/gateHandoff.d.ts +25 -0
  30. package/dist/browser/gateHandoff.js +83 -0
  31. package/dist/browser/humanLogin.d.ts +18 -0
  32. package/dist/browser/humanLogin.js +34 -0
  33. package/dist/browser/keyProvider.d.ts +10 -0
  34. package/dist/browser/keyProvider.js +39 -0
  35. package/dist/browser/localBrowserHost.d.ts +10 -0
  36. package/dist/browser/localBrowserHost.js +152 -0
  37. package/dist/browser/localProfileLock.d.ts +2 -0
  38. package/dist/browser/localProfileLock.js +218 -0
  39. package/dist/browser/localProfileStore.d.ts +5 -0
  40. package/dist/browser/localProfileStore.js +91 -0
  41. package/dist/browser/loginCheck.d.ts +53 -0
  42. package/dist/browser/loginCheck.js +147 -0
  43. package/dist/browser/memoryProfileLock.d.ts +2 -0
  44. package/dist/browser/memoryProfileLock.js +53 -0
  45. package/dist/browser/memoryProfileStore.d.ts +2 -0
  46. package/dist/browser/memoryProfileStore.js +31 -0
  47. package/dist/browser/navigationAudit.d.ts +16 -0
  48. package/dist/browser/navigationAudit.js +53 -0
  49. package/dist/browser/persistedEnv.d.ts +3 -0
  50. package/dist/browser/persistedEnv.js +15 -0
  51. package/dist/browser/profileLock.d.ts +40 -0
  52. package/dist/browser/profileLock.js +10 -0
  53. package/dist/browser/profileStore.d.ts +23 -0
  54. package/dist/browser/profileStore.js +39 -0
  55. package/dist/browser/runLiveness.d.ts +13 -0
  56. package/dist/browser/runLiveness.js +39 -0
  57. package/dist/browser/sitePolicy.d.ts +10 -0
  58. package/dist/browser/sitePolicy.js +61 -0
  59. package/dist/browser/stageBrowserEnv.d.ts +22 -0
  60. package/dist/browser/stageBrowserEnv.js +147 -0
  61. package/dist/browser/stageProfileLock.d.ts +17 -0
  62. package/dist/browser/stageProfileLock.js +39 -0
  63. package/dist/cli/browserCommand.d.ts +44 -0
  64. package/dist/cli/browserCommand.js +472 -0
  65. package/dist/cli/doctorCommand.js +7 -0
  66. package/dist/cli/hostClient.d.ts +20 -0
  67. package/dist/cli/hostClient.js +36 -2
  68. package/dist/cli/initCommand.d.ts +1 -0
  69. package/dist/cli/initCommand.js +23 -7
  70. package/dist/cli/initTemplates.d.ts +5 -2
  71. package/dist/cli/initTemplates.js +25 -2
  72. package/dist/cli/providersCommand.d.ts +1 -1
  73. package/dist/cli/providersCommand.js +4 -4
  74. package/dist/cli/runsCommand.js +6 -2
  75. package/dist/cli/triggerCommand.d.ts +12 -0
  76. package/dist/cli/triggerCommand.js +183 -0
  77. package/dist/cli/validateCommand.d.ts +1 -1
  78. package/dist/cli/validateCommand.js +23 -6
  79. package/dist/cli.js +32 -3
  80. package/dist/config/browseCatalog.d.ts +1 -0
  81. package/dist/config/browseCatalog.js +5 -4
  82. package/dist/config/builtinSkills.d.ts +4 -0
  83. package/dist/config/builtinSkills.js +23 -0
  84. package/dist/config/catalogRelativePath.d.ts +1 -0
  85. package/dist/config/catalogRelativePath.js +10 -2
  86. package/dist/config/createTrigger.d.ts +27 -0
  87. package/dist/config/createTrigger.js +232 -0
  88. package/dist/config/draftPackage.d.ts +117 -0
  89. package/dist/config/draftPackage.js +550 -0
  90. package/dist/config/ensureCatalogScanRoot.d.ts +16 -0
  91. package/dist/config/ensureCatalogScanRoot.js +73 -0
  92. package/dist/config/hostConfig.d.ts +2 -0
  93. package/dist/config/hostConfig.js +27 -0
  94. package/dist/config/listSkills.d.ts +2 -2
  95. package/dist/config/listSkills.js +17 -3
  96. package/dist/config/loadOutcome.d.ts +6 -0
  97. package/dist/config/loadPipeline.js +16 -0
  98. package/dist/config/loadStage.js +7 -0
  99. package/dist/config/loadStageflowManifest.js +25 -0
  100. package/dist/config/loadTrigger.d.ts +9 -0
  101. package/dist/config/loadTrigger.js +120 -0
  102. package/dist/config/multiProjectCatalog.d.ts +2 -0
  103. package/dist/config/multiProjectCatalog.js +26 -18
  104. package/dist/config/normalizePipelineStageEntry.js +8 -1
  105. package/dist/config/parseCompletionContract.js +6 -0
  106. package/dist/config/pipelineStageKeys.js +1 -0
  107. package/dist/config/publishDraftPackage.d.ts +7 -0
  108. package/dist/config/publishDraftPackage.js +25 -0
  109. package/dist/config/resolveCatalogContext.js +1 -1
  110. package/dist/config/resolvePipelineDag.js +1 -1
  111. package/dist/config/scanCatalogPaths.d.ts +1 -1
  112. package/dist/config/scanCatalogPaths.js +6 -2
  113. package/dist/config/stageBrowser.d.ts +12 -0
  114. package/dist/config/stageBrowser.js +118 -0
  115. package/dist/config/triggerCatalog.d.ts +10 -0
  116. package/dist/config/triggerCatalog.js +37 -0
  117. package/dist/config/validateCatalog.d.ts +13 -3
  118. package/dist/config/validateCatalog.js +83 -2
  119. package/dist/config/validateCompletionContract.js +8 -0
  120. package/dist/envelope/preEmitChecks.d.ts +1 -1
  121. package/dist/envelope/preEmitChecks.js +8 -0
  122. package/dist/logging/redact.d.ts +4 -0
  123. package/dist/logging/redact.js +17 -0
  124. package/dist/mcp/catalogTools.js +43 -8
  125. package/dist/mcp/controlTools.js +3 -1
  126. package/dist/mcp/deps.d.ts +2 -0
  127. package/dist/mcp/server.js +1 -0
  128. package/dist/mcp/tools.js +2 -0
  129. package/dist/mcp/triggerTools.d.ts +3 -0
  130. package/dist/mcp/triggerTools.js +176 -0
  131. package/dist/operatorAgent/docsRetrieval.d.ts +40 -0
  132. package/dist/operatorAgent/docsRetrieval.js +269 -0
  133. package/dist/operatorAgent/draftContext.d.ts +16 -0
  134. package/dist/operatorAgent/draftContext.js +68 -0
  135. package/dist/operatorAgent/fakeHost.d.ts +39 -0
  136. package/dist/operatorAgent/fakeHost.js +92 -0
  137. package/dist/operatorAgent/host.d.ts +40 -0
  138. package/dist/operatorAgent/host.js +179 -0
  139. package/dist/operatorAgent/index.d.ts +9 -0
  140. package/dist/operatorAgent/index.js +8 -0
  141. package/dist/operatorAgent/piModel.d.ts +80 -0
  142. package/dist/operatorAgent/piModel.js +528 -0
  143. package/dist/operatorAgent/profiles/workshopAuthor.d.ts +23 -0
  144. package/dist/operatorAgent/profiles/workshopAuthor.js +338 -0
  145. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +6 -0
  146. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +103 -0
  147. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +57 -0
  148. package/dist/operatorAgent/profiles/workshopAuthorTools.js +623 -0
  149. package/dist/operatorAgent/proposals.d.ts +32 -0
  150. package/dist/operatorAgent/proposals.js +144 -0
  151. package/dist/operatorAgent/types.d.ts +128 -0
  152. package/dist/operatorAgent/types.js +1 -0
  153. package/dist/package-meta.d.ts +1 -1
  154. package/dist/package-meta.js +1 -1
  155. package/dist/project/findManifestRoot.d.ts +3 -0
  156. package/dist/project/findManifestRoot.js +35 -0
  157. package/dist/project/resolveStageflowContext.d.ts +7 -0
  158. package/dist/project/resolveStageflowContext.js +44 -28
  159. package/dist/runstore/assertTmpdir.js +6 -2
  160. package/dist/runstore/diskUsage.d.ts +1 -1
  161. package/dist/runstore/diskUsage.js +2 -7
  162. package/dist/runstore/port.d.ts +28 -0
  163. package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -1
  164. package/dist/runstore/sqlite/SqliteRunStore.js +90 -0
  165. package/dist/runstore/sqlite/migrations/008-triggers-table.d.ts +7 -0
  166. package/dist/runstore/sqlite/migrations/008-triggers-table.js +19 -0
  167. package/dist/runstore/sqlite/migrations/009-trigger-next-run.d.ts +7 -0
  168. package/dist/runstore/sqlite/migrations/009-trigger-next-run.js +19 -0
  169. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.d.ts +7 -0
  170. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.js +17 -0
  171. package/dist/runstore/sqlite/migrations/index.js +6 -0
  172. package/dist/runtime/answerResume.d.ts +1 -0
  173. package/dist/runtime/answerResume.js +3 -1
  174. package/dist/runtime/completionCheckRunner.d.ts +12 -1
  175. package/dist/runtime/completionCheckRunner.js +22 -0
  176. package/dist/runtime/credentialBinding.d.ts +7 -2
  177. package/dist/runtime/credentialBinding.js +20 -28
  178. package/dist/runtime/emailSource.d.ts +72 -0
  179. package/dist/runtime/emailSource.js +304 -0
  180. package/dist/runtime/githubPollSource.d.ts +86 -0
  181. package/dist/runtime/githubPollSource.js +284 -0
  182. package/dist/runtime/pipelineRunner.d.ts +4 -0
  183. package/dist/runtime/pipelineRunner.js +3 -0
  184. package/dist/runtime/pipelineScheduler.d.ts +2 -0
  185. package/dist/runtime/pipelineScheduler.js +86 -1
  186. package/dist/runtime/repositoryMaterialize.d.ts +1 -1
  187. package/dist/runtime/runManager.d.ts +11 -0
  188. package/dist/runtime/runManager.js +161 -3
  189. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  190. package/dist/runtime/runRetryCoordinator.js +1 -0
  191. package/dist/runtime/scheduleSource.d.ts +38 -0
  192. package/dist/runtime/scheduleSource.js +119 -0
  193. package/dist/runtime/settingsFile.d.ts +7 -2
  194. package/dist/runtime/settingsFile.js +66 -56
  195. package/dist/runtime/stageAttemptBootstrap.js +55 -3
  196. package/dist/runtime/stageEnvironment.js +1 -0
  197. package/dist/runtime/stageHitl.d.ts +1 -0
  198. package/dist/runtime/stageHitl.js +5 -1
  199. package/dist/runtime/stageProcessLauncher.d.ts +3 -0
  200. package/dist/runtime/stageProcessLauncher.js +52 -5
  201. package/dist/runtime/stageRunner.d.ts +5 -0
  202. package/dist/runtime/stageRunner.js +30 -6
  203. package/dist/runtime/stageStreamLog.d.ts +1 -0
  204. package/dist/runtime/stageStreamLog.js +2 -1
  205. package/dist/runtime/triggerCatalog.d.ts +6 -0
  206. package/dist/runtime/triggerCatalog.js +24 -0
  207. package/dist/runtime/triggerEventMatch.d.ts +2 -0
  208. package/dist/runtime/triggerEventMatch.js +6 -0
  209. package/dist/runtime/triggerPort.d.ts +14 -0
  210. package/dist/runtime/triggerPort.js +1 -0
  211. package/dist/runtime/triggerRunner.d.ts +17 -0
  212. package/dist/runtime/triggerRunner.js +89 -0
  213. package/dist/runtime/verifiedStageExecution.d.ts +7 -0
  214. package/dist/runtime/verifiedStageExecution.js +14 -0
  215. package/dist/runtime/webhookSignature.d.ts +1 -0
  216. package/dist/runtime/webhookSignature.js +12 -0
  217. package/dist/server/bootstrap.d.ts +6 -0
  218. package/dist/server/bootstrap.js +70 -0
  219. package/dist/server/controlToken.js +13 -0
  220. package/dist/server/createHttpHost.js +3 -0
  221. package/dist/server/healthSurfaces.js +31 -6
  222. package/dist/server/http.d.ts +15 -0
  223. package/dist/server/http.js +1251 -74
  224. package/dist/server/requestAuthContext.d.ts +1 -1
  225. package/dist/server/triggerRoutes.d.ts +15 -0
  226. package/dist/server/triggerRoutes.js +268 -0
  227. package/dist/tools/askOperator.d.ts +3 -2
  228. package/dist/types/completion.d.ts +3 -0
  229. package/dist/types/pipeline.d.ts +3 -1
  230. package/dist/types/preEmitCheck.d.ts +7 -0
  231. package/dist/types/stage.d.ts +14 -0
  232. package/dist/types/stageflowManifest.d.ts +3 -0
  233. package/dist/types/trigger.d.ts +18 -0
  234. package/dist/types/trigger.js +1 -0
  235. package/dist/ui/assets/{index-CSsDued1.css → index-Bv4p1aPK.css} +1 -1
  236. package/dist/ui/assets/index-p8Iou3zk.js +133 -0
  237. package/dist/ui/index.html +2 -2
  238. package/dist/workshop/autosave.d.ts +58 -0
  239. package/dist/workshop/autosave.js +222 -0
  240. package/dist/workshop/buildStore.d.ts +79 -0
  241. package/dist/workshop/buildStore.js +326 -0
  242. package/dist/workshop/chatTurn.d.ts +232 -0
  243. package/dist/workshop/chatTurn.js +475 -0
  244. package/dist/workshop/modelSettings.d.ts +18 -0
  245. package/dist/workshop/modelSettings.js +44 -0
  246. package/dist/workshop/sessionStore.d.ts +61 -0
  247. package/dist/workshop/sessionStore.js +254 -0
  248. package/dist/workshop/workshopPin.d.ts +72 -0
  249. package/dist/workshop/workshopPin.js +193 -0
  250. package/examples/README.md +2 -1
  251. package/examples/browser-session/README.md +77 -0
  252. package/examples/browser-session/browser-session.pipeline.yaml +50 -0
  253. package/examples/browser-session/browser-session.task.yaml +6 -0
  254. package/examples/browser-session/check-login.yaml +22 -0
  255. package/examples/browser-session/fixture-server.mjs +64 -0
  256. package/examples/browser-session/human-login.yaml +31 -0
  257. package/examples/browser-session/merge.yaml +36 -0
  258. package/examples/browser-session/work-a.yaml +41 -0
  259. package/examples/browser-session/work-b.yaml +41 -0
  260. package/examples/conditional-fork/decide.yaml +1 -1
  261. package/examples/github-release/README.md +17 -3
  262. package/examples/stage-mcp/README.md +3 -2
  263. package/examples/stageflow.yaml +51 -0
  264. package/package.json +9 -4
  265. package/skills/stageflow/references/control-surface.md +3 -1
  266. package/skills/stageflow-author/references/stage-prompt-template.md +4 -4
  267. package/skills/stageflow-run/SKILL.md +2 -0
  268. package/skills/stageflow-run/references/task-and-pipeline-selection.md +3 -1
  269. package/skills/stageflow-setup/SKILL.md +11 -0
  270. 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";
@@ -31,6 +31,9 @@ export type CompletionCheck = {
31
31
  id: string;
32
32
  type: "checkout_changes";
33
33
  path_fields?: string[];
34
+ } | {
35
+ id: string;
36
+ type: "browser_login";
34
37
  };
35
38
  export type CompletionContract = {
36
39
  mode: "all";
@@ -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
  };
@@ -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 {};