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.
Files changed (261) 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 +2 -0
  5. package/dist/agent/cursorProvider.js +30 -5
  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/streamLogRedact.d.ts +6 -0
  14. package/dist/agent/streamLogRedact.js +23 -1
  15. package/dist/browser/anchor.d.ts +27 -0
  16. package/dist/browser/anchor.js +127 -0
  17. package/dist/browser/auditSink.d.ts +38 -0
  18. package/dist/browser/auditSink.js +34 -0
  19. package/dist/browser/browserHost.d.ts +86 -0
  20. package/dist/browser/browserHost.js +7 -0
  21. package/dist/browser/browserSweep.d.ts +14 -0
  22. package/dist/browser/browserSweep.js +54 -0
  23. package/dist/browser/browserTeardown.d.ts +56 -0
  24. package/dist/browser/browserTeardown.js +235 -0
  25. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -0
  26. package/dist/browser/fakeRemoteBrowserHost.js +34 -0
  27. package/dist/browser/gateHandoff.d.ts +25 -0
  28. package/dist/browser/gateHandoff.js +83 -0
  29. package/dist/browser/humanLogin.d.ts +18 -0
  30. package/dist/browser/humanLogin.js +34 -0
  31. package/dist/browser/keyProvider.d.ts +10 -0
  32. package/dist/browser/keyProvider.js +39 -0
  33. package/dist/browser/localBrowserHost.d.ts +10 -0
  34. package/dist/browser/localBrowserHost.js +152 -0
  35. package/dist/browser/localProfileLock.d.ts +2 -0
  36. package/dist/browser/localProfileLock.js +218 -0
  37. package/dist/browser/localProfileStore.d.ts +5 -0
  38. package/dist/browser/localProfileStore.js +91 -0
  39. package/dist/browser/loginCheck.d.ts +53 -0
  40. package/dist/browser/loginCheck.js +147 -0
  41. package/dist/browser/memoryProfileLock.d.ts +2 -0
  42. package/dist/browser/memoryProfileLock.js +53 -0
  43. package/dist/browser/memoryProfileStore.d.ts +2 -0
  44. package/dist/browser/memoryProfileStore.js +31 -0
  45. package/dist/browser/navigationAudit.d.ts +16 -0
  46. package/dist/browser/navigationAudit.js +53 -0
  47. package/dist/browser/persistedEnv.d.ts +3 -0
  48. package/dist/browser/persistedEnv.js +15 -0
  49. package/dist/browser/profileLock.d.ts +40 -0
  50. package/dist/browser/profileLock.js +10 -0
  51. package/dist/browser/profileStore.d.ts +23 -0
  52. package/dist/browser/profileStore.js +39 -0
  53. package/dist/browser/runLiveness.d.ts +13 -0
  54. package/dist/browser/runLiveness.js +39 -0
  55. package/dist/browser/sitePolicy.d.ts +10 -0
  56. package/dist/browser/sitePolicy.js +61 -0
  57. package/dist/browser/stageBrowserEnv.d.ts +22 -0
  58. package/dist/browser/stageBrowserEnv.js +147 -0
  59. package/dist/browser/stageProfileLock.d.ts +17 -0
  60. package/dist/browser/stageProfileLock.js +39 -0
  61. package/dist/cli/browserCommand.d.ts +44 -0
  62. package/dist/cli/browserCommand.js +472 -0
  63. package/dist/cli/hostClient.d.ts +20 -0
  64. package/dist/cli/hostClient.js +36 -2
  65. package/dist/cli/initCommand.d.ts +1 -0
  66. package/dist/cli/initCommand.js +23 -7
  67. package/dist/cli/initTemplates.d.ts +5 -2
  68. package/dist/cli/initTemplates.js +25 -2
  69. package/dist/cli/runsCommand.js +6 -2
  70. package/dist/cli/triggerCommand.d.ts +12 -0
  71. package/dist/cli/triggerCommand.js +183 -0
  72. package/dist/cli/validateCommand.d.ts +1 -1
  73. package/dist/cli/validateCommand.js +23 -6
  74. package/dist/cli.js +31 -2
  75. package/dist/config/browseCatalog.d.ts +1 -0
  76. package/dist/config/browseCatalog.js +5 -4
  77. package/dist/config/builtinSkills.d.ts +4 -0
  78. package/dist/config/builtinSkills.js +23 -0
  79. package/dist/config/catalogRelativePath.d.ts +1 -0
  80. package/dist/config/catalogRelativePath.js +10 -2
  81. package/dist/config/createTrigger.d.ts +27 -0
  82. package/dist/config/createTrigger.js +232 -0
  83. package/dist/config/draftPackage.d.ts +117 -0
  84. package/dist/config/draftPackage.js +550 -0
  85. package/dist/config/ensureCatalogScanRoot.d.ts +16 -0
  86. package/dist/config/ensureCatalogScanRoot.js +73 -0
  87. package/dist/config/hostConfig.d.ts +2 -0
  88. package/dist/config/hostConfig.js +27 -0
  89. package/dist/config/listSkills.d.ts +2 -2
  90. package/dist/config/listSkills.js +17 -3
  91. package/dist/config/loadOutcome.d.ts +6 -0
  92. package/dist/config/loadPipeline.js +16 -0
  93. package/dist/config/loadStage.js +7 -0
  94. package/dist/config/loadStageflowManifest.js +25 -0
  95. package/dist/config/loadTrigger.d.ts +9 -0
  96. package/dist/config/loadTrigger.js +120 -0
  97. package/dist/config/multiProjectCatalog.d.ts +2 -0
  98. package/dist/config/multiProjectCatalog.js +26 -18
  99. package/dist/config/normalizePipelineStageEntry.js +8 -1
  100. package/dist/config/parseCompletionContract.js +6 -0
  101. package/dist/config/pipelineStageKeys.js +1 -0
  102. package/dist/config/publishDraftPackage.d.ts +7 -0
  103. package/dist/config/publishDraftPackage.js +25 -0
  104. package/dist/config/resolveCatalogContext.js +1 -1
  105. package/dist/config/resolvePipelineDag.js +1 -1
  106. package/dist/config/scanCatalogPaths.d.ts +1 -1
  107. package/dist/config/scanCatalogPaths.js +6 -2
  108. package/dist/config/stageBrowser.d.ts +12 -0
  109. package/dist/config/stageBrowser.js +118 -0
  110. package/dist/config/triggerCatalog.d.ts +10 -0
  111. package/dist/config/triggerCatalog.js +37 -0
  112. package/dist/config/validateCatalog.d.ts +13 -3
  113. package/dist/config/validateCatalog.js +83 -2
  114. package/dist/config/validateCompletionContract.js +8 -0
  115. package/dist/envelope/preEmitChecks.d.ts +1 -1
  116. package/dist/envelope/preEmitChecks.js +8 -0
  117. package/dist/logging/redact.d.ts +4 -0
  118. package/dist/logging/redact.js +17 -0
  119. package/dist/mcp/catalogTools.js +43 -8
  120. package/dist/mcp/controlTools.js +3 -1
  121. package/dist/mcp/deps.d.ts +2 -0
  122. package/dist/mcp/server.js +1 -0
  123. package/dist/mcp/tools.js +2 -0
  124. package/dist/mcp/triggerTools.d.ts +3 -0
  125. package/dist/mcp/triggerTools.js +176 -0
  126. package/dist/operatorAgent/docsRetrieval.d.ts +40 -0
  127. package/dist/operatorAgent/docsRetrieval.js +269 -0
  128. package/dist/operatorAgent/draftContext.d.ts +16 -0
  129. package/dist/operatorAgent/draftContext.js +68 -0
  130. package/dist/operatorAgent/fakeHost.d.ts +39 -0
  131. package/dist/operatorAgent/fakeHost.js +92 -0
  132. package/dist/operatorAgent/host.d.ts +40 -0
  133. package/dist/operatorAgent/host.js +179 -0
  134. package/dist/operatorAgent/index.d.ts +9 -0
  135. package/dist/operatorAgent/index.js +8 -0
  136. package/dist/operatorAgent/piModel.d.ts +80 -0
  137. package/dist/operatorAgent/piModel.js +528 -0
  138. package/dist/operatorAgent/profiles/workshopAuthor.d.ts +23 -0
  139. package/dist/operatorAgent/profiles/workshopAuthor.js +338 -0
  140. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +6 -0
  141. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +103 -0
  142. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +57 -0
  143. package/dist/operatorAgent/profiles/workshopAuthorTools.js +623 -0
  144. package/dist/operatorAgent/proposals.d.ts +32 -0
  145. package/dist/operatorAgent/proposals.js +144 -0
  146. package/dist/operatorAgent/types.d.ts +128 -0
  147. package/dist/operatorAgent/types.js +1 -0
  148. package/dist/package-meta.d.ts +1 -1
  149. package/dist/package-meta.js +1 -1
  150. package/dist/project/findManifestRoot.d.ts +3 -0
  151. package/dist/project/findManifestRoot.js +35 -0
  152. package/dist/project/resolveStageflowContext.d.ts +7 -0
  153. package/dist/project/resolveStageflowContext.js +44 -28
  154. package/dist/runstore/assertTmpdir.js +6 -2
  155. package/dist/runstore/port.d.ts +28 -0
  156. package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -1
  157. package/dist/runstore/sqlite/SqliteRunStore.js +90 -0
  158. package/dist/runstore/sqlite/migrations/008-triggers-table.d.ts +7 -0
  159. package/dist/runstore/sqlite/migrations/008-triggers-table.js +19 -0
  160. package/dist/runstore/sqlite/migrations/009-trigger-next-run.d.ts +7 -0
  161. package/dist/runstore/sqlite/migrations/009-trigger-next-run.js +19 -0
  162. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.d.ts +7 -0
  163. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.js +17 -0
  164. package/dist/runstore/sqlite/migrations/index.js +6 -0
  165. package/dist/runtime/answerResume.d.ts +1 -0
  166. package/dist/runtime/answerResume.js +3 -1
  167. package/dist/runtime/completionCheckRunner.d.ts +12 -1
  168. package/dist/runtime/completionCheckRunner.js +22 -0
  169. package/dist/runtime/credentialBinding.d.ts +2 -0
  170. package/dist/runtime/credentialBinding.js +3 -0
  171. package/dist/runtime/emailSource.d.ts +72 -0
  172. package/dist/runtime/emailSource.js +304 -0
  173. package/dist/runtime/githubPollSource.d.ts +86 -0
  174. package/dist/runtime/githubPollSource.js +284 -0
  175. package/dist/runtime/pipelineRunner.d.ts +4 -0
  176. package/dist/runtime/pipelineRunner.js +3 -0
  177. package/dist/runtime/pipelineScheduler.d.ts +2 -0
  178. package/dist/runtime/pipelineScheduler.js +85 -1
  179. package/dist/runtime/repositoryMaterialize.d.ts +1 -1
  180. package/dist/runtime/runManager.d.ts +11 -0
  181. package/dist/runtime/runManager.js +149 -1
  182. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  183. package/dist/runtime/runRetryCoordinator.js +1 -0
  184. package/dist/runtime/scheduleSource.d.ts +38 -0
  185. package/dist/runtime/scheduleSource.js +119 -0
  186. package/dist/runtime/settingsFile.d.ts +5 -0
  187. package/dist/runtime/settingsFile.js +61 -54
  188. package/dist/runtime/stageAttemptBootstrap.js +55 -3
  189. package/dist/runtime/stageEnvironment.js +1 -0
  190. package/dist/runtime/stageHitl.d.ts +1 -0
  191. package/dist/runtime/stageHitl.js +5 -1
  192. package/dist/runtime/stageProcessLauncher.d.ts +2 -0
  193. package/dist/runtime/stageProcessLauncher.js +44 -5
  194. package/dist/runtime/stageRunner.d.ts +5 -0
  195. package/dist/runtime/stageRunner.js +30 -6
  196. package/dist/runtime/stageStreamLog.d.ts +1 -0
  197. package/dist/runtime/stageStreamLog.js +2 -1
  198. package/dist/runtime/triggerCatalog.d.ts +6 -0
  199. package/dist/runtime/triggerCatalog.js +24 -0
  200. package/dist/runtime/triggerEventMatch.d.ts +2 -0
  201. package/dist/runtime/triggerEventMatch.js +6 -0
  202. package/dist/runtime/triggerPort.d.ts +14 -0
  203. package/dist/runtime/triggerPort.js +1 -0
  204. package/dist/runtime/triggerRunner.d.ts +17 -0
  205. package/dist/runtime/triggerRunner.js +89 -0
  206. package/dist/runtime/verifiedStageExecution.d.ts +7 -0
  207. package/dist/runtime/verifiedStageExecution.js +14 -0
  208. package/dist/runtime/webhookSignature.d.ts +1 -0
  209. package/dist/runtime/webhookSignature.js +12 -0
  210. package/dist/server/bootstrap.d.ts +6 -0
  211. package/dist/server/bootstrap.js +64 -0
  212. package/dist/server/controlToken.js +13 -0
  213. package/dist/server/createHttpHost.js +3 -0
  214. package/dist/server/healthSurfaces.js +31 -6
  215. package/dist/server/http.d.ts +15 -0
  216. package/dist/server/http.js +1251 -74
  217. package/dist/server/requestAuthContext.d.ts +1 -1
  218. package/dist/server/triggerRoutes.d.ts +15 -0
  219. package/dist/server/triggerRoutes.js +268 -0
  220. package/dist/tools/askOperator.d.ts +3 -2
  221. package/dist/types/completion.d.ts +3 -0
  222. package/dist/types/pipeline.d.ts +3 -1
  223. package/dist/types/preEmitCheck.d.ts +7 -0
  224. package/dist/types/stage.d.ts +14 -0
  225. package/dist/types/stageflowManifest.d.ts +3 -0
  226. package/dist/types/trigger.d.ts +18 -0
  227. package/dist/types/trigger.js +1 -0
  228. package/dist/ui/assets/{index-CSsDued1.css → index-Bv4p1aPK.css} +1 -1
  229. package/dist/ui/assets/index-CntB4bZR.js +133 -0
  230. package/dist/ui/index.html +2 -2
  231. package/dist/workshop/autosave.d.ts +58 -0
  232. package/dist/workshop/autosave.js +222 -0
  233. package/dist/workshop/buildStore.d.ts +79 -0
  234. package/dist/workshop/buildStore.js +326 -0
  235. package/dist/workshop/chatTurn.d.ts +232 -0
  236. package/dist/workshop/chatTurn.js +475 -0
  237. package/dist/workshop/modelSettings.d.ts +18 -0
  238. package/dist/workshop/modelSettings.js +44 -0
  239. package/dist/workshop/sessionStore.d.ts +61 -0
  240. package/dist/workshop/sessionStore.js +254 -0
  241. package/dist/workshop/workshopPin.d.ts +72 -0
  242. package/dist/workshop/workshopPin.js +193 -0
  243. package/examples/README.md +2 -1
  244. package/examples/browser-session/README.md +77 -0
  245. package/examples/browser-session/browser-session.pipeline.yaml +50 -0
  246. package/examples/browser-session/browser-session.task.yaml +6 -0
  247. package/examples/browser-session/check-login.yaml +22 -0
  248. package/examples/browser-session/fixture-server.mjs +64 -0
  249. package/examples/browser-session/human-login.yaml +31 -0
  250. package/examples/browser-session/merge.yaml +36 -0
  251. package/examples/browser-session/work-a.yaml +41 -0
  252. package/examples/browser-session/work-b.yaml +41 -0
  253. package/examples/stage-mcp/README.md +3 -2
  254. package/examples/stageflow.yaml +51 -0
  255. package/package.json +5 -1
  256. package/skills/stageflow/references/control-surface.md +3 -1
  257. package/skills/stageflow-author/references/stage-prompt-template.md +4 -4
  258. package/skills/stageflow-run/SKILL.md +2 -0
  259. package/skills/stageflow-run/references/task-and-pipeline-selection.md +3 -1
  260. package/skills/stageflow-setup/SKILL.md +11 -0
  261. package/dist/ui/assets/index-B6hlSXXn.js +0 -120
@@ -616,10 +616,14 @@ export async function runRunsCommand(args, options = {}) {
616
616
  return 1;
617
617
  }
618
618
  if (parsed.json) {
619
- printJson(out, { ok: true });
619
+ printJson(out, result.verification !== undefined
620
+ ? { ok: true, verification: result.verification }
621
+ : { ok: true });
620
622
  }
621
623
  else {
622
- out.log("ok");
624
+ out.log(result.verification !== undefined
625
+ ? `ok (${result.verification})`
626
+ : "ok");
623
627
  }
624
628
  return 0;
625
629
  }
@@ -0,0 +1,12 @@
1
+ import { type EnsureGlobalServiceResult } from "../server/ensureGlobalService.js";
2
+ export declare const TRIGGER_USAGE = "Usage:\n sf trigger list [--json]\n sf trigger show <id> [--json]\n sf trigger fire <id> [--task-inline '<json>'] [--json]";
3
+ export type TriggerCommandIo = {
4
+ log: (line: string) => void;
5
+ error: (line: string) => void;
6
+ };
7
+ export declare function runTriggerCommand(args: string[], options?: {
8
+ cwd?: string;
9
+ io?: Partial<TriggerCommandIo>;
10
+ hostBaseUrl?: string;
11
+ ensureService?: () => Promise<EnsureGlobalServiceResult>;
12
+ }): Promise<number>;
@@ -0,0 +1,183 @@
1
+ import { completeCliRun } from "./runCommand.js";
2
+ import { reportCliRun, writeQueuedAdmissionLine } from "./runOutput.js";
3
+ import { ensureGlobalService, hostBaseUrl, } from "../server/ensureGlobalService.js";
4
+ import { httpFireTrigger, httpGetTrigger, httpListTriggers, } from "./hostClient.js";
5
+ export const TRIGGER_USAGE = `Usage:
6
+ sf trigger list [--json]
7
+ sf trigger show <id> [--json]
8
+ sf trigger fire <id> [--task-inline '<json>'] [--json]`;
9
+ const defaultIo = {
10
+ log: (line) => console.log(line),
11
+ error: (line) => console.error(line),
12
+ };
13
+ function parseTriggerArgs(args) {
14
+ if (args.length === 0) {
15
+ return { help: false, json: false };
16
+ }
17
+ if (args[0] === "--help" || args[0] === "-h") {
18
+ return { help: true, json: false };
19
+ }
20
+ const subcommand = args[0];
21
+ let help = false;
22
+ let json = false;
23
+ let id;
24
+ let taskInline;
25
+ for (let i = 1; i < args.length; i++) {
26
+ const arg = args[i];
27
+ if (arg === "--help" || arg === "-h") {
28
+ help = true;
29
+ }
30
+ else if (arg === "--json") {
31
+ json = true;
32
+ }
33
+ else if (arg === "--task-inline") {
34
+ const value = args[++i];
35
+ if (value === undefined || value.length === 0) {
36
+ throw new Error("Missing value for --task-inline");
37
+ }
38
+ taskInline = value;
39
+ }
40
+ else if (arg.startsWith("-")) {
41
+ throw new Error(`Unknown flag: ${arg}`);
42
+ }
43
+ else if (id === undefined) {
44
+ id = arg;
45
+ }
46
+ else {
47
+ throw new Error(`Unexpected argument: ${arg}`);
48
+ }
49
+ }
50
+ return { help, json, subcommand, id, taskInline };
51
+ }
52
+ function parseJsonFlag(raw, flagName) {
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(raw);
56
+ }
57
+ catch {
58
+ throw new Error(`${flagName} must be valid JSON`);
59
+ }
60
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
61
+ throw new Error(`${flagName} must be a JSON object`);
62
+ }
63
+ return parsed;
64
+ }
65
+ function printJson(io, payload) {
66
+ io.log(JSON.stringify(payload, null, 2));
67
+ }
68
+ function usageError(io, message) {
69
+ if (message !== undefined)
70
+ io.error(message);
71
+ io.error(TRIGGER_USAGE);
72
+ return 1;
73
+ }
74
+ export async function runTriggerCommand(args, options = {}) {
75
+ const out = { ...defaultIo, ...options.io };
76
+ const base = options.hostBaseUrl ?? hostBaseUrl();
77
+ const ensureService = options.ensureService ?? (() => ensureGlobalService());
78
+ let parsed;
79
+ try {
80
+ parsed = parseTriggerArgs(args);
81
+ }
82
+ catch (err) {
83
+ const message = err instanceof Error ? err.message : String(err);
84
+ return usageError(out, message);
85
+ }
86
+ if (parsed.help) {
87
+ out.error(TRIGGER_USAGE);
88
+ return 0;
89
+ }
90
+ if (!parsed.subcommand) {
91
+ return usageError(out);
92
+ }
93
+ if (parsed.subcommand !== "list" &&
94
+ parsed.subcommand !== "show" &&
95
+ parsed.subcommand !== "fire") {
96
+ return usageError(out, `Unknown trigger subcommand: ${parsed.subcommand}`);
97
+ }
98
+ const ensured = await ensureService();
99
+ if (!ensured.ok) {
100
+ if (parsed.json) {
101
+ printJson(out, { error: ensured.message, reason: ensured.reason });
102
+ }
103
+ else {
104
+ out.error(ensured.message);
105
+ }
106
+ return 1;
107
+ }
108
+ const mutatingIo = out;
109
+ switch (parsed.subcommand) {
110
+ case "list": {
111
+ const result = await httpListTriggers(base);
112
+ if (!result.ok) {
113
+ const payload = { error: result.reason };
114
+ if (result.status !== undefined)
115
+ payload.status = result.status;
116
+ if (parsed.json) {
117
+ printJson(out, payload);
118
+ }
119
+ else {
120
+ out.error(result.reason);
121
+ }
122
+ return 1;
123
+ }
124
+ if (parsed.json) {
125
+ printJson(out, { triggers: result.triggers });
126
+ }
127
+ else {
128
+ for (const trigger of result.triggers) {
129
+ out.log(`${trigger.id}\t${trigger.kind}\t${trigger.enabled}`);
130
+ }
131
+ }
132
+ return 0;
133
+ }
134
+ case "show": {
135
+ if (!parsed.id) {
136
+ return usageError(out, "Missing <id>");
137
+ }
138
+ const result = await httpGetTrigger(base, parsed.id);
139
+ if (!result.ok) {
140
+ const payload = { error: result.reason };
141
+ if (result.status !== undefined)
142
+ payload.status = result.status;
143
+ if (parsed.json) {
144
+ printJson(out, payload);
145
+ }
146
+ else {
147
+ out.error(result.reason);
148
+ }
149
+ return 1;
150
+ }
151
+ if (parsed.json) {
152
+ printJson(out, result.trigger);
153
+ }
154
+ else {
155
+ out.log(`${result.trigger.id}\t${result.trigger.kind}\t${result.trigger.enabled}`);
156
+ }
157
+ return 0;
158
+ }
159
+ case "fire": {
160
+ if (!parsed.id) {
161
+ return usageError(out, "Missing <id>");
162
+ }
163
+ let task;
164
+ if (parsed.taskInline !== undefined) {
165
+ try {
166
+ task = parseJsonFlag(parsed.taskInline, "--task-inline");
167
+ }
168
+ catch (err) {
169
+ out.error(err instanceof Error ? err.message : String(err));
170
+ return 1;
171
+ }
172
+ }
173
+ const started = await httpFireTrigger(base, parsed.id, task);
174
+ if (!started.ok) {
175
+ return reportCliRun({ kind: "start-failure", started }, { json: parsed.json, io: mutatingIo });
176
+ }
177
+ writeQueuedAdmissionLine(started, mutatingIo);
178
+ return completeCliRun(started, mutatingIo, { json: parsed.json });
179
+ }
180
+ default:
181
+ return usageError(out, `Unknown trigger subcommand: ${parsed.subcommand}`);
182
+ }
183
+ }
@@ -1,5 +1,5 @@
1
1
  import { validateCatalog as defaultValidateCatalog, type ValidationResult } from "../config/validateCatalog.js";
2
- export declare const VALIDATE_USAGE = "Usage:\n sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]\n\n With no flags, validates all pipelines and tasks declared in stageflow.yaml (manifest-all).\n --pipeline validates one pipeline file (includes uses:/include: transitively).\n --task validates one task file.";
2
+ export declare const VALIDATE_USAGE = "Usage:\n sf validate [--pipeline <path>] [--task <path>] [--trigger <path>] [--strict] [--json]\n\n With no flags, validates all pipelines and tasks declared in stageflow.yaml (manifest-all).\n --pipeline validates one pipeline file (includes uses:/include: transitively).\n --task validates one task file.\n --trigger validates one trigger file, including its pipeline/task refs.";
3
3
  export type ValidateCommandIo = {
4
4
  log: (line: string) => void;
5
5
  error: (line: string) => void;
@@ -1,11 +1,12 @@
1
1
  import { validateCatalog as defaultValidateCatalog, } from "../config/validateCatalog.js";
2
2
  import { exitCodeForValidation, formatValidationHuman, formatValidationJson, } from "./validateOutput.js";
3
3
  export const VALIDATE_USAGE = `Usage:
4
- sf validate [--pipeline <path>] [--task <path>] [--strict] [--json]
4
+ sf validate [--pipeline <path>] [--task <path>] [--trigger <path>] [--strict] [--json]
5
5
 
6
6
  With no flags, validates all pipelines and tasks declared in stageflow.yaml (manifest-all).
7
7
  --pipeline validates one pipeline file (includes uses:/include: transitively).
8
- --task validates one task file.`;
8
+ --task validates one task file.
9
+ --trigger validates one trigger file, including its pipeline/task refs.`;
9
10
  const defaultIo = {
10
11
  log: (line) => console.log(line),
11
12
  error: (line) => console.error(line),
@@ -19,6 +20,7 @@ function parseValidateArgs(args) {
19
20
  }
20
21
  let pipeline;
21
22
  let task;
23
+ let trigger;
22
24
  let strict = false;
23
25
  let json = false;
24
26
  let help = false;
@@ -41,6 +43,13 @@ function parseValidateArgs(args) {
41
43
  }
42
44
  task = value;
43
45
  }
46
+ else if (arg === "--trigger") {
47
+ const value = args[++i];
48
+ if (value === undefined || value.length === 0) {
49
+ throw new Error("Missing value for --trigger");
50
+ }
51
+ trigger = value;
52
+ }
44
53
  else if (arg === "--strict") {
45
54
  strict = true;
46
55
  }
@@ -54,10 +63,11 @@ function parseValidateArgs(args) {
54
63
  throw new Error(`Unexpected argument: ${arg}`);
55
64
  }
56
65
  }
57
- if (pipeline !== undefined && task !== undefined) {
58
- throw new Error("Use at most one of --pipeline or --task");
66
+ const scopedFlagCount = [pipeline, task, trigger].filter((v) => v !== undefined).length;
67
+ if (scopedFlagCount > 1) {
68
+ throw new Error("Use at most one of --pipeline, --task, or --trigger");
59
69
  }
60
- return { help, pipeline, task, strict, json };
70
+ return { help, pipeline, task, trigger, strict, json };
61
71
  }
62
72
  export async function runValidateCommand(args, options = {}) {
63
73
  const cwd = options.cwd ?? process.cwd();
@@ -70,13 +80,20 @@ export async function runValidateCommand(args, options = {}) {
70
80
  out.error(VALIDATE_USAGE);
71
81
  return 0;
72
82
  }
73
- const scope = parsed.pipeline ? "pipeline" : parsed.task ? "task" : "full";
83
+ const scope = parsed.pipeline
84
+ ? "pipeline"
85
+ : parsed.task
86
+ ? "task"
87
+ : parsed.trigger
88
+ ? "trigger"
89
+ : "full";
74
90
  const result = await validateCatalogFn({
75
91
  scope,
76
92
  cwd,
77
93
  projectRoot,
78
94
  pipeline: parsed.pipeline,
79
95
  task: parsed.task,
96
+ trigger: parsed.trigger,
80
97
  strict: parsed.strict,
81
98
  });
82
99
  if (parsed.json) {
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ import { realpathSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { globalAgentBackendFromManifest, resolveAgentPort } from "./agent/resolveAgentPort.js";
8
+ import { BROWSER_USAGE, runBrowserCommand } from "./cli/browserCommand.js";
8
9
  import { ARTIFACT_USAGE, runArtifactCommand } from "./cli/artifactCommand.js";
9
10
  import { ENVELOPE_USAGE, runEnvelopeCommand, } from "./cli/envelopeCommand.js";
10
11
  import { EXPORT_RUN_USAGE, runExportRunCommand, } from "./cli/exportRunCommand.js";
@@ -17,6 +18,7 @@ import { PROVIDERS_USAGE, runProvidersCommand } from "./cli/providersCommand.js"
17
18
  import { RUN_USAGE, runRunCommand } from "./cli/runCommand.js";
18
19
  import { RUN_STAGE_USAGE, runRunStageCommand } from "./cli/runStageCommand.js";
19
20
  import { RUNS_USAGE, runRunsCommand } from "./cli/runsCommand.js";
21
+ import { TRIGGER_USAGE, runTriggerCommand } from "./cli/triggerCommand.js";
20
22
  import { resolveOperatorCatalog } from "./cli/operatorCatalog.js";
21
23
  import { SKILLS_USAGE, runSkillsCommand } from "./cli/skillsCommand.js";
22
24
  import { VALIDATE_USAGE, runValidateCommand } from "./cli/validateCommand.js";
@@ -73,6 +75,11 @@ const USAGE = `Usage:
73
75
  sf skills list
74
76
  sf skills install --from-path <dir> [--skill-name <name>]
75
77
  sf skills install --from-zip <url-or-path> [--skill-name <name>] [--checksum sha256:<hex>]
78
+ sf browser profiles [--json]
79
+ sf browser status <name> [--json]
80
+ sf browser check <name> --url <url> --logged-in <glob> [--logged-out <glob>]... [--headless] [--json]
81
+ sf browser login <name> --url <login-url> --logged-in <glob> [--timeout-sec <n>]
82
+ sf browser clear <name> [--yes]
76
83
  sf --version
77
84
  sf -V
78
85
  sf --help
@@ -115,9 +122,13 @@ ${EXPORT_ALL_USAGE}
115
122
 
116
123
  ${RUNS_USAGE}
117
124
 
125
+ ${TRIGGER_USAGE}
126
+
118
127
  ${PROVIDERS_USAGE}
119
128
 
120
- ${SKILLS_USAGE}`;
129
+ ${SKILLS_USAGE}
130
+
131
+ ${BROWSER_USAGE}`;
121
132
  function parseArgs(argv) {
122
133
  const args = argv.slice(2);
123
134
  if (args.length === 0) {
@@ -153,7 +164,9 @@ function parseArgs(argv) {
153
164
  command === "restore" ||
154
165
  command === "export" ||
155
166
  command === "runs" ||
156
- command === "skills") {
167
+ command === "trigger" ||
168
+ command === "skills" ||
169
+ command === "browser") {
157
170
  return { help: false, command };
158
171
  }
159
172
  if (args.includes("--help") || args.includes("-h")) {
@@ -473,6 +486,11 @@ async function main(argv) {
473
486
  cwd: ctx.invocationCwd,
474
487
  });
475
488
  }
489
+ if (parsed.command === "trigger") {
490
+ return runTriggerCommand(argv.slice(3), {
491
+ cwd: ctx.invocationCwd,
492
+ });
493
+ }
476
494
  if (parsed.command === "providers") {
477
495
  return runProvidersCommand(argv.slice(3), ctx.invocationCwd);
478
496
  }
@@ -482,6 +500,9 @@ async function main(argv) {
482
500
  projectRoot: ctx.projectRoot,
483
501
  });
484
502
  }
503
+ if (parsed.command === "browser") {
504
+ return runBrowserCommand(argv.slice(3));
505
+ }
485
506
  const globalAgent = globalAgentBackendFromManifest(ctx.manifest);
486
507
  if (parsed.command === "ui") {
487
508
  const listenHost = resolveListenHost({ flag: parsed.host });
@@ -499,6 +520,14 @@ async function main(argv) {
499
520
  mcpStateless,
500
521
  controlTokens: tokens,
501
522
  });
523
+ if (host.store) {
524
+ try {
525
+ await host.store.ensureProject(ctx.projectRoot);
526
+ }
527
+ catch {
528
+ // The console still serves seeded catalogs when this project cannot be registered.
529
+ }
530
+ }
502
531
  console.log(`Operator console: ${host.url}`);
503
532
  console.log(`MCP endpoint: ${host.mcpUrl}`);
504
533
  if (!isNoOpenEnabled(parsed.noOpen)) {
@@ -37,6 +37,7 @@ export type CatalogBrowseResult = {
37
37
  export type CatalogScanPaths = {
38
38
  pipelinePaths: string[];
39
39
  taskPaths: string[];
40
+ triggerPaths: string[];
40
41
  };
41
42
  export declare function getCatalogScanPaths(ctx: CatalogContext): Promise<CatalogScanPaths | null>;
42
43
  export declare function browseCatalog(invocationCwd: string | StageflowContext): Promise<CatalogBrowseResult>;
@@ -28,7 +28,7 @@ function bakedModels() {
28
28
  return [...BAKED_MODEL_IDS].sort((a, b) => a.localeCompare(b));
29
29
  }
30
30
  function catalogReadyFromStageflow(ctx) {
31
- return ctx.isGitProject && ctx.manifestStatus === "ok" && ctx.manifest !== null;
31
+ return ctx.manifestStatus === "ok" && ctx.manifest !== null;
32
32
  }
33
33
  function catalogReady(ctx) {
34
34
  return ctx.manifestStatus === "ok" && ctx.projectRoot !== null && ctx.manifest !== null;
@@ -37,11 +37,12 @@ export async function getCatalogScanPaths(ctx) {
37
37
  if (!catalogReady(ctx)) {
38
38
  return null;
39
39
  }
40
- const [pipelinePaths, taskPaths] = await Promise.all([
40
+ const [pipelinePaths, taskPaths, triggerPaths] = await Promise.all([
41
41
  scanCatalogPaths(ctx.manifest, "pipeline"),
42
42
  scanCatalogPaths(ctx.manifest, "task"),
43
+ scanCatalogPaths(ctx.manifest, "trigger"),
43
44
  ]);
44
- return { pipelinePaths, taskPaths };
45
+ return { pipelinePaths, taskPaths, triggerPaths };
45
46
  }
46
47
  async function listTasksFromManifest(projectRoot, manifest, warnings) {
47
48
  const filePaths = await scanCatalogPaths(manifest, "task");
@@ -122,7 +123,7 @@ export async function browseCatalog(invocationCwd) {
122
123
  ? await resolveStageflowContext(invocationCwd)
123
124
  : invocationCwd;
124
125
  const base = {
125
- projectRoot: ctx.isGitProject ? ctx.projectRoot : null,
126
+ projectRoot: ctx.manifestStatus === "not_git" ? null : ctx.projectRoot,
126
127
  manifest: ctx.manifest,
127
128
  manifestStatus: ctx.manifestStatus,
128
129
  issues: ctx.manifestIssues,
@@ -0,0 +1,4 @@
1
+ export declare const BROWSER_SKILL_NAME = "browser";
2
+ export declare function isBuiltinSkillName(name: string): boolean;
3
+ /** Absolute SKILL.md of a skill shipped inside the package, if present on disk. */
4
+ export declare function resolveBuiltinSkillFile(name: string, fromUrl?: string): string | undefined;
@@ -0,0 +1,23 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export const BROWSER_SKILL_NAME = "browser";
5
+ const BUILTIN_SKILL_NAMES = new Set([BROWSER_SKILL_NAME]);
6
+ export function isBuiltinSkillName(name) {
7
+ return BUILTIN_SKILL_NAMES.has(name);
8
+ }
9
+ /** Absolute SKILL.md of a skill shipped inside the package, if present on disk. */
10
+ export function resolveBuiltinSkillFile(name, fromUrl = import.meta.url) {
11
+ if (!isBuiltinSkillName(name))
12
+ return undefined;
13
+ const here = path.dirname(fileURLToPath(fromUrl));
14
+ for (const root of [
15
+ path.resolve(here, "../../builtin-skills"),
16
+ path.resolve(here, "../../../builtin-skills"),
17
+ ]) {
18
+ const file = path.join(root, name, "SKILL.md");
19
+ if (existsSync(file))
20
+ return file;
21
+ }
22
+ return undefined;
23
+ }
@@ -28,6 +28,7 @@ export declare function catalogPathErrorBody(err: CatalogPathError): {
28
28
  error: string;
29
29
  code: CatalogPathErrorCode;
30
30
  registered_roots: string[];
31
+ hint?: string;
31
32
  };
32
33
  /**
33
34
  * Pick the catalog root for start_run / POST /api/runs.
@@ -33,7 +33,10 @@ export function resolveCatalogRelativePath(input) {
33
33
  const field = input.fieldName ?? "path";
34
34
  const registered = input.roots.map((r) => r.project_root);
35
35
  if (path.isAbsolute(input.inputPath)) {
36
- throw new CatalogPathError(`Absolute ${field} is not allowed on network surfaces; use a catalog-relative path under a registered project_root, or an inline definition.`, "absolute_path_not_allowed", registered);
36
+ const rootsList = registered.length > 0
37
+ ? registered.join(", ")
38
+ : "(none — register a project or use seeded examples)";
39
+ throw new CatalogPathError(`Absolute ${field} is not allowed on network surfaces. Use a catalog-relative path under project_root (registered or seeded roots: ${rootsList}). Local CLI may pass absolute paths and auto-registers the project folder.`, "absolute_path_not_allowed", registered);
37
40
  }
38
41
  const root = selectCatalogRootForStart(input.roots, input.projectRoot);
39
42
  const absolutePath = path.resolve(root.path, input.inputPath);
@@ -47,11 +50,16 @@ export function resolveCatalogRelativePath(input) {
47
50
  };
48
51
  }
49
52
  export function catalogPathErrorBody(err) {
50
- return {
53
+ const body = {
51
54
  error: err.message,
52
55
  code: err.code,
53
56
  registered_roots: err.registered_roots,
54
57
  };
58
+ if (err.code === "absolute_path_not_allowed") {
59
+ body.hint =
60
+ "MCP/HTTP: relative path under project_root; CLI may pass absolute paths and auto-register.";
61
+ }
62
+ return body;
55
63
  }
56
64
  /**
57
65
  * Pick the catalog root for start_run / POST /api/runs.
@@ -0,0 +1,27 @@
1
+ import type { TriggerEvent, TriggerSchedule } from "../types/trigger.js";
2
+ import type { TriggerListItem } from "./triggerCatalog.js";
3
+ export type CreateTriggerInput = {
4
+ directory: string;
5
+ id: string;
6
+ pipeline: string;
7
+ task?: string;
8
+ kind: "manual" | "schedule" | "event";
9
+ schedule?: TriggerSchedule;
10
+ event?: TriggerEvent;
11
+ enabled?: boolean;
12
+ };
13
+ export type CreateTriggerParseError = {
14
+ ok: false;
15
+ status: 400;
16
+ error: string;
17
+ };
18
+ export type CreateTriggerResult = {
19
+ ok: true;
20
+ trigger: TriggerListItem;
21
+ } | {
22
+ ok: false;
23
+ status: 400 | 409 | 422 | 500;
24
+ error: string;
25
+ };
26
+ export declare function parseCreateTriggerBody(body: unknown): CreateTriggerInput | CreateTriggerParseError;
27
+ export declare function createTrigger(rawProjectRoot: string, input: CreateTriggerInput): Promise<CreateTriggerResult>;