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
|
@@ -63,6 +63,8 @@ export const KNOWN_STAGEFLOW_ENV_KEYS = new Set([
|
|
|
63
63
|
"STAGEFLOW_TOOLCHAIN_MANIFEST",
|
|
64
64
|
"STAGEFLOW_SECRET_REGISTRY",
|
|
65
65
|
"STAGEFLOW_BUILD_SHA",
|
|
66
|
+
"STAGEFLOW_TRIGGER_TICK_INTERVAL_MS",
|
|
67
|
+
"STAGEFLOW_GITHUB_POLL_INTERVAL_MS",
|
|
66
68
|
]);
|
|
67
69
|
const KNOWN_ENV_PREFIXES = [
|
|
68
70
|
"STAGEFLOW_PROVIDER_",
|
|
@@ -78,6 +80,7 @@ const FILE_KEY_TO_FIELD = {
|
|
|
78
80
|
trust_workspace_config: "trustWorkspaceConfig",
|
|
79
81
|
allow_unknown_config: "allowUnknownConfig",
|
|
80
82
|
callers: "callers",
|
|
83
|
+
browser: "browser",
|
|
81
84
|
};
|
|
82
85
|
const DEFAULT_MAX_CONCURRENT = 3;
|
|
83
86
|
const DEFAULT_MAX_QUEUED = 32;
|
|
@@ -299,6 +302,29 @@ export function loadHostConfig(options) {
|
|
|
299
302
|
if (file.values.callers !== undefined) {
|
|
300
303
|
callers = coerceCallers(file.values.callers, "callers");
|
|
301
304
|
}
|
|
305
|
+
let browserBlockedSites = [];
|
|
306
|
+
if (file.values.browser !== undefined) {
|
|
307
|
+
const raw = file.values.browser;
|
|
308
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
309
|
+
throw new HostConfigError(`Invalid value for browser`, "config_invalid", "browser");
|
|
310
|
+
}
|
|
311
|
+
for (const sub of Object.keys(raw)) {
|
|
312
|
+
if (sub !== "blocked_sites") {
|
|
313
|
+
throw new HostConfigError(`Unknown key "${sub}" under browser`, "config_unknown_key", `browser.${sub}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const sites = raw.blocked_sites;
|
|
317
|
+
if (sites !== undefined) {
|
|
318
|
+
browserBlockedSites = coerceFileStringList(sites, "browser.blocked_sites")
|
|
319
|
+
.map((s) => s.trim().toLowerCase().replace(/^\*\./, "").replace(/^\./, ""))
|
|
320
|
+
.filter((s) => s.length > 0);
|
|
321
|
+
for (const site of browserBlockedSites) {
|
|
322
|
+
if (!/^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/.test(site)) {
|
|
323
|
+
throw new HostConfigError(`Invalid domain "${site}" in browser.blocked_sites`, "config_invalid", "browser.blocked_sites");
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
302
328
|
return {
|
|
303
329
|
maxConcurrentRuns,
|
|
304
330
|
maxConcurrentRunsPerProject,
|
|
@@ -309,6 +335,7 @@ export function loadHostConfig(options) {
|
|
|
309
335
|
controlToken,
|
|
310
336
|
readToken,
|
|
311
337
|
callers,
|
|
338
|
+
browserBlockedSites,
|
|
312
339
|
configFilePath: configFilePath !== undefined && existsSync(configFilePath)
|
|
313
340
|
? configFilePath
|
|
314
341
|
: undefined,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type SkillScope = "user" | "project" | "temporary";
|
|
2
2
|
/** Skill resolution origin — separate from ConfigOriginKind. */
|
|
3
|
-
export type SkillOrigin = "run" | "checkout" | "host";
|
|
3
|
+
export type SkillOrigin = "run" | "checkout" | "host" | "builtin";
|
|
4
4
|
export type SkillListing = {
|
|
5
5
|
name: string;
|
|
6
6
|
description: string;
|
|
@@ -41,7 +41,7 @@ export type SkillOriginListing = {
|
|
|
41
41
|
origin: SkillOrigin;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
|
-
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir.
|
|
44
|
+
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir → package built-ins.
|
|
45
45
|
*/
|
|
46
46
|
export declare function resolveSkillByName(name: string, options: ListSkillsOptions): Promise<ResolvedSkill | undefined>;
|
|
47
47
|
export declare function listSkills(options: ListSkillsOptions): Promise<SkillCatalog>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { access, readFile, readdir } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { resolveBuiltinSkillFile } from "./builtinSkills.js";
|
|
3
4
|
import { DefaultResourceLoader, SettingsManager, } from "@earendil-works/pi-coding-agent";
|
|
4
5
|
function toListing(skill, origin) {
|
|
5
6
|
return {
|
|
@@ -102,8 +103,21 @@ function originForLoaderSkill(skill, options) {
|
|
|
102
103
|
}
|
|
103
104
|
return "host";
|
|
104
105
|
}
|
|
106
|
+
function resolveBuiltinResolved(name) {
|
|
107
|
+
const filePath = resolveBuiltinSkillFile(name);
|
|
108
|
+
if (filePath === undefined)
|
|
109
|
+
return undefined;
|
|
110
|
+
return {
|
|
111
|
+
name,
|
|
112
|
+
filePath,
|
|
113
|
+
baseDir: path.dirname(filePath),
|
|
114
|
+
scope: "user",
|
|
115
|
+
source: "builtin",
|
|
116
|
+
origin: "builtin",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
105
119
|
/**
|
|
106
|
-
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir.
|
|
120
|
+
* Resolve a skill by name. Search order: run skills → checkout `.pi/skills` → host agentDir → package built-ins.
|
|
107
121
|
*/
|
|
108
122
|
export async function resolveSkillByName(name, options) {
|
|
109
123
|
if (options.runSkillsDir !== undefined) {
|
|
@@ -119,12 +133,12 @@ export async function resolveSkillByName(name, options) {
|
|
|
119
133
|
const loader = await openSkillCatalogLoader(options);
|
|
120
134
|
const match = loader.getSkills().skills.find((skill) => skill.name === name);
|
|
121
135
|
if (!match)
|
|
122
|
-
return
|
|
136
|
+
return resolveBuiltinResolved(name);
|
|
123
137
|
try {
|
|
124
138
|
await access(match.filePath);
|
|
125
139
|
}
|
|
126
140
|
catch {
|
|
127
|
-
return
|
|
141
|
+
return resolveBuiltinResolved(name);
|
|
128
142
|
}
|
|
129
143
|
if (options.checkoutRoot !== undefined &&
|
|
130
144
|
isUnderRoot(match.filePath, path.join(options.checkoutRoot, ".pi", "skills"))) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ValidationFindingCode } from "./validateCatalog.js";
|
|
2
2
|
export type TaskLoadCode = "task.invalid_shape" | "task.load_error" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid";
|
|
3
|
+
export type TriggerLoadCode = "trigger.invalid_shape" | "trigger.load_error" | "trigger.unknown_pipeline" | "trigger.unknown_task";
|
|
3
4
|
export type LoadIssue = {
|
|
4
5
|
code: ValidationFindingCode;
|
|
5
6
|
message: string;
|
|
@@ -16,6 +17,11 @@ export type LoadIssue = {
|
|
|
16
17
|
message: string;
|
|
17
18
|
category: "task";
|
|
18
19
|
taskId?: string;
|
|
20
|
+
} | {
|
|
21
|
+
code: TriggerLoadCode;
|
|
22
|
+
message: string;
|
|
23
|
+
category: "trigger";
|
|
24
|
+
triggerId?: string;
|
|
19
25
|
} | {
|
|
20
26
|
code: ValidationFindingCode | string;
|
|
21
27
|
message: string;
|
|
@@ -13,6 +13,7 @@ import { validateCompletionContractForStage } from "./validateCompletionContract
|
|
|
13
13
|
import { applyCloneChains } from "./cloneChain.js";
|
|
14
14
|
import { collectRouteIfSchemaIssues, collectRouteIfIllegalCombos, collectRouteAllGatedWarnings, } from "./routeIf.js";
|
|
15
15
|
import { mergeToolRequires } from "./toolRequires.js";
|
|
16
|
+
import { withBrowserRequires } from "./stageBrowser.js";
|
|
16
17
|
function schemaCompileIssue(stageId, field, err, pipelineId) {
|
|
17
18
|
const message = err instanceof Error ? err.message : String(err);
|
|
18
19
|
if (err instanceof UnresolvedSchemaRefError) {
|
|
@@ -189,6 +190,15 @@ async function buildLoadedPipelineFromMerge(merge, options) {
|
|
|
189
190
|
return loadFailure(merged.issues);
|
|
190
191
|
stage = { ...stage, requires: merged.value };
|
|
191
192
|
}
|
|
193
|
+
const inlineRequires = withBrowserRequires(stage, {
|
|
194
|
+
pipelineId,
|
|
195
|
+
stageId: entry.id,
|
|
196
|
+
});
|
|
197
|
+
if (!inlineRequires.ok)
|
|
198
|
+
return loadFailure(inlineRequires.issues);
|
|
199
|
+
if (inlineRequires.value !== undefined) {
|
|
200
|
+
stage = { ...stage, requires: inlineRequires.value };
|
|
201
|
+
}
|
|
192
202
|
stages.push(stage);
|
|
193
203
|
stageSources[stageId] = { kind: "inline" };
|
|
194
204
|
continue;
|
|
@@ -244,8 +254,14 @@ async function buildLoadedPipelineFromMerge(merge, options) {
|
|
|
244
254
|
return loadFailure(merged.issues);
|
|
245
255
|
stageRequires = merged.value;
|
|
246
256
|
}
|
|
257
|
+
const browser = entry.browser ?? stageOutcome.value.browser;
|
|
258
|
+
const fileRequires = withBrowserRequires({ browser, requires: stageRequires }, { pipelineId, stageId: entry.id });
|
|
259
|
+
if (!fileRequires.ok)
|
|
260
|
+
return loadFailure(fileRequires.issues);
|
|
261
|
+
stageRequires = fileRequires.value;
|
|
247
262
|
const stage = {
|
|
248
263
|
...stageOutcome.value,
|
|
264
|
+
...(browser !== undefined ? { browser } : {}),
|
|
249
265
|
...(entry.skill !== undefined ? { skill: entry.skill } : {}),
|
|
250
266
|
...(entry.mcp !== undefined ? { mcp: entry.mcp } : {}),
|
|
251
267
|
...(entry.secrets !== undefined ? { secrets: entry.secrets } : {}),
|
package/dist/config/loadStage.js
CHANGED
|
@@ -9,6 +9,7 @@ import { parsePreEmitChecks } from "./parsePreEmitChecks.js";
|
|
|
9
9
|
import { readYamlObject } from "./readYamlObject.js";
|
|
10
10
|
import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
|
|
11
11
|
import { parseToolRequires } from "./toolRequires.js";
|
|
12
|
+
import { parseStageBrowser } from "./stageBrowser.js";
|
|
12
13
|
import { classifyYamlDocument, compileTargetContract, dialectFromKeys, mixedDialectIssue, STAGE_FILE_WIRING_KEYS, } from "./yamlDialect.js";
|
|
13
14
|
const afterCompletionByStage = new WeakMap();
|
|
14
15
|
/** After-phase IR from target `verify` (`when` includes after). Stamped onto DAG `completion`. */
|
|
@@ -366,6 +367,12 @@ function parseStageFields(raw, label, entryId, deferSchemaRefs, requireIo, compi
|
|
|
366
367
|
if (requiresOutcome.value !== undefined) {
|
|
367
368
|
stage.requires = requiresOutcome.value;
|
|
368
369
|
}
|
|
370
|
+
const browserOutcome = parseStageBrowser(raw.browser, label, entryId);
|
|
371
|
+
if (!browserOutcome.ok)
|
|
372
|
+
return browserOutcome;
|
|
373
|
+
if (browserOutcome.value !== undefined) {
|
|
374
|
+
stage.browser = browserOutcome.value;
|
|
375
|
+
}
|
|
369
376
|
const agentField = parseAgentField(raw.agent);
|
|
370
377
|
if (!agentField.ok) {
|
|
371
378
|
return loadFailure([
|
|
@@ -6,6 +6,7 @@ import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
|
6
6
|
import { parseModelField } from "./modelField.js";
|
|
7
7
|
const DEFAULT_PIPELINE_PATTERN = "*.pipeline.yaml";
|
|
8
8
|
const DEFAULT_TASK_PATTERN = "*.task.yaml";
|
|
9
|
+
const DEFAULT_TRIGGER_PATTERN = "*.trigger.yaml";
|
|
9
10
|
export function manifestPathForProject(projectRoot) {
|
|
10
11
|
return path.join(projectRoot, "stageflow.yaml");
|
|
11
12
|
}
|
|
@@ -39,6 +40,7 @@ function parsePatterns(raw, issues) {
|
|
|
39
40
|
const defaults = {
|
|
40
41
|
pipeline: DEFAULT_PIPELINE_PATTERN,
|
|
41
42
|
task: DEFAULT_TASK_PATTERN,
|
|
43
|
+
trigger: DEFAULT_TRIGGER_PATTERN,
|
|
42
44
|
};
|
|
43
45
|
if (raw === undefined || raw === null) {
|
|
44
46
|
return defaults;
|
|
@@ -58,15 +60,24 @@ function parsePatterns(raw, issues) {
|
|
|
58
60
|
: typeof record.task === "string" && record.task.trim().length > 0
|
|
59
61
|
? record.task.trim()
|
|
60
62
|
: null;
|
|
63
|
+
const trigger = record.trigger === undefined
|
|
64
|
+
? defaults.trigger
|
|
65
|
+
: typeof record.trigger === "string" && record.trigger.trim().length > 0
|
|
66
|
+
? record.trigger.trim()
|
|
67
|
+
: null;
|
|
61
68
|
if (pipeline === null) {
|
|
62
69
|
issues.push(catalogIssue("catalog.manifest_invalid", "catalog.patterns.pipeline must be a string"));
|
|
63
70
|
}
|
|
64
71
|
if (task === null) {
|
|
65
72
|
issues.push(catalogIssue("catalog.manifest_invalid", "catalog.patterns.task must be a string"));
|
|
66
73
|
}
|
|
74
|
+
if (trigger === null) {
|
|
75
|
+
issues.push(catalogIssue("catalog.manifest_invalid", "catalog.patterns.trigger must be a string"));
|
|
76
|
+
}
|
|
67
77
|
return {
|
|
68
78
|
pipeline: pipeline ?? defaults.pipeline,
|
|
69
79
|
task: task ?? defaults.task,
|
|
80
|
+
trigger: trigger ?? defaults.trigger,
|
|
70
81
|
};
|
|
71
82
|
}
|
|
72
83
|
export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoot) {
|
|
@@ -109,6 +120,14 @@ export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoo
|
|
|
109
120
|
exclude = parsed;
|
|
110
121
|
}
|
|
111
122
|
}
|
|
123
|
+
const triggersRaw = catalogRecord.triggers;
|
|
124
|
+
let triggers;
|
|
125
|
+
if (triggersRaw !== undefined) {
|
|
126
|
+
const parsed = parseStringArray(triggersRaw, "triggers", issues);
|
|
127
|
+
if (parsed !== null) {
|
|
128
|
+
triggers = parsed;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
112
131
|
const patterns = parsePatterns(catalogRecord.patterns, issues);
|
|
113
132
|
let agent;
|
|
114
133
|
const agentField = parseAgentField(record.agent);
|
|
@@ -136,6 +155,9 @@ export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoo
|
|
|
136
155
|
if (exclude !== undefined) {
|
|
137
156
|
catalog.exclude = exclude;
|
|
138
157
|
}
|
|
158
|
+
if (triggers !== undefined) {
|
|
159
|
+
catalog.triggers = triggers;
|
|
160
|
+
}
|
|
139
161
|
if (catalogRecord.patterns !== undefined) {
|
|
140
162
|
catalog.patterns = {};
|
|
141
163
|
if (typeof catalogRecord.patterns.pipeline === "string") {
|
|
@@ -144,6 +166,9 @@ export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoo
|
|
|
144
166
|
if (typeof catalogRecord.patterns.task === "string") {
|
|
145
167
|
catalog.patterns.task = patterns.task;
|
|
146
168
|
}
|
|
169
|
+
if (typeof catalogRecord.patterns.trigger === "string") {
|
|
170
|
+
catalog.patterns.trigger = patterns.trigger;
|
|
171
|
+
}
|
|
147
172
|
}
|
|
148
173
|
const manifest = {
|
|
149
174
|
version: 1,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TriggerFile } from "../types/trigger.js";
|
|
2
|
+
import { type LoadOutcome } from "./loadOutcome.js";
|
|
3
|
+
/** Structural TriggerFile shape only. */
|
|
4
|
+
export declare function coerceTriggerFile(raw: unknown): TriggerFile | undefined;
|
|
5
|
+
export declare function parseTriggerFile(raw: unknown, source?: string): LoadOutcome<TriggerFile>;
|
|
6
|
+
export declare function loadTriggerFromYamlOutcome(yamlText: string, source?: string): LoadOutcome<TriggerFile>;
|
|
7
|
+
export declare function loadTriggerOutcome(filePath: string): Promise<LoadOutcome<TriggerFile>>;
|
|
8
|
+
export declare function loadTriggerFromYaml(yamlText: string, source?: string): TriggerFile;
|
|
9
|
+
export declare function loadTrigger(filePath: string): Promise<TriggerFile>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function parseSchedule(raw) {
|
|
8
|
+
if (!isPlainObject(raw) || typeof raw.cron !== "string")
|
|
9
|
+
return undefined;
|
|
10
|
+
return {
|
|
11
|
+
cron: raw.cron,
|
|
12
|
+
...(typeof raw.timezone === "string" ? { timezone: raw.timezone } : {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function parseEvent(raw) {
|
|
16
|
+
if (!isPlainObject(raw) || typeof raw.source !== "string")
|
|
17
|
+
return undefined;
|
|
18
|
+
return {
|
|
19
|
+
source: raw.source,
|
|
20
|
+
...(isPlainObject(raw.match) ? { match: raw.match } : {}),
|
|
21
|
+
...(isPlainObject(raw.config) ? { config: raw.config } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Structural TriggerFile shape only. */
|
|
25
|
+
export function coerceTriggerFile(raw) {
|
|
26
|
+
const record = raw;
|
|
27
|
+
if (typeof record?.id !== "string" ||
|
|
28
|
+
typeof record?.pipeline !== "string" ||
|
|
29
|
+
typeof record?.enabled !== "boolean") {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (record.task !== undefined && typeof record.task !== "string") {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (record.kind !== "manual" && record.kind !== "schedule" && record.kind !== "event") {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
let schedule;
|
|
39
|
+
if (record.schedule !== undefined) {
|
|
40
|
+
schedule = parseSchedule(record.schedule);
|
|
41
|
+
if (schedule === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
let event;
|
|
45
|
+
if (record.event !== undefined) {
|
|
46
|
+
event = parseEvent(record.event);
|
|
47
|
+
if (event === undefined)
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
id: record.id,
|
|
52
|
+
pipeline: record.pipeline,
|
|
53
|
+
kind: record.kind,
|
|
54
|
+
enabled: record.enabled,
|
|
55
|
+
...(typeof record.task === "string" ? { task: record.task } : {}),
|
|
56
|
+
...(schedule !== undefined ? { schedule } : {}),
|
|
57
|
+
...(event !== undefined ? { event } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function parseTriggerFile(raw, source = "trigger") {
|
|
61
|
+
const record = raw;
|
|
62
|
+
const trigger = coerceTriggerFile(raw);
|
|
63
|
+
if (trigger === undefined) {
|
|
64
|
+
return loadFailure([
|
|
65
|
+
{
|
|
66
|
+
code: "trigger.invalid_shape",
|
|
67
|
+
message: `Invalid ${source}: id, pipeline, kind, and enabled are required`,
|
|
68
|
+
category: "trigger",
|
|
69
|
+
triggerId: typeof record?.id === "string" ? record.id : undefined,
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
return loadSuccess(trigger);
|
|
74
|
+
}
|
|
75
|
+
export function loadTriggerFromYamlOutcome(yamlText, source = "trigger yaml") {
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = parseYaml(yamlText);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
82
|
+
return loadFailure([
|
|
83
|
+
{
|
|
84
|
+
code: "trigger.load_error",
|
|
85
|
+
message,
|
|
86
|
+
category: "trigger",
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
return parseTriggerFile(raw, source);
|
|
91
|
+
}
|
|
92
|
+
export async function loadTriggerOutcome(filePath) {
|
|
93
|
+
let yamlText;
|
|
94
|
+
try {
|
|
95
|
+
yamlText = await readFile(filePath, "utf8");
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
99
|
+
return loadFailure([
|
|
100
|
+
{
|
|
101
|
+
code: "trigger.load_error",
|
|
102
|
+
message,
|
|
103
|
+
category: "trigger",
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
return loadTriggerFromYamlOutcome(yamlText, `trigger file ${filePath}`);
|
|
108
|
+
}
|
|
109
|
+
export function loadTriggerFromYaml(yamlText, source = "trigger yaml") {
|
|
110
|
+
const outcome = loadTriggerFromYamlOutcome(yamlText, source);
|
|
111
|
+
if (!outcome.ok)
|
|
112
|
+
throw new Error(outcome.issues[0].message);
|
|
113
|
+
return outcome.value;
|
|
114
|
+
}
|
|
115
|
+
export async function loadTrigger(filePath) {
|
|
116
|
+
const outcome = await loadTriggerOutcome(filePath);
|
|
117
|
+
if (!outcome.ok)
|
|
118
|
+
throw new Error(outcome.issues[0].message);
|
|
119
|
+
return outcome.value;
|
|
120
|
+
}
|
|
@@ -9,7 +9,9 @@ export type MultiProjectListResult<T> = {
|
|
|
9
9
|
items: T[];
|
|
10
10
|
root_errors: CatalogRootError[];
|
|
11
11
|
roots: CatalogRoot[];
|
|
12
|
+
tip?: string;
|
|
12
13
|
};
|
|
14
|
+
export declare const EMPTY_CATALOG_LIST_TIP = "No catalog entries listed. Register a project root (POST /api/projects or local sf run / ensure), ensure stageflow.yaml exists at that root, then retry list_pipelines / list_tasks. Packaged examples use project_root \"examples\" when present. Git is not required for discovery.";
|
|
13
15
|
export declare function listPipelinesMultiProject(options: ResolveCatalogRootsOptions & {
|
|
14
16
|
projectRootFilter?: string;
|
|
15
17
|
}): Promise<MultiProjectListResult<PipelineListing & {
|
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import { listModelsForContext, listPipelinesForContext, listTasksForContext, } from "./browseCatalog.js";
|
|
2
2
|
import { loadStageflowManifestOutcome, } from "./loadStageflowManifest.js";
|
|
3
3
|
import { findCatalogRoot, isRootReadable, resolveCatalogRoots, } from "./resolveCatalogRoots.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export const EMPTY_CATALOG_LIST_TIP = "No catalog entries listed. Register a project root (POST /api/projects or local sf run / ensure), ensure stageflow.yaml exists at that root, then retry list_pipelines / list_tasks. Packaged examples use project_root \"examples\" when present. Git is not required for discovery.";
|
|
5
|
+
function listTip(itemsLength, root_errors) {
|
|
6
|
+
if (itemsLength > 0)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (root_errors.some((e) => e.code === "unknown_project_root")) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return EMPTY_CATALOG_LIST_TIP;
|
|
12
|
+
}
|
|
6
13
|
async function catalogContextForRoot(root) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!outcome.ok) {
|
|
10
|
-
return {
|
|
11
|
-
projectRoot: root.path,
|
|
12
|
-
manifest: null,
|
|
13
|
-
manifestStatus: "invalid",
|
|
14
|
-
issues: outcome.issues,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
14
|
+
const outcome = await loadStageflowManifestOutcome(root.path);
|
|
15
|
+
if (!outcome.ok) {
|
|
17
16
|
return {
|
|
18
17
|
projectRoot: root.path,
|
|
19
|
-
manifest:
|
|
20
|
-
manifestStatus: "
|
|
21
|
-
issues:
|
|
18
|
+
manifest: null,
|
|
19
|
+
manifestStatus: "invalid",
|
|
20
|
+
issues: outcome.issues,
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
|
-
return
|
|
23
|
+
return {
|
|
24
|
+
projectRoot: root.path,
|
|
25
|
+
manifest: outcome.value,
|
|
26
|
+
manifestStatus: "ok",
|
|
27
|
+
issues: [],
|
|
28
|
+
};
|
|
25
29
|
}
|
|
26
30
|
async function selectRoots(options) {
|
|
27
31
|
const roots = await resolveCatalogRoots(options);
|
|
@@ -70,6 +74,10 @@ async function selectRoots(options) {
|
|
|
70
74
|
}
|
|
71
75
|
return { roots, selected, root_errors };
|
|
72
76
|
}
|
|
77
|
+
function withListTip(result) {
|
|
78
|
+
const tip = listTip(result.items.length, result.root_errors);
|
|
79
|
+
return tip !== undefined ? { ...result, tip } : result;
|
|
80
|
+
}
|
|
73
81
|
export async function listPipelinesMultiProject(options) {
|
|
74
82
|
const { roots, selected, root_errors } = await selectRoots(options);
|
|
75
83
|
const items = [];
|
|
@@ -89,7 +97,7 @@ export async function listPipelinesMultiProject(options) {
|
|
|
89
97
|
});
|
|
90
98
|
}
|
|
91
99
|
}
|
|
92
|
-
return { items, root_errors, roots };
|
|
100
|
+
return withListTip({ items, root_errors, roots });
|
|
93
101
|
}
|
|
94
102
|
export async function listTasksMultiProject(options) {
|
|
95
103
|
const { roots, selected, root_errors } = await selectRoots(options);
|
|
@@ -110,7 +118,7 @@ export async function listTasksMultiProject(options) {
|
|
|
110
118
|
});
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
|
-
return { items, root_errors, roots };
|
|
121
|
+
return withListTip({ items, root_errors, roots });
|
|
114
122
|
}
|
|
115
123
|
export async function listModelsMultiProject(options) {
|
|
116
124
|
const { roots, selected, root_errors } = await selectRoots(options);
|
|
@@ -8,6 +8,7 @@ import path from "node:path";
|
|
|
8
8
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
9
9
|
import { parseStageMcp } from "./loadStage.js";
|
|
10
10
|
import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
|
|
11
|
+
import { parseStageBrowser } from "./stageBrowser.js";
|
|
11
12
|
import { parseToolRequires } from "./toolRequires.js";
|
|
12
13
|
import { legacyAuthoringRejected, presentLegacyKeys } from "./legacyYaml.js";
|
|
13
14
|
import { compileTargetContract, dialectFromKeys, mixedDialectIssue, } from "./yamlDialect.js";
|
|
@@ -45,7 +46,8 @@ function hasBodyKey(raw) {
|
|
|
45
46
|
key !== "skill" &&
|
|
46
47
|
key !== "mcp" &&
|
|
47
48
|
key !== "secrets" &&
|
|
48
|
-
key !== "requires"
|
|
49
|
+
key !== "requires" &&
|
|
50
|
+
key !== "browser");
|
|
49
51
|
}
|
|
50
52
|
function readSkill(raw) {
|
|
51
53
|
if (raw.skill === undefined)
|
|
@@ -129,6 +131,10 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
|
|
|
129
131
|
if (!requiresOutcome.ok)
|
|
130
132
|
return requiresOutcome;
|
|
131
133
|
const requires = requiresOutcome.value;
|
|
134
|
+
const browserOutcome = parseStageBrowser(raw.browser, `entry at index ${index} in ${declaringPath}`, typeof raw.id === "string" ? raw.id : undefined);
|
|
135
|
+
if (!browserOutcome.ok)
|
|
136
|
+
return browserOutcome;
|
|
137
|
+
const browser = browserOutcome.value;
|
|
132
138
|
if (uses && hasBody) {
|
|
133
139
|
return loadFailure([
|
|
134
140
|
{
|
|
@@ -358,6 +364,7 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
|
|
|
358
364
|
...(mcp !== undefined ? { mcp } : {}),
|
|
359
365
|
...(secrets !== undefined ? { secrets } : {}),
|
|
360
366
|
...(requires !== undefined ? { requires } : {}),
|
|
367
|
+
...(browser !== undefined ? { browser } : {}),
|
|
361
368
|
...(cloneCap !== undefined ? { clone_cap: cloneCap } : {}),
|
|
362
369
|
...(cloneMode !== undefined ? { clone_mode: cloneMode } : {}),
|
|
363
370
|
};
|
|
@@ -124,6 +124,12 @@ function parseCheck(raw, stageId, index) {
|
|
|
124
124
|
return failure(stageId, "completion", `checks[${index}]: unknown key "${unknown}"`);
|
|
125
125
|
return loadSuccess({ id, type: "payload_schema" });
|
|
126
126
|
}
|
|
127
|
+
if (raw.type === "browser_login") {
|
|
128
|
+
const unknown = hasOnlyKeys(raw, ["id", "type"]);
|
|
129
|
+
if (unknown)
|
|
130
|
+
return failure(stageId, "completion", `checks[${index}]: unknown key "${unknown}"`);
|
|
131
|
+
return loadSuccess({ id, type: "browser_login" });
|
|
132
|
+
}
|
|
127
133
|
if (raw.type === "gate") {
|
|
128
134
|
const unknown = hasOnlyKeys(raw, ["id", "type", "kind"]);
|
|
129
135
|
if (unknown)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type CreateDraftPackageInput, type DraftPackageWriteResult } from "./draftPackage.js";
|
|
2
|
+
export type PublishDraftPackageMode = "create" | "overwrite" | "auto";
|
|
3
|
+
export type PublishDraftPackageResult = {
|
|
4
|
+
write: DraftPackageWriteResult;
|
|
5
|
+
catalogChanged: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function publishDraftPackage(projectRoot: string, input: CreateDraftPackageInput, mode: PublishDraftPackageMode): Promise<PublishDraftPackageResult>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createDraftPackage, overwriteDraftPackage, } from "./draftPackage.js";
|
|
2
|
+
import { ensureCatalogScanRoot } from "./ensureCatalogScanRoot.js";
|
|
3
|
+
export async function publishDraftPackage(projectRoot, input, mode) {
|
|
4
|
+
let write;
|
|
5
|
+
if (mode === "create") {
|
|
6
|
+
write = await createDraftPackage(projectRoot, input);
|
|
7
|
+
}
|
|
8
|
+
else if (mode === "overwrite") {
|
|
9
|
+
write = await overwriteDraftPackage(projectRoot, input);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const created = await createDraftPackage(projectRoot, input);
|
|
13
|
+
if (created.ok || created.status !== 409) {
|
|
14
|
+
write = created;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
write = await overwriteDraftPackage(projectRoot, input);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (!write.ok) {
|
|
21
|
+
return { write, catalogChanged: false };
|
|
22
|
+
}
|
|
23
|
+
const catalogChanged = await ensureCatalogScanRoot(projectRoot, input.directory);
|
|
24
|
+
return { write, catalogChanged };
|
|
25
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveStageflowContext, } from "../project/resolveStageflowContext.js";
|
|
2
2
|
export function catalogContextFromStageflow(ctx) {
|
|
3
3
|
return {
|
|
4
|
-
projectRoot: ctx.
|
|
4
|
+
projectRoot: ctx.manifestStatus === "not_git" ? null : ctx.projectRoot,
|
|
5
5
|
manifest: ctx.manifest,
|
|
6
6
|
manifestStatus: ctx.manifestStatus,
|
|
7
7
|
issues: ctx.manifestIssues,
|
|
@@ -18,7 +18,7 @@ function wrapRawStagesForNormalize(rawStages, ctx) {
|
|
|
18
18
|
}
|
|
19
19
|
const id = typeof raw.id === "string" && raw.id ? raw.id : undefined;
|
|
20
20
|
const hasUses = typeof raw.uses === "string";
|
|
21
|
-
const hasBody = Object.keys(raw).some((key) => BODY_KEYS.has(key) && key !== "skill" && key !== "mcp");
|
|
21
|
+
const hasBody = Object.keys(raw).some((key) => BODY_KEYS.has(key) && key !== "skill" && key !== "mcp" && key !== "browser");
|
|
22
22
|
if (hasUses || hasBody || !id) {
|
|
23
23
|
return { raw, declaringPath: ctx.path };
|
|
24
24
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { LoadedManifest } from "../types/stageflowManifest.js";
|
|
2
|
-
export type CatalogPathKind = "pipeline" | "task";
|
|
2
|
+
export type CatalogPathKind = "pipeline" | "task" | "trigger";
|
|
3
3
|
export declare function isExcluded(repoRelPath: string, exclude: string[] | undefined): boolean;
|
|
4
4
|
export declare function scanCatalogPaths(manifest: LoadedManifest, kind: CatalogPathKind): Promise<string[]>;
|
|
@@ -60,8 +60,12 @@ async function expandCatalogEntry(projectRoot, entry, kind, pattern) {
|
|
|
60
60
|
}
|
|
61
61
|
export async function scanCatalogPaths(manifest, kind) {
|
|
62
62
|
const { projectRoot, manifest: doc, patterns } = manifest;
|
|
63
|
-
const entries = kind === "pipeline"
|
|
64
|
-
|
|
63
|
+
const entries = kind === "pipeline"
|
|
64
|
+
? doc.catalog.pipelines
|
|
65
|
+
: kind === "task"
|
|
66
|
+
? doc.catalog.tasks
|
|
67
|
+
: (doc.catalog.triggers ?? []);
|
|
68
|
+
const pattern = kind === "pipeline" ? patterns.pipeline : kind === "task" ? patterns.task : patterns.trigger;
|
|
65
69
|
const exclude = doc.catalog.exclude;
|
|
66
70
|
const seen = new Set();
|
|
67
71
|
const resolved = [];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StageBrowserConfig } from "../types/stage.js";
|
|
2
|
+
import { type LoadOutcome } from "./loadOutcome.js";
|
|
3
|
+
import { type ToolRequirement } from "./toolRequires.js";
|
|
4
|
+
export declare const BROWSER_TOOL_NAME = "agent-browser";
|
|
5
|
+
export declare function parseStageBrowser(raw: unknown, label: string, stageId?: string): LoadOutcome<StageBrowserConfig | undefined>;
|
|
6
|
+
export declare function withBrowserRequires(stage: {
|
|
7
|
+
browser?: StageBrowserConfig;
|
|
8
|
+
requires?: ToolRequirement[];
|
|
9
|
+
}, ctx: {
|
|
10
|
+
pipelineId: string;
|
|
11
|
+
stageId: string;
|
|
12
|
+
}): LoadOutcome<ToolRequirement[] | undefined>;
|