@keystrokehq/cli 0.0.1
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/AGENTS-blurb.md +123 -0
- package/LICENSE +42 -0
- package/README.md +177 -0
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/bin/keystroke.mjs +107 -0
- package/dist/_manifest-JSRE3H8k.mjs +385 -0
- package/dist/agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs +2344 -0
- package/dist/agent-manifest-CDnbkR2f.mjs +245 -0
- package/dist/agents-CZJGxVqV.mjs +228 -0
- package/dist/api-keys-D2lgguuY.mjs +40 -0
- package/dist/auth-DN2VusyU.mjs +59 -0
- package/dist/auth.handler-CT1BQUvu.mjs +340 -0
- package/dist/browser-qwFrUH82.mjs +24 -0
- package/dist/build-agents-BmM_AsSd-BGi9wtzt.mjs +514 -0
- package/dist/build-metadata-BWS7uhd_-DR8gJjTX.mjs +1422 -0
- package/dist/build-progress-DgYKb4hB.mjs +183 -0
- package/dist/build-tasks-CdihpudT-D5r5HUHe.mjs +91 -0
- package/dist/build-workflows-CfxBnIWh-CdYPv8w2.mjs +370 -0
- package/dist/build.handler-4799CjWH.mjs +36 -0
- package/dist/chunk-CH6r78ws.mjs +37 -0
- package/dist/clear-cache.handler-B9tqSoSM.mjs +11 -0
- package/dist/clear.handler-BTIXXPTJ.mjs +42 -0
- package/dist/clear.handler-BydlX-zE.mjs +11 -0
- package/dist/commander-DfTVqQ-3.mjs +133 -0
- package/dist/concurrency-gXn9Rw8x-DNl2YtrS.mjs +20 -0
- package/dist/connect-BUXkeH0F.mjs +43 -0
- package/dist/connect.handler-CYel9cy6.mjs +430 -0
- package/dist/constants-CPpPdSNg.mjs +8 -0
- package/dist/context-T7HZuB97.mjs +138 -0
- package/dist/credential-env-map-CI8yWHVy.mjs +28 -0
- package/dist/credential-schema-mismatch-BKo5PjcQ.mjs +76 -0
- package/dist/credentials-CvmjU0lK.mjs +171 -0
- package/dist/credentials-OfVHOtG3.mjs +151216 -0
- package/dist/current-deployment-workflow-poHt27i3.mjs +94 -0
- package/dist/current.handler-B8zKzfPp.mjs +21 -0
- package/dist/delete.handler-bAu1iXVQ.mjs +17 -0
- package/dist/deploy-7Jjls436.mjs +26 -0
- package/dist/deploy-BOPIpRWm.mjs +74 -0
- package/dist/deploy-progress-BmGUNFKg.mjs +70 -0
- package/dist/deploy.handler-BAzgiNhd.mjs +370 -0
- package/dist/detect-env-access-CwkOYeYM-D_BCZqV6.mjs +209 -0
- package/dist/diff-utils-NEfcjqxt.mjs +185 -0
- package/dist/diff.handler-Du7SY8K4.mjs +47 -0
- package/dist/dist-BkJUoBiG.mjs +1116 -0
- package/dist/dist-CUK7yBM0.mjs +308 -0
- package/dist/env-91KwMKov.mjs +140 -0
- package/dist/env.handler-BAzBuMzQ.mjs +277 -0
- package/dist/error-boundary-VL-JLfIa.mjs +34 -0
- package/dist/file-metadata-D1vm-XY2.mjs +191 -0
- package/dist/get-intrinsic-zLxwtrLK.mjs +658 -0
- package/dist/import-module-CV84H5fZ-B_CBCmb4.mjs +1747 -0
- package/dist/init-DpMCotSK.mjs +45 -0
- package/dist/init.handler-CPRnif52.mjs +585 -0
- package/dist/inspect.handler-DT_cD036.mjs +146 -0
- package/dist/integration-catalog-Bt-L3GjF.mjs +104 -0
- package/dist/integrations-DlatPK4W.mjs +79 -0
- package/dist/keystroke.d.mts +3 -0
- package/dist/keystroke.mjs +707 -0
- package/dist/layout-CbMtQ2tm.mjs +67 -0
- package/dist/list-enrichment-y-cwizLr.mjs +189 -0
- package/dist/list.handler-BTWvCyjA.mjs +52 -0
- package/dist/list.handler-CWF_Dj15.mjs +24 -0
- package/dist/list.handler-CZ6G2x_G.mjs +75 -0
- package/dist/list.handler-DWaQkJaR.mjs +51 -0
- package/dist/list.handler-DqbFcBW7.mjs +180 -0
- package/dist/list.handler-lq3ZGAn4.mjs +104 -0
- package/dist/logs-BEg9L5l8.mjs +28 -0
- package/dist/logs.handler-6hoMBzqw.mjs +35 -0
- package/dist/logs.handler-BD_dXiL1.mjs +231 -0
- package/dist/metadata-layout-GUYIUo0i-_aG2zjue.mjs +5877 -0
- package/dist/normalize-path-CojS-CgQ-DLCOvnD1.mjs +20 -0
- package/dist/options-CeaTcFxP.mjs +43 -0
- package/dist/org-xLzBtt2_.mjs +41 -0
- package/dist/output-DM4b7KgY.mjs +72 -0
- package/dist/oxc-B3KI3rf_-n9d1hKNq.mjs +119 -0
- package/dist/paused.handler-BMFm9Cff.mjs +94 -0
- package/dist/project-config-D1qsQlO7.mjs +107 -0
- package/dist/projects-CHkRE9rS.mjs +1574 -0
- package/dist/projects-Cjb7sovS.mjs +30 -0
- package/dist/read-credential-keys-77a91T8M-KA0Iw0Z1.mjs +9 -0
- package/dist/register.handler-BPCdor1_.mjs +86 -0
- package/dist/requirements.handler-DPXdSks3.mjs +201 -0
- package/dist/resolve-project-DDJ29sCF.mjs +35 -0
- package/dist/rolldown-runtime-twds-ZHy-BWWzu8VG.mjs +15 -0
- package/dist/run-polling-CAgFRdK3.mjs +20 -0
- package/dist/runs-D9hNLb9A.mjs +259 -0
- package/dist/schedule-BXx3uXwr.mjs +1142 -0
- package/dist/schema-17qMfNyI.mjs +18 -0
- package/dist/schema-display-CgmeKigW.mjs +130 -0
- package/dist/schemas-CDib1RhE.mjs +125 -0
- package/dist/skills-sync.handler-DIy8GR16.mjs +34 -0
- package/dist/skills.command-CrjI2dN9.mjs +35 -0
- package/dist/skills.handler-Bz8bJKql.mjs +9 -0
- package/dist/source-analysis-Cj-ADyu--BJQcFPCG.mjs +144 -0
- package/dist/spinner-progress-DMVwgqO9.mjs +173 -0
- package/dist/src-C0X6u_Mw.mjs +1340 -0
- package/dist/src-eHwu-Gfw.mjs +369 -0
- package/dist/status.handler-BO4nwvWn.mjs +101 -0
- package/dist/switch.handler-D_9213Vf.mjs +51 -0
- package/dist/sync-BL_Mo5st.mjs +39 -0
- package/dist/sync-keystroke-agent-skills-Kx_H7UTd.mjs +70 -0
- package/dist/sync.handler-BUFPdzWz.mjs +82 -0
- package/dist/task-B2sZMaZu.mjs +8 -0
- package/dist/task-target-build-CBeCKbu2.mjs +432 -0
- package/dist/task-target-deploy-C5X-USeR.mjs +4 -0
- package/dist/task-target-deploy-CA6elFpF-BEr4gkol.mjs +271 -0
- package/dist/task-target-deploy-runner.d.mts +3 -0
- package/dist/task-target-deploy-runner.mjs +202 -0
- package/dist/test-BHTgR3UA.mjs +698 -0
- package/dist/test.handler-BcPQ8b74.mjs +13 -0
- package/dist/trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs +239 -0
- package/dist/trigger-manifest-CY7brZeg.mjs +30 -0
- package/dist/try-deploy.handler-DqybNhXx.mjs +490 -0
- package/dist/upload-CkU--iDC.mjs +207 -0
- package/dist/upload.handler-DCtiznQp.mjs +441 -0
- package/dist/utils-CywxCDM7.mjs +14 -0
- package/dist/validate.handler-DOcTaJL0.mjs +280 -0
- package/dist/workflow-build-DBQaBfnn.mjs +1819 -0
- package/dist/workflow-bundler-BPiqVscj-X1PFFAuP.mjs +167 -0
- package/dist/workflows-g9z87AJJ.mjs +799 -0
- package/dist/writer-BG8poUm3-BbXlU2kI.mjs +426 -0
- package/package.json +87 -0
|
@@ -0,0 +1,1819 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { i as __toESM, n as __exportAll } from "./chunk-CH6r78ws.mjs";
|
|
4
|
+
import { a as originalConsole, h as toErrorMessage, i as logger, o as ANSI, s as style, t as ui } from "./keystroke.mjs";
|
|
5
|
+
import { a as getKeystrokeTmpDir } from "./dist-CUK7yBM0.mjs";
|
|
6
|
+
import { t as assertWorkflowProjectRoot } from "./project-config-D1qsQlO7.mjs";
|
|
7
|
+
import { c as FlowGraphSchema, s as WorkflowManifestSchema } from "./_manifest-JSRE3H8k.mjs";
|
|
8
|
+
import { t as AgentVersionManifestSchema } from "./agent-manifest-CDnbkR2f.mjs";
|
|
9
|
+
import { r as RelativeFilePathSchema } from "./file-metadata-D1vm-XY2.mjs";
|
|
10
|
+
import { c as createArtifactOutputFiles, l as createMetadataOutputFile, o as METADATA_ROOT_DIR_NAME, p as getWorkflowArtifactPaths, t as BUILD_DIR_NAME } from "./layout-CbMtQ2tm.mjs";
|
|
11
|
+
import { t as resolveConfiguredBuildOutputDir } from "./utils-CywxCDM7.mjs";
|
|
12
|
+
import { a as readAgentSandboxPackage, r as AGENT_VM_TOOLS_RUNTIME_RELATIVE_PATH } from "./agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs";
|
|
13
|
+
import { a as prewarmFileContentCache, c as typedEntries, i as createFileContentCache, l as require_out, n as computeBuilderFingerprint, o as resetFileContentCache, r as computeWorkflowFingerprint, s as sha256String } from "./metadata-layout-GUYIUo0i-_aG2zjue.mjs";
|
|
14
|
+
import { a as getAgentArtifactPaths, c as hashWorkflowManifestForDisk, d as resolveOutputDir, i as createAgentOutputFiles, l as removeAgentArtifacts, n as BUILD_CACHE_FILE_NAME, o as hashAgentManifestForDisk, r as allOutputFilesExist, s as hashWorkflowFlowForDisk, t as AGENT_ARTIFACT_DIR_PREFIX, u as removeWorkflowArtifacts } from "./writer-BG8poUm3-BbXlU2kI.mjs";
|
|
15
|
+
import { a as createDiscoveryFailure, c as createNamespaceStarExportDiscoveryError, d as isWorkflowLoadResult, f as loadWorkflowMetadataBatch, i as createAmbiguousExportDiscoveryError, l as isAgentLoadResult, o as createDuplicateWorkflowIdFailure, t as DuplicateWorkflowIdError, u as isTaskLoadResult } from "./import-module-CV84H5fZ-B_CBCmb4.mjs";
|
|
16
|
+
import { a as literalString, n as identifierName, o as parseSourceFile, r as isNode } from "./oxc-B3KI3rf_-n9d1hKNq.mjs";
|
|
17
|
+
import { a as getLocalModuleSpecifier, c as removeAllMetadataArtifacts, d as resolveDefaultExportAssignment, f as resolveLocalModulePath, i as collectWorkflowImportNames, n as DISCOVERY_IGNORE, o as getVariableDeclarators, r as collectLocalWorkflowBindings, s as isExportedVariableStatement, t as DISCOVERY_GLOB, u as removeMetadataArtifacts } from "./source-analysis-Cj-ADyu--BJQcFPCG.mjs";
|
|
18
|
+
import { n as parseRelativeFilePath } from "./normalize-path-CojS-CgQ-DLCOvnD1.mjs";
|
|
19
|
+
import * as fs from "node:fs/promises";
|
|
20
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
21
|
+
import * as path$1 from "node:path";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
import { createHash } from "node:crypto";
|
|
26
|
+
import "oxc-parser";
|
|
27
|
+
import { performance } from "node:perf_hooks";
|
|
28
|
+
//#region ../../packages/workflow-core/dist/chunks/schema-DnT5yizJ.mjs
|
|
29
|
+
var import_out = /* @__PURE__ */ __toESM(require_out(), 1);
|
|
30
|
+
const MAX_JSON_DEPTH = 20;
|
|
31
|
+
function buildJsonValueSchema(depth) {
|
|
32
|
+
const primitives = z.union([
|
|
33
|
+
z.string(),
|
|
34
|
+
z.number(),
|
|
35
|
+
z.boolean(),
|
|
36
|
+
z.null()
|
|
37
|
+
]);
|
|
38
|
+
if (depth <= 0) return primitives;
|
|
39
|
+
const nested = buildJsonValueSchema(depth - 1);
|
|
40
|
+
return z.union([
|
|
41
|
+
primitives,
|
|
42
|
+
z.array(nested),
|
|
43
|
+
z.record(z.string(), nested)
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
const jsonValueSchema = buildJsonValueSchema(MAX_JSON_DEPTH);
|
|
47
|
+
z.record(z.string(), jsonValueSchema);
|
|
48
|
+
z.custom((value) => value instanceof z.ZodType, "Expected a Zod schema");
|
|
49
|
+
z.custom((value) => value instanceof z.ZodObject, "Expected a Zod object schema");
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region ../../packages/workflow-core/dist/flow-graph-toolkit/index.mjs
|
|
52
|
+
function detectAgentInPathCycles(input) {
|
|
53
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
54
|
+
const edges = /* @__PURE__ */ new Map();
|
|
55
|
+
for (const node of [
|
|
56
|
+
...input.agents,
|
|
57
|
+
...input.workflows,
|
|
58
|
+
...input.operations
|
|
59
|
+
]) {
|
|
60
|
+
nodes.set(node.id, node);
|
|
61
|
+
edges.set(node.id, node.kind === "agent" ? node.tools : node.kind === "workflow" ? node.callees : []);
|
|
62
|
+
}
|
|
63
|
+
const cycles = [];
|
|
64
|
+
const path = [];
|
|
65
|
+
const visited = /* @__PURE__ */ new Set();
|
|
66
|
+
const visit = (id) => {
|
|
67
|
+
const existingIndex = path.indexOf(id);
|
|
68
|
+
if (existingIndex >= 0) {
|
|
69
|
+
const cycleNodes = path.slice(existingIndex).concat(id).flatMap((cycleId) => {
|
|
70
|
+
const node = nodes.get(cycleId);
|
|
71
|
+
return node ? [toCycleNode(node)] : [];
|
|
72
|
+
});
|
|
73
|
+
if (cycleNodes.some((node) => node.kind === "agent")) cycles.push({
|
|
74
|
+
path: cycleNodes,
|
|
75
|
+
description: cycleNodes.map((node) => `${node.kind}:${node.id}`).join(" -> ")
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (visited.has(id)) return;
|
|
80
|
+
visited.add(id);
|
|
81
|
+
path.push(id);
|
|
82
|
+
for (const next of edges.get(id) ?? []) visit(next);
|
|
83
|
+
path.pop();
|
|
84
|
+
};
|
|
85
|
+
for (const id of nodes.keys()) visit(id);
|
|
86
|
+
return cycles;
|
|
87
|
+
}
|
|
88
|
+
function toCycleNode(node) {
|
|
89
|
+
return {
|
|
90
|
+
kind: node.kind,
|
|
91
|
+
id: node.id,
|
|
92
|
+
displayName: node.displayName,
|
|
93
|
+
source: node.source
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region ../../packages/workflow-builder/dist/build-9Sd6SkIz.mjs
|
|
98
|
+
const DiscoveredWorkflowSchema = z.object({
|
|
99
|
+
exportFilePath: z.string(),
|
|
100
|
+
resolvedFilePath: z.string(),
|
|
101
|
+
relativePath: z.string(),
|
|
102
|
+
exportName: z.string(),
|
|
103
|
+
isDefaultExport: z.boolean(),
|
|
104
|
+
localExportName: z.string(),
|
|
105
|
+
bindingKey: z.string(),
|
|
106
|
+
exportKind: z.union([
|
|
107
|
+
z.literal("workflow"),
|
|
108
|
+
z.literal("agent"),
|
|
109
|
+
z.literal("task")
|
|
110
|
+
])
|
|
111
|
+
});
|
|
112
|
+
const ScanCacheEntrySchema = z.object({
|
|
113
|
+
mtimeMs: z.number(),
|
|
114
|
+
size: z.number(),
|
|
115
|
+
hasWorkflow: z.boolean(),
|
|
116
|
+
exportNames: z.array(z.string()),
|
|
117
|
+
discoveryEntries: z.array(DiscoveredWorkflowSchema),
|
|
118
|
+
dependencyPaths: z.array(z.string())
|
|
119
|
+
});
|
|
120
|
+
const WorkflowCacheEntrySchema = z.object({
|
|
121
|
+
bindingKey: z.string(),
|
|
122
|
+
workflowId: z.string(),
|
|
123
|
+
resolvedFilePath: z.string().optional(),
|
|
124
|
+
inputFingerprint: z.string(),
|
|
125
|
+
dependencyPaths: z.array(z.string()),
|
|
126
|
+
manifestHash: z.string(),
|
|
127
|
+
flowGraphHash: z.string(),
|
|
128
|
+
bundleHash: z.string(),
|
|
129
|
+
sourceMapHash: z.string().optional(),
|
|
130
|
+
outputFiles: z.array(z.string()),
|
|
131
|
+
updatedAt: z.string()
|
|
132
|
+
});
|
|
133
|
+
const AgentCacheEntrySchema = z.object({
|
|
134
|
+
bindingKey: z.string(),
|
|
135
|
+
agentId: z.string(),
|
|
136
|
+
resolvedFilePath: z.string().optional(),
|
|
137
|
+
inputFingerprint: z.string(),
|
|
138
|
+
dependencyPaths: z.array(z.string()),
|
|
139
|
+
manifestHash: z.string(),
|
|
140
|
+
bundleHash: z.string(),
|
|
141
|
+
sandboxPackageHash: z.string(),
|
|
142
|
+
sourceMapHash: z.string().optional(),
|
|
143
|
+
outputFiles: z.array(z.string()),
|
|
144
|
+
updatedAt: z.string()
|
|
145
|
+
});
|
|
146
|
+
const FileMetadataCacheEntrySchema = z.object({
|
|
147
|
+
filePath: RelativeFilePathSchema,
|
|
148
|
+
sourceChecksum: z.string().length(64).regex(/^[a-f0-9]{64}$/i),
|
|
149
|
+
metadataHash: z.string().min(1),
|
|
150
|
+
outputFile: z.string().min(1),
|
|
151
|
+
updatedAt: z.iso.datetime(),
|
|
152
|
+
crossReferenceFingerprint: z.string().min(1).optional()
|
|
153
|
+
});
|
|
154
|
+
const BuildCacheSchema = z.object({
|
|
155
|
+
cacheVersion: z.literal(2),
|
|
156
|
+
builderFingerprint: z.string(),
|
|
157
|
+
scanEntries: z.record(z.string(), ScanCacheEntrySchema),
|
|
158
|
+
bindings: z.record(z.string(), WorkflowCacheEntrySchema),
|
|
159
|
+
agentBindings: z.record(z.string(), AgentCacheEntrySchema).default({}),
|
|
160
|
+
metadata: z.record(z.string(), FileMetadataCacheEntrySchema).default({})
|
|
161
|
+
});
|
|
162
|
+
function sha256Buffer(buffer) {
|
|
163
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
164
|
+
}
|
|
165
|
+
async function readBuildCache(outputDir) {
|
|
166
|
+
const cachePath = path.join(outputDir, BUILD_CACHE_FILE_NAME);
|
|
167
|
+
try {
|
|
168
|
+
const parsed = JSON.parse(await readFile(cachePath, "utf-8"));
|
|
169
|
+
const result = BuildCacheSchema.safeParse(parsed);
|
|
170
|
+
return result.success ? result.data : null;
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function writeBuildCache(outputDir, cache) {
|
|
176
|
+
const cachePath = path.join(outputDir, BUILD_CACHE_FILE_NAME);
|
|
177
|
+
const validatedCache = BuildCacheSchema.parse(cache);
|
|
178
|
+
await mkdir(outputDir, { recursive: true });
|
|
179
|
+
await writeFile(cachePath, `${JSON.stringify(validatedCache, null, 2)}\n`, "utf-8");
|
|
180
|
+
}
|
|
181
|
+
function createEmptyBuildCache(builderFingerprint) {
|
|
182
|
+
return {
|
|
183
|
+
cacheVersion: 2,
|
|
184
|
+
builderFingerprint,
|
|
185
|
+
scanEntries: {},
|
|
186
|
+
bindings: {},
|
|
187
|
+
agentBindings: {},
|
|
188
|
+
metadata: {}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async function loadCachedArtifact(outputDir, discoveredWorkflow, cachedEntry) {
|
|
192
|
+
if (!await allOutputFilesExist(outputDir, cachedEntry.outputFiles)) return null;
|
|
193
|
+
try {
|
|
194
|
+
const artifactPaths = getWorkflowArtifactPaths(outputDir, cachedEntry.workflowId);
|
|
195
|
+
const [manifestText, flowText, bundleCode, sourceMap] = await Promise.all([
|
|
196
|
+
readFile(artifactPaths.manifestPath, "utf-8"),
|
|
197
|
+
readFile(artifactPaths.flowPath, "utf-8"),
|
|
198
|
+
readFile(artifactPaths.bundlePath, "utf-8"),
|
|
199
|
+
cachedEntry.sourceMapHash ? readFile(artifactPaths.sourceMapPath, "utf-8") : null
|
|
200
|
+
]);
|
|
201
|
+
if (sha256String(manifestText) !== cachedEntry.manifestHash) return null;
|
|
202
|
+
if (sha256String(flowText) !== cachedEntry.flowGraphHash) return null;
|
|
203
|
+
const manifest = WorkflowManifestSchema.parse(JSON.parse(manifestText));
|
|
204
|
+
const flowGraph = FlowGraphSchema.parse(JSON.parse(flowText));
|
|
205
|
+
if (manifest.id !== cachedEntry.workflowId) return null;
|
|
206
|
+
if (path.basename(artifactPaths.workflowDir) !== manifest.id) return null;
|
|
207
|
+
if (sha256String(bundleCode) !== cachedEntry.bundleHash) return null;
|
|
208
|
+
if (cachedEntry.sourceMapHash && sourceMap && sha256String(sourceMap) !== cachedEntry.sourceMapHash) return null;
|
|
209
|
+
return {
|
|
210
|
+
workflow: {
|
|
211
|
+
...discoveredWorkflow,
|
|
212
|
+
workflowId: manifest.id
|
|
213
|
+
},
|
|
214
|
+
manifest,
|
|
215
|
+
flowGraph,
|
|
216
|
+
bundle: {
|
|
217
|
+
code: bundleCode,
|
|
218
|
+
sourceMap,
|
|
219
|
+
hash: cachedEntry.bundleHash,
|
|
220
|
+
...cachedEntry.sourceMapHash ? { sourceMapHash: cachedEntry.sourceMapHash } : {},
|
|
221
|
+
localDependencies: [...cachedEntry.dependencyPaths],
|
|
222
|
+
externalImports: [],
|
|
223
|
+
size: Buffer.byteLength(bundleCode)
|
|
224
|
+
},
|
|
225
|
+
triggers: [],
|
|
226
|
+
timing: {
|
|
227
|
+
importMs: 0,
|
|
228
|
+
manifestMs: 0,
|
|
229
|
+
flowGraphMs: 0,
|
|
230
|
+
bundleMs: 0,
|
|
231
|
+
triggerMs: 0,
|
|
232
|
+
totalMs: 0
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
} catch {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async function loadCachedAgentArtifact(outputDir, discoveredWorkflow, cachedEntry) {
|
|
240
|
+
if (!await allOutputFilesExist(outputDir, cachedEntry.outputFiles)) return null;
|
|
241
|
+
try {
|
|
242
|
+
const artifactPaths = getAgentArtifactPaths(outputDir, cachedEntry.agentId);
|
|
243
|
+
const [manifestText, sandboxPackageBuffer] = await Promise.all([readFile(artifactPaths.manifestPath, "utf-8"), readFile(artifactPaths.sandboxPackagePath)]);
|
|
244
|
+
if (sha256String(manifestText) !== cachedEntry.manifestHash) return null;
|
|
245
|
+
const manifest = AgentVersionManifestSchema.parse(JSON.parse(manifestText));
|
|
246
|
+
if (sha256Buffer(sandboxPackageBuffer) !== cachedEntry.sandboxPackageHash) return null;
|
|
247
|
+
const toolsRuntimeFile = (await readAgentSandboxPackage(sandboxPackageBuffer)).find((file) => path.posix.normalize(file.path) === AGENT_VM_TOOLS_RUNTIME_RELATIVE_PATH);
|
|
248
|
+
if (!toolsRuntimeFile) return null;
|
|
249
|
+
const bundleCode = Buffer.isBuffer(toolsRuntimeFile.content) ? toolsRuntimeFile.content.toString("utf-8") : toolsRuntimeFile.content;
|
|
250
|
+
if (sha256String(bundleCode) !== cachedEntry.bundleHash) return null;
|
|
251
|
+
return {
|
|
252
|
+
agent: {
|
|
253
|
+
bindingKey: discoveredWorkflow.bindingKey,
|
|
254
|
+
exportFilePath: discoveredWorkflow.exportFilePath,
|
|
255
|
+
resolvedFilePath: discoveredWorkflow.resolvedFilePath,
|
|
256
|
+
exportName: discoveredWorkflow.exportName,
|
|
257
|
+
localExportName: discoveredWorkflow.localExportName,
|
|
258
|
+
agentId: cachedEntry.agentId,
|
|
259
|
+
agentName: manifest.agentName
|
|
260
|
+
},
|
|
261
|
+
manifest,
|
|
262
|
+
bundle: {
|
|
263
|
+
code: bundleCode,
|
|
264
|
+
sourceMap: null,
|
|
265
|
+
hash: cachedEntry.bundleHash,
|
|
266
|
+
localDependencies: [...cachedEntry.dependencyPaths],
|
|
267
|
+
externalImports: [],
|
|
268
|
+
size: Buffer.byteLength(bundleCode)
|
|
269
|
+
},
|
|
270
|
+
sandboxPackage: {
|
|
271
|
+
buffer: sandboxPackageBuffer,
|
|
272
|
+
size: sandboxPackageBuffer.byteLength,
|
|
273
|
+
hash: cachedEntry.sandboxPackageHash
|
|
274
|
+
},
|
|
275
|
+
timing: {
|
|
276
|
+
importMs: 0,
|
|
277
|
+
manifestMs: 0,
|
|
278
|
+
bundleMs: 0,
|
|
279
|
+
totalMs: 0
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
} catch {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function createWorkflowCacheEntries(artifacts, validatedHashes) {
|
|
287
|
+
return Object.fromEntries(artifacts.map((artifact) => {
|
|
288
|
+
const outputFiles = createArtifactOutputFiles(artifact.workflow.workflowId, artifact.bundle.sourceMap !== null || artifact.bundle.sourceMapHash !== void 0 || artifact.bundle.sourceMapPath !== void 0);
|
|
289
|
+
const existing = validatedHashes?.get(artifact.workflow.bindingKey);
|
|
290
|
+
return [artifact.workflow.bindingKey, {
|
|
291
|
+
bindingKey: artifact.workflow.bindingKey,
|
|
292
|
+
workflowId: artifact.workflow.workflowId,
|
|
293
|
+
resolvedFilePath: artifact.workflow.resolvedFilePath,
|
|
294
|
+
inputFingerprint: "",
|
|
295
|
+
dependencyPaths: artifact.bundle.localDependencies.filter((dependencyPath) => path.isAbsolute(dependencyPath) && !dependencyPath.includes("\0")),
|
|
296
|
+
manifestHash: existing?.manifestHash ?? hashWorkflowManifestForDisk(artifact.manifest),
|
|
297
|
+
flowGraphHash: existing?.flowGraphHash ?? hashWorkflowFlowForDisk(artifact.flowGraph),
|
|
298
|
+
bundleHash: existing?.bundleHash ?? artifact.bundle.hash ?? sha256String(artifact.bundle.code),
|
|
299
|
+
sourceMapHash: existing?.sourceMapHash ?? artifact.bundle.sourceMapHash ?? (artifact.bundle.sourceMap ? sha256String(artifact.bundle.sourceMap) : void 0),
|
|
300
|
+
outputFiles,
|
|
301
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
302
|
+
}];
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
function createAgentCacheEntries(artifacts, validatedHashes) {
|
|
306
|
+
return Object.fromEntries(artifacts.map((artifact) => {
|
|
307
|
+
const existing = validatedHashes?.get(artifact.agent.bindingKey);
|
|
308
|
+
return [artifact.agent.bindingKey, {
|
|
309
|
+
bindingKey: artifact.agent.bindingKey,
|
|
310
|
+
agentId: artifact.agent.agentId,
|
|
311
|
+
resolvedFilePath: artifact.agent.resolvedFilePath,
|
|
312
|
+
inputFingerprint: "",
|
|
313
|
+
dependencyPaths: artifact.bundle.localDependencies.filter((dependencyPath) => path.isAbsolute(dependencyPath) && !dependencyPath.includes("\0")),
|
|
314
|
+
manifestHash: existing?.manifestHash ?? hashAgentManifestForDisk(artifact.manifest),
|
|
315
|
+
bundleHash: existing?.bundleHash ?? artifact.bundle.hash ?? sha256String(artifact.bundle.code),
|
|
316
|
+
sandboxPackageHash: existing?.sandboxPackageHash ?? sha256Buffer(artifact.sandboxPackage.buffer),
|
|
317
|
+
outputFiles: createAgentOutputFiles(artifact.agent.agentId),
|
|
318
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
319
|
+
}];
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
async function resolveCachedArtifacts(options) {
|
|
323
|
+
const cachedArtifacts = [];
|
|
324
|
+
const cachedAgentArtifacts = [];
|
|
325
|
+
const workflowsToBuild = [];
|
|
326
|
+
const fingerprintByBinding = /* @__PURE__ */ new Map();
|
|
327
|
+
const validatedHashesByBinding = /* @__PURE__ */ new Map();
|
|
328
|
+
const warnings = [];
|
|
329
|
+
let cacheHits = 0;
|
|
330
|
+
let cacheMisses = 0;
|
|
331
|
+
let cachedWorkflowIndex = 0;
|
|
332
|
+
const cacheResolutionStartedAt = performance.now();
|
|
333
|
+
createFileContentCache();
|
|
334
|
+
await prewarmFileContentCache(collectDependencyPaths(options.scopedDiscoveredWorkflows, options.buildCache));
|
|
335
|
+
for (const discoveredWorkflow of options.scopedDiscoveredWorkflows) {
|
|
336
|
+
if (options.config.force) {
|
|
337
|
+
workflowsToBuild.push(discoveredWorkflow);
|
|
338
|
+
cacheMisses += 1;
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (discoveredWorkflow.exportKind === "agent") {
|
|
342
|
+
const resolved = await resolveCachedAgentArtifact({
|
|
343
|
+
buildCache: options.buildCache,
|
|
344
|
+
discoveredWorkflow,
|
|
345
|
+
outputDir: options.outputDir,
|
|
346
|
+
fingerprintByBinding
|
|
347
|
+
});
|
|
348
|
+
if (!resolved) {
|
|
349
|
+
workflowsToBuild.push(discoveredWorkflow);
|
|
350
|
+
cacheMisses += 1;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
cachedAgentArtifacts.push(resolved.artifact);
|
|
354
|
+
cacheHits += 1;
|
|
355
|
+
validatedHashesByBinding.set(discoveredWorkflow.bindingKey, resolved.validatedHashes);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const resolved = await resolveCachedWorkflowArtifact({
|
|
359
|
+
config: options.config,
|
|
360
|
+
buildCache: options.buildCache,
|
|
361
|
+
discoveredWorkflow,
|
|
362
|
+
outputDir: options.outputDir,
|
|
363
|
+
fingerprintByBinding
|
|
364
|
+
});
|
|
365
|
+
if (!resolved) {
|
|
366
|
+
workflowsToBuild.push(discoveredWorkflow);
|
|
367
|
+
cacheMisses += 1;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
cachedArtifacts.push(resolved.artifact);
|
|
371
|
+
cacheHits += 1;
|
|
372
|
+
validatedHashesByBinding.set(discoveredWorkflow.bindingKey, resolved.validatedHashes);
|
|
373
|
+
options.emit({
|
|
374
|
+
phase: "workflow-stage",
|
|
375
|
+
stage: "cached",
|
|
376
|
+
workflow: resolved.artifact.workflow,
|
|
377
|
+
workflowIndex: cachedWorkflowIndex,
|
|
378
|
+
workflowCount: options.scopedWorkflowCount,
|
|
379
|
+
elapsedMs: 0
|
|
380
|
+
});
|
|
381
|
+
cachedWorkflowIndex += 1;
|
|
382
|
+
}
|
|
383
|
+
resetFileContentCache();
|
|
384
|
+
const cacheResolutionMs = performance.now() - cacheResolutionStartedAt;
|
|
385
|
+
options.emit({
|
|
386
|
+
phase: "cache-stats",
|
|
387
|
+
cacheHits,
|
|
388
|
+
cacheMisses,
|
|
389
|
+
invalidated: options.cacheInvalidated
|
|
390
|
+
});
|
|
391
|
+
return {
|
|
392
|
+
cachedArtifacts,
|
|
393
|
+
cachedAgentArtifacts,
|
|
394
|
+
workflowsToBuild,
|
|
395
|
+
fingerprintByBinding,
|
|
396
|
+
validatedHashesByBinding,
|
|
397
|
+
warnings,
|
|
398
|
+
cacheHits,
|
|
399
|
+
cacheMisses,
|
|
400
|
+
cacheResolutionMs
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function collectDependencyPaths(scopedDiscoveredWorkflows, buildCache) {
|
|
404
|
+
const allDepPaths = [];
|
|
405
|
+
for (const discoveredWorkflow of scopedDiscoveredWorkflows) {
|
|
406
|
+
allDepPaths.push(discoveredWorkflow.resolvedFilePath);
|
|
407
|
+
const cached = discoveredWorkflow.exportKind === "agent" ? buildCache.agentBindings[discoveredWorkflow.bindingKey] : buildCache.bindings[discoveredWorkflow.bindingKey];
|
|
408
|
+
if (cached) allDepPaths.push(...cached.dependencyPaths);
|
|
409
|
+
}
|
|
410
|
+
return allDepPaths;
|
|
411
|
+
}
|
|
412
|
+
async function resolveCachedAgentArtifact(options) {
|
|
413
|
+
const cachedEntry = options.buildCache.agentBindings[options.discoveredWorkflow.bindingKey];
|
|
414
|
+
if (!cachedEntry) return null;
|
|
415
|
+
try {
|
|
416
|
+
const inputFingerprint = await computeWorkflowFingerprint(options.discoveredWorkflow.resolvedFilePath, cachedEntry.dependencyPaths);
|
|
417
|
+
options.fingerprintByBinding.set(options.discoveredWorkflow.bindingKey, inputFingerprint);
|
|
418
|
+
if (inputFingerprint !== cachedEntry.inputFingerprint) return null;
|
|
419
|
+
const artifact = await loadCachedAgentArtifact(options.outputDir, options.discoveredWorkflow, cachedEntry);
|
|
420
|
+
if (!artifact) return null;
|
|
421
|
+
return {
|
|
422
|
+
artifact,
|
|
423
|
+
validatedHashes: {
|
|
424
|
+
manifestHash: cachedEntry.manifestHash,
|
|
425
|
+
bundleHash: cachedEntry.bundleHash,
|
|
426
|
+
sandboxPackageHash: cachedEntry.sandboxPackageHash
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
} catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async function resolveCachedWorkflowArtifact(options) {
|
|
434
|
+
const cachedEntry = options.buildCache.bindings[options.discoveredWorkflow.bindingKey];
|
|
435
|
+
if (!cachedEntry) return null;
|
|
436
|
+
try {
|
|
437
|
+
const inputFingerprint = await computeWorkflowFingerprint(options.discoveredWorkflow.resolvedFilePath, cachedEntry.dependencyPaths);
|
|
438
|
+
options.fingerprintByBinding.set(options.discoveredWorkflow.bindingKey, inputFingerprint);
|
|
439
|
+
if (inputFingerprint !== cachedEntry.inputFingerprint) return null;
|
|
440
|
+
const artifact = await loadCachedArtifact(options.outputDir, options.discoveredWorkflow, cachedEntry);
|
|
441
|
+
if (!artifact) return null;
|
|
442
|
+
return {
|
|
443
|
+
artifact,
|
|
444
|
+
validatedHashes: {
|
|
445
|
+
manifestHash: cachedEntry.manifestHash,
|
|
446
|
+
flowGraphHash: cachedEntry.flowGraphHash,
|
|
447
|
+
bundleHash: cachedEntry.bundleHash,
|
|
448
|
+
sourceMapHash: cachedEntry.sourceMapHash
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
} catch {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/** Narrows to any failure tied to a specific workflow (workflow or loader-protocol). */
|
|
456
|
+
function isWorkflowScopedBuildFailure(failure) {
|
|
457
|
+
return failure.kind === "workflow" || failure.kind === "loader-protocol";
|
|
458
|
+
}
|
|
459
|
+
/** Narrows to a duplicate-workflow-id conflict failure. */
|
|
460
|
+
function isDuplicateWorkflowIdFailure(failure) {
|
|
461
|
+
return failure.kind === "duplicate-workflow-id";
|
|
462
|
+
}
|
|
463
|
+
/** Narrows to a duplicate-agent-id conflict failure. */
|
|
464
|
+
function isDuplicateAgentIdFailure(failure) {
|
|
465
|
+
return failure.kind === "duplicate-agent-id";
|
|
466
|
+
}
|
|
467
|
+
async function cleanupFailedBuildState(options) {
|
|
468
|
+
const workflowIdsToRemove = Array.from(new Set(options.workflowIdsToRemove));
|
|
469
|
+
if (workflowIdsToRemove.length > 0) await removeWorkflowArtifacts(options.outputDir, workflowIdsToRemove);
|
|
470
|
+
const agentIdsToRemove = Array.from(new Set(options.agentIdsToRemove ?? []));
|
|
471
|
+
if (agentIdsToRemove.length > 0) await removeAgentArtifacts(options.outputDir, agentIdsToRemove);
|
|
472
|
+
if (options.metadataPathsToRemove && options.metadataPathsToRemove.length > 0) await removeMetadataArtifacts(options.outputDir, options.metadataPathsToRemove.map((filePath) => createMetadataOutputFile(filePath)));
|
|
473
|
+
else await removeAllMetadataArtifacts(options.outputDir);
|
|
474
|
+
if (!options.cache) return;
|
|
475
|
+
const bindingKeysToRemove = new Set(options.bindingKeysToRemove);
|
|
476
|
+
const workflowIdsToRemoveSet = new Set(workflowIdsToRemove);
|
|
477
|
+
const agentIdsToRemoveSet = new Set(agentIdsToRemove);
|
|
478
|
+
const bindings = Object.fromEntries(typedEntries(options.cache.bindings).filter(([bindingKey, entry]) => !bindingKeysToRemove.has(bindingKey) && !workflowIdsToRemoveSet.has(entry.workflowId)));
|
|
479
|
+
const agentBindings = Object.fromEntries(typedEntries(options.cache.agentBindings).filter(([bindingKey, entry]) => !bindingKeysToRemove.has(bindingKey) && !agentIdsToRemoveSet.has(entry.agentId)));
|
|
480
|
+
const metadataPathsToRemove = new Set(options.metadataPathsToRemove ?? []);
|
|
481
|
+
const metadata = metadataPathsToRemove.size > 0 ? Object.fromEntries(typedEntries(options.cache.metadata).filter(([filePath]) => !metadataPathsToRemove.has(parseRelativeFilePath(filePath)))) : {};
|
|
482
|
+
await writeBuildCache(options.outputDir, {
|
|
483
|
+
...options.cache,
|
|
484
|
+
builderFingerprint: options.builderFingerprint ?? options.cache.builderFingerprint,
|
|
485
|
+
scanEntries: options.scanEntries ?? options.cache.scanEntries,
|
|
486
|
+
bindings,
|
|
487
|
+
agentBindings,
|
|
488
|
+
metadata
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
async function resolveCandidateFiles(projectRoot) {
|
|
492
|
+
const resolvedProjectRoot = path.resolve(projectRoot);
|
|
493
|
+
const files = await (0, import_out.default)([...DISCOVERY_GLOB], {
|
|
494
|
+
cwd: resolvedProjectRoot,
|
|
495
|
+
absolute: true,
|
|
496
|
+
onlyFiles: true,
|
|
497
|
+
ignore: [...DISCOVERY_IGNORE]
|
|
498
|
+
});
|
|
499
|
+
files.sort((left, right) => left.localeCompare(right));
|
|
500
|
+
return files;
|
|
501
|
+
}
|
|
502
|
+
async function resolveDiscoveredWorkflowEntries(candidateFiles, projectRoot) {
|
|
503
|
+
const resolutionContext = { cache: /* @__PURE__ */ new Map() };
|
|
504
|
+
const entries = [];
|
|
505
|
+
for (const exportFilePath of candidateFiles) {
|
|
506
|
+
const moduleResolution = await resolveModuleExports(exportFilePath, resolutionContext, []);
|
|
507
|
+
const discoveredByBindingKey = /* @__PURE__ */ new Map();
|
|
508
|
+
for (const [exportName, target] of moduleResolution.namedExports) {
|
|
509
|
+
if (!target) continue;
|
|
510
|
+
const discovered = createDiscoveredWorkflow({
|
|
511
|
+
exportFilePath,
|
|
512
|
+
exportName,
|
|
513
|
+
isDefaultExport: false,
|
|
514
|
+
projectRoot,
|
|
515
|
+
target
|
|
516
|
+
});
|
|
517
|
+
discoveredByBindingKey.set(discovered.bindingKey, discoveredByBindingKey.get(discovered.bindingKey) ?? discovered);
|
|
518
|
+
}
|
|
519
|
+
if (moduleResolution.defaultExport) {
|
|
520
|
+
const discovered = createDiscoveredWorkflow({
|
|
521
|
+
exportFilePath,
|
|
522
|
+
exportName: "default",
|
|
523
|
+
isDefaultExport: true,
|
|
524
|
+
projectRoot,
|
|
525
|
+
target: moduleResolution.defaultExport
|
|
526
|
+
});
|
|
527
|
+
discoveredByBindingKey.set(discovered.bindingKey, discoveredByBindingKey.get(discovered.bindingKey) ?? discovered);
|
|
528
|
+
}
|
|
529
|
+
entries.push({
|
|
530
|
+
exportFilePath,
|
|
531
|
+
discoveryEntries: [...discoveredByBindingKey.values()].sort((left, right) => left.bindingKey.localeCompare(right.bindingKey)),
|
|
532
|
+
dependencyPaths: moduleResolution.dependencyPaths.filter((dependencyPath) => dependencyPath !== exportFilePath)
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
return entries.sort((left, right) => left.exportFilePath.localeCompare(right.exportFilePath));
|
|
536
|
+
}
|
|
537
|
+
async function resolveModuleExports(filePath, context, resolutionStack) {
|
|
538
|
+
const resolvedFilePath = path.resolve(filePath);
|
|
539
|
+
const cached = context.cache.get(resolvedFilePath);
|
|
540
|
+
if (cached) return cached;
|
|
541
|
+
const resolutionPromise = resolveModuleExportsUncached(resolvedFilePath, context, resolutionStack);
|
|
542
|
+
context.cache.set(resolvedFilePath, resolutionPromise);
|
|
543
|
+
return resolutionPromise;
|
|
544
|
+
}
|
|
545
|
+
async function resolveModuleExportsUncached(filePath, context, resolutionStack) {
|
|
546
|
+
if (resolutionStack.includes(filePath)) return {
|
|
547
|
+
namedExports: /* @__PURE__ */ new Map(),
|
|
548
|
+
defaultExport: null,
|
|
549
|
+
dependencyPaths: [filePath]
|
|
550
|
+
};
|
|
551
|
+
const analysis = await analyzeModule(filePath, parseSourceFile(filePath, await readFile(filePath, "utf-8")), context, [...resolutionStack, filePath]);
|
|
552
|
+
if (analysis.hasNamespaceStarExport) throw createNamespaceStarExportDiscoveryError(filePath);
|
|
553
|
+
const ambiguousExports = [...analysis.namedExports.entries()].filter(([, target]) => target === null).map(([exportName]) => exportName);
|
|
554
|
+
if (ambiguousExports.length > 0) throw createAmbiguousExportDiscoveryError(filePath, ambiguousExports);
|
|
555
|
+
return {
|
|
556
|
+
namedExports: analysis.namedExports,
|
|
557
|
+
defaultExport: analysis.defaultExport,
|
|
558
|
+
dependencyPaths: [...new Set([filePath, ...analysis.dependencyPaths])].sort((left, right) => left.localeCompare(right))
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
async function analyzeModule(filePath, sourceFile, context, resolutionStack) {
|
|
562
|
+
const workflowImportNames = collectWorkflowImportNames(sourceFile);
|
|
563
|
+
const localWorkflowBindings = collectLocalWorkflowBindings(sourceFile, workflowImportNames);
|
|
564
|
+
const namedExports = /* @__PURE__ */ new Map();
|
|
565
|
+
let defaultExport = null;
|
|
566
|
+
let hasNamespaceStarExport = false;
|
|
567
|
+
const dependencyPaths = /* @__PURE__ */ new Set();
|
|
568
|
+
for (const statement of sourceFile.statements) {
|
|
569
|
+
if (isExportedVariableStatement(statement)) {
|
|
570
|
+
for (const declaration of getVariableDeclarators(statement)) {
|
|
571
|
+
const localName = identifierName(declaration.id);
|
|
572
|
+
if (!localName) continue;
|
|
573
|
+
const exportKind = localWorkflowBindings.get(localName);
|
|
574
|
+
if (!exportKind) continue;
|
|
575
|
+
addNamedExport(namedExports, localName, {
|
|
576
|
+
resolvedFilePath: filePath,
|
|
577
|
+
localExportName: localName,
|
|
578
|
+
exportKind
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
if (statement.type === "ExportNamedDeclaration") {
|
|
584
|
+
const moduleSpecifier = getLocalModuleSpecifier(literalString(statement.source));
|
|
585
|
+
if (!moduleSpecifier) {
|
|
586
|
+
if (Array.isArray(statement.specifiers)) for (const specifier of statement.specifiers) {
|
|
587
|
+
if (!isNode(specifier) || specifier.type !== "ExportSpecifier") continue;
|
|
588
|
+
const localName = identifierName(specifier.local);
|
|
589
|
+
const exportName = identifierName(specifier.exported);
|
|
590
|
+
if (!localName || !exportName) continue;
|
|
591
|
+
const exportKind = localWorkflowBindings.get(localName);
|
|
592
|
+
if (!exportKind) continue;
|
|
593
|
+
addNamedExport(namedExports, exportName, {
|
|
594
|
+
resolvedFilePath: filePath,
|
|
595
|
+
localExportName: localName,
|
|
596
|
+
exportKind
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
const resolvedModuleFile = await resolveLocalModulePath(filePath, moduleSpecifier);
|
|
602
|
+
if (!resolvedModuleFile) continue;
|
|
603
|
+
const targetResolution = await resolveModuleExports(resolvedModuleFile, context, resolutionStack);
|
|
604
|
+
dependencyPaths.add(resolvedModuleFile);
|
|
605
|
+
for (const dependencyPath of targetResolution.dependencyPaths) dependencyPaths.add(dependencyPath);
|
|
606
|
+
for (const specifier of Array.isArray(statement.specifiers) ? statement.specifiers : []) {
|
|
607
|
+
if (!isNode(specifier) || specifier.type !== "ExportSpecifier") continue;
|
|
608
|
+
const sourceExportName = identifierName(specifier.local);
|
|
609
|
+
const exportName = identifierName(specifier.exported);
|
|
610
|
+
if (!sourceExportName || !exportName) continue;
|
|
611
|
+
if (sourceExportName === "default") {
|
|
612
|
+
if (exportName === "default") defaultExport = targetResolution.defaultExport;
|
|
613
|
+
else addNamedExport(namedExports, exportName, targetResolution.defaultExport);
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
addNamedExport(namedExports, exportName, targetResolution.namedExports.get(sourceExportName) ?? null);
|
|
617
|
+
}
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (statement.type === "ExportAllDeclaration") {
|
|
621
|
+
const moduleSpecifier = getLocalModuleSpecifier(literalString(statement.source));
|
|
622
|
+
if (!moduleSpecifier) continue;
|
|
623
|
+
const resolvedModuleFile = await resolveLocalModulePath(filePath, moduleSpecifier);
|
|
624
|
+
if (!resolvedModuleFile) continue;
|
|
625
|
+
const targetResolution = await resolveModuleExports(resolvedModuleFile, context, resolutionStack);
|
|
626
|
+
dependencyPaths.add(resolvedModuleFile);
|
|
627
|
+
for (const dependencyPath of targetResolution.dependencyPaths) dependencyPaths.add(dependencyPath);
|
|
628
|
+
if (identifierName(statement.exported)) {
|
|
629
|
+
hasNamespaceStarExport = true;
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
for (const [exportName, target] of targetResolution.namedExports) addNamedExport(namedExports, exportName, target);
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
if (statement.type === "ExportDefaultDeclaration" && isNode(statement.declaration)) defaultExport = resolveDefaultExportAssignment(statement.declaration, filePath, localWorkflowBindings, workflowImportNames);
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
localWorkflowBindings,
|
|
639
|
+
namedExports,
|
|
640
|
+
defaultExport,
|
|
641
|
+
hasNamespaceStarExport,
|
|
642
|
+
dependencyPaths: [...dependencyPaths].sort((left, right) => left.localeCompare(right))
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function addNamedExport(exportsMap, exportName, target) {
|
|
646
|
+
if (!target) return;
|
|
647
|
+
const existing = exportsMap.get(exportName);
|
|
648
|
+
if (!existing) {
|
|
649
|
+
exportsMap.set(exportName, target);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
if (existing.resolvedFilePath === target.resolvedFilePath && existing.localExportName === target.localExportName && existing.exportKind === target.exportKind) return;
|
|
653
|
+
exportsMap.set(exportName, null);
|
|
654
|
+
}
|
|
655
|
+
function createDiscoveredWorkflow(options) {
|
|
656
|
+
return {
|
|
657
|
+
exportFilePath: options.exportFilePath,
|
|
658
|
+
resolvedFilePath: options.target.resolvedFilePath,
|
|
659
|
+
relativePath: path.relative(options.projectRoot, options.target.resolvedFilePath),
|
|
660
|
+
exportName: options.exportName,
|
|
661
|
+
isDefaultExport: options.isDefaultExport,
|
|
662
|
+
localExportName: options.target.localExportName,
|
|
663
|
+
bindingKey: `${options.target.resolvedFilePath}::${options.target.localExportName}`,
|
|
664
|
+
exportKind: options.target.exportKind
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const BLOCK_COMMENTS_RE = /\/\*[\s\S]*?\*\//g;
|
|
668
|
+
const LINE_COMMENTS_RE = /(^|[^:])\/\/.*$/gm;
|
|
669
|
+
function stripComments(source) {
|
|
670
|
+
return source.replace(BLOCK_COMMENTS_RE, "").replace(LINE_COMMENTS_RE, "$1");
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Fast pre-filter: returns true if the file MIGHT contain a workflow, agent,
|
|
674
|
+
* or task export. Files that return false are guaranteed not to export
|
|
675
|
+
* Workflow/Agent/Task instances and can skip expensive AST parsing.
|
|
676
|
+
*
|
|
677
|
+
* The heuristic checks for:
|
|
678
|
+
* 1. Direct `new Workflow(`, `new Agent(`, or `new Task(` constructor calls
|
|
679
|
+
* 2. Re-exports that reference a local module (`export { ... } from './...`)
|
|
680
|
+
* or `export * from './...` — these might re-export a workflow/agent/task
|
|
681
|
+
*
|
|
682
|
+
* We intentionally skip `export {` without a `from` clause when there's no
|
|
683
|
+
* Workflow/Agent/Task reference, since those are just re-exports of local bindings
|
|
684
|
+
* which would already be caught by the constructor check.
|
|
685
|
+
*/
|
|
686
|
+
function couldContainWorkflowExport(source) {
|
|
687
|
+
const codeOnly = stripComments(source);
|
|
688
|
+
if (codeOnly.includes("new Workflow(") || codeOnly.includes("new Agent(") || codeOnly.includes("new Task(")) return true;
|
|
689
|
+
if (REEXPORT_FROM_LOCAL_RE.test(codeOnly)) return true;
|
|
690
|
+
if (codeOnly.includes("export default")) return codeOnly.includes("Workflow") || codeOnly.includes("Agent") || codeOnly.includes("Task");
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
const REEXPORT_FROM_LOCAL_RE = /export\s+(?:\{[^}]*\}|\*(?:\s+as\s+\w+)?)\s+from\s+['"]\.[\w./-]*['"]/;
|
|
694
|
+
const CONCURRENCY_LIMIT = 20;
|
|
695
|
+
async function discoverWorkflows(options) {
|
|
696
|
+
const startedAt = performance.now();
|
|
697
|
+
const projectRoot = path.resolve(options.projectRoot);
|
|
698
|
+
const allCandidateFiles = await resolveCandidateFiles(projectRoot);
|
|
699
|
+
const scanEntries = {};
|
|
700
|
+
const discoveredByBindingKey = /* @__PURE__ */ new Map();
|
|
701
|
+
const fileStats = await batchStat(allCandidateFiles);
|
|
702
|
+
const cacheHitFiles = [];
|
|
703
|
+
const cacheMissFiles = [];
|
|
704
|
+
for (let i = 0; i < allCandidateFiles.length; i++) {
|
|
705
|
+
const filePath = allCandidateFiles[i];
|
|
706
|
+
const fileStat = fileStats[i];
|
|
707
|
+
const cachedEntry = options.scanEntries?.[filePath];
|
|
708
|
+
if (cachedEntry && isScanCacheEntryValid(fileStat, cachedEntry, options.scanEntries ?? {}, fileStats, allCandidateFiles)) cacheHitFiles.push({
|
|
709
|
+
filePath,
|
|
710
|
+
entry: cachedEntry
|
|
711
|
+
});
|
|
712
|
+
else cacheMissFiles.push({
|
|
713
|
+
filePath,
|
|
714
|
+
fileStat
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
for (const { filePath, entry } of cacheHitFiles) {
|
|
718
|
+
scanEntries[filePath] = entry;
|
|
719
|
+
for (const workflow of entry.discoveryEntries) discoveredByBindingKey.set(workflow.bindingKey, discoveredByBindingKey.get(workflow.bindingKey) ?? workflow);
|
|
720
|
+
}
|
|
721
|
+
let filesScanned = cacheHitFiles.length;
|
|
722
|
+
options.onProgress?.({
|
|
723
|
+
filesScanned,
|
|
724
|
+
filesTotal: allCandidateFiles.length
|
|
725
|
+
});
|
|
726
|
+
for (let batchStart = 0; batchStart < cacheMissFiles.length; batchStart += CONCURRENCY_LIMIT) {
|
|
727
|
+
const batch = cacheMissFiles.slice(batchStart, batchStart + CONCURRENCY_LIMIT);
|
|
728
|
+
const batchResults = await Promise.all(batch.map(async ({ filePath, fileStat }) => {
|
|
729
|
+
if (!couldContainWorkflowExport(await readFile(filePath, "utf-8"))) return {
|
|
730
|
+
filePath,
|
|
731
|
+
entry: {
|
|
732
|
+
mtimeMs: fileStat.mtimeMs,
|
|
733
|
+
size: fileStat.size,
|
|
734
|
+
hasWorkflow: false,
|
|
735
|
+
exportNames: [],
|
|
736
|
+
discoveryEntries: [],
|
|
737
|
+
dependencyPaths: []
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
const [resolvedEntry] = await resolveDiscoveredWorkflowEntries([filePath], projectRoot);
|
|
741
|
+
const discoveryEntries = resolvedEntry?.discoveryEntries ?? [];
|
|
742
|
+
return {
|
|
743
|
+
filePath,
|
|
744
|
+
entry: {
|
|
745
|
+
mtimeMs: fileStat.mtimeMs,
|
|
746
|
+
size: fileStat.size,
|
|
747
|
+
hasWorkflow: discoveryEntries.length > 0,
|
|
748
|
+
exportNames: discoveryEntries.map((w) => w.exportName),
|
|
749
|
+
discoveryEntries,
|
|
750
|
+
dependencyPaths: resolvedEntry?.dependencyPaths ?? []
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
}));
|
|
754
|
+
for (const { filePath, entry } of batchResults) {
|
|
755
|
+
scanEntries[filePath] = entry;
|
|
756
|
+
for (const workflow of entry.discoveryEntries) discoveredByBindingKey.set(workflow.bindingKey, discoveredByBindingKey.get(workflow.bindingKey) ?? workflow);
|
|
757
|
+
}
|
|
758
|
+
filesScanned += batch.length;
|
|
759
|
+
options.onProgress?.({
|
|
760
|
+
filesScanned,
|
|
761
|
+
filesTotal: allCandidateFiles.length
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
const discoveredExports = [...discoveredByBindingKey.values()].sort((left, right) => left.bindingKey.localeCompare(right.bindingKey));
|
|
765
|
+
const { workflowCount, agentCount, taskCount } = countDiscoveredExports$1(discoveredExports);
|
|
766
|
+
return {
|
|
767
|
+
projectRoot,
|
|
768
|
+
workflows: discoveredExports,
|
|
769
|
+
workflowCount,
|
|
770
|
+
agentCount,
|
|
771
|
+
taskCount,
|
|
772
|
+
filesScanned,
|
|
773
|
+
elapsedMs: performance.now() - startedAt,
|
|
774
|
+
scanEntries
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
async function batchStat(files) {
|
|
778
|
+
const results = [];
|
|
779
|
+
for (let i = 0; i < files.length; i += CONCURRENCY_LIMIT) {
|
|
780
|
+
const batch = files.slice(i, i + CONCURRENCY_LIMIT);
|
|
781
|
+
const batchResults = await Promise.all(batch.map(async (filePath) => {
|
|
782
|
+
const s = await stat(filePath);
|
|
783
|
+
return {
|
|
784
|
+
mtimeMs: s.mtimeMs,
|
|
785
|
+
size: s.size
|
|
786
|
+
};
|
|
787
|
+
}));
|
|
788
|
+
results.push(...batchResults);
|
|
789
|
+
}
|
|
790
|
+
return results;
|
|
791
|
+
}
|
|
792
|
+
function isScanCacheEntryValid(fileStat, cachedEntry, previousScanEntries, allFileStats, allFilePaths) {
|
|
793
|
+
if (cachedEntry.discoveryEntries.some((entry) => entry.exportKind !== "workflow" && entry.exportKind !== "agent" && entry.exportKind !== "task")) return false;
|
|
794
|
+
if (cachedEntry.mtimeMs !== fileStat.mtimeMs || cachedEntry.size !== fileStat.size) return false;
|
|
795
|
+
const fileStatLookup = /* @__PURE__ */ new Map();
|
|
796
|
+
for (let i = 0; i < allFilePaths.length; i++) {
|
|
797
|
+
const fp = allFilePaths[i];
|
|
798
|
+
const fs = allFileStats[i];
|
|
799
|
+
fileStatLookup.set(fp, fs);
|
|
800
|
+
}
|
|
801
|
+
for (const dependencyPath of cachedEntry.dependencyPaths) {
|
|
802
|
+
const dependencyEntry = previousScanEntries[dependencyPath];
|
|
803
|
+
if (!dependencyEntry) return false;
|
|
804
|
+
const dependencyStat = fileStatLookup.get(dependencyPath);
|
|
805
|
+
if (!dependencyStat) return false;
|
|
806
|
+
if (dependencyEntry.mtimeMs !== dependencyStat.mtimeMs || dependencyEntry.size !== dependencyStat.size) return false;
|
|
807
|
+
}
|
|
808
|
+
return true;
|
|
809
|
+
}
|
|
810
|
+
function countDiscoveredExports$1(discoveredExports) {
|
|
811
|
+
let workflowCount = 0;
|
|
812
|
+
let agentCount = 0;
|
|
813
|
+
let taskCount = 0;
|
|
814
|
+
for (const discoveredExport of discoveredExports) if (discoveredExport.exportKind === "agent") agentCount += 1;
|
|
815
|
+
else if (discoveredExport.exportKind === "task") taskCount += 1;
|
|
816
|
+
else workflowCount += 1;
|
|
817
|
+
return {
|
|
818
|
+
workflowCount,
|
|
819
|
+
agentCount,
|
|
820
|
+
taskCount
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
function createProgressEmitter(callback) {
|
|
824
|
+
return function emit(event) {
|
|
825
|
+
if (!callback) return;
|
|
826
|
+
queueMicrotask(() => {
|
|
827
|
+
try {
|
|
828
|
+
callback(event);
|
|
829
|
+
} catch {}
|
|
830
|
+
});
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function runCycleDetection(params) {
|
|
834
|
+
const detectedCycles = detectAgentInPathCycles(buildCycleAnalysisInput(params));
|
|
835
|
+
return {
|
|
836
|
+
detectedCycles,
|
|
837
|
+
blocking: detectedCycles.length > 0
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
function buildCycleAnalysisInput(params) {
|
|
841
|
+
return {
|
|
842
|
+
agents: params.agentArtifacts.map((artifact) => ({
|
|
843
|
+
kind: "agent",
|
|
844
|
+
id: artifact.agent.agentId,
|
|
845
|
+
displayName: artifact.agent.agentName,
|
|
846
|
+
tools: (artifact.manifest.tools ?? []).filter((tool) => tool.sourceKind === "workflow" && tool.authoredWorkflowId).map((tool) => tool.authoredWorkflowId)
|
|
847
|
+
})),
|
|
848
|
+
workflows: params.workflowArtifacts.map((artifact) => ({
|
|
849
|
+
kind: "workflow",
|
|
850
|
+
id: artifact.workflow.workflowId,
|
|
851
|
+
displayName: artifact.manifest.name,
|
|
852
|
+
callees: artifact.flowGraph.nodes.flatMap((node) => {
|
|
853
|
+
if (node.type !== "step" || node.data.kind !== "call") return [];
|
|
854
|
+
if (node.data.callKind !== "child-workflow" && node.data.callKind !== "agent") return [];
|
|
855
|
+
return node.data.stepId ? [node.data.stepId] : [];
|
|
856
|
+
})
|
|
857
|
+
})),
|
|
858
|
+
operations: []
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Names that conflict with builder output directories/files.
|
|
863
|
+
* A workflow id matching any of these would overwrite builder infrastructure.
|
|
864
|
+
*
|
|
865
|
+
* Note: `.keystroke` is not included because it contains a dot, which is already
|
|
866
|
+
* rejected by the workflow id schema (`[a-zA-Z0-9_-]+`).
|
|
867
|
+
*/
|
|
868
|
+
const RESERVED_WORKFLOW_IDS = new Set([
|
|
869
|
+
METADATA_ROOT_DIR_NAME,
|
|
870
|
+
BUILD_DIR_NAME,
|
|
871
|
+
"node_modules"
|
|
872
|
+
]);
|
|
873
|
+
/**
|
|
874
|
+
* Prefixes that conflict with builder output directory naming conventions.
|
|
875
|
+
* A workflow id starting with any of these would collide with agent artifact dirs.
|
|
876
|
+
*/
|
|
877
|
+
const RESERVED_WORKFLOW_ID_PREFIXES = [AGENT_ARTIFACT_DIR_PREFIX];
|
|
878
|
+
var ReservedWorkflowIdError = class extends Error {
|
|
879
|
+
workflowId;
|
|
880
|
+
file;
|
|
881
|
+
bindingKey;
|
|
882
|
+
constructor(options) {
|
|
883
|
+
const reserved = RESERVED_WORKFLOW_ID_PREFIXES.some((prefix) => options.workflowId.startsWith(prefix)) ? `prefix "${options.workflowId.split("_")[0]}_"` : `"${options.workflowId}"`;
|
|
884
|
+
super(`Workflow id ${reserved} is reserved by the build system and cannot be used (in ${options.file})`);
|
|
885
|
+
this.name = "ReservedWorkflowIdError";
|
|
886
|
+
this.workflowId = options.workflowId;
|
|
887
|
+
this.file = options.file;
|
|
888
|
+
this.bindingKey = options.bindingKey;
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
function assertUniqueWorkflowIds(artifacts) {
|
|
892
|
+
const artifactByWorkflowId = /* @__PURE__ */ new Map();
|
|
893
|
+
for (const artifact of artifacts) {
|
|
894
|
+
assertNotReservedWorkflowId(artifact);
|
|
895
|
+
const existingSource = artifactByWorkflowId.get(artifact.workflow.workflowId);
|
|
896
|
+
if (existingSource) throw new DuplicateWorkflowIdError({
|
|
897
|
+
workflowId: artifact.workflow.workflowId,
|
|
898
|
+
files: [existingSource.file, artifact.workflow.resolvedFilePath],
|
|
899
|
+
bindingKeys: [existingSource.bindingKey, artifact.workflow.bindingKey]
|
|
900
|
+
});
|
|
901
|
+
artifactByWorkflowId.set(artifact.workflow.workflowId, {
|
|
902
|
+
file: artifact.workflow.resolvedFilePath,
|
|
903
|
+
bindingKey: artifact.workflow.bindingKey
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
var DuplicateAgentIdError = class extends Error {
|
|
908
|
+
agentId;
|
|
909
|
+
files;
|
|
910
|
+
bindingKeys;
|
|
911
|
+
constructor(options) {
|
|
912
|
+
super(`Duplicate agent id "${options.agentId}" found in ${options.files.join(" and ")}`);
|
|
913
|
+
this.name = "DuplicateAgentIdError";
|
|
914
|
+
this.agentId = options.agentId;
|
|
915
|
+
this.files = [...options.files];
|
|
916
|
+
this.bindingKeys = [...options.bindingKeys];
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
function assertUniqueAgentIds(artifacts) {
|
|
920
|
+
const seen = /* @__PURE__ */ new Map();
|
|
921
|
+
for (const artifact of artifacts) {
|
|
922
|
+
const existing = seen.get(artifact.agent.agentId);
|
|
923
|
+
if (existing) throw new DuplicateAgentIdError({
|
|
924
|
+
agentId: artifact.agent.agentId,
|
|
925
|
+
files: [existing.file, artifact.agent.resolvedFilePath],
|
|
926
|
+
bindingKeys: [existing.bindingKey, artifact.agent.bindingKey]
|
|
927
|
+
});
|
|
928
|
+
seen.set(artifact.agent.agentId, {
|
|
929
|
+
file: artifact.agent.resolvedFilePath,
|
|
930
|
+
bindingKey: artifact.agent.bindingKey
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
var DuplicateCredentialSetIdError = class extends Error {
|
|
935
|
+
resolvedCredentialSetId;
|
|
936
|
+
files;
|
|
937
|
+
constructor(options) {
|
|
938
|
+
super(`Duplicate credential set resolved ID "${options.resolvedCredentialSetId}" found in ${options.files.join(" and ")}`);
|
|
939
|
+
this.name = "DuplicateCredentialSetIdError";
|
|
940
|
+
this.resolvedCredentialSetId = options.resolvedCredentialSetId;
|
|
941
|
+
this.files = [...options.files];
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
function assertUniqueCredentialSetDefinitionResolvedIds(analyzedFiles) {
|
|
945
|
+
const seen = /* @__PURE__ */ new Map();
|
|
946
|
+
for (const analyzedFile of analyzedFiles) for (const credentialSet of analyzedFile.definitions.credentialSets) {
|
|
947
|
+
if (!credentialSet.resolvedCredentialSetId) continue;
|
|
948
|
+
const existing = seen.get(credentialSet.resolvedCredentialSetId);
|
|
949
|
+
if (existing && existing !== analyzedFile.filePath) throw new DuplicateCredentialSetIdError({
|
|
950
|
+
resolvedCredentialSetId: credentialSet.resolvedCredentialSetId,
|
|
951
|
+
files: [existing, analyzedFile.filePath]
|
|
952
|
+
});
|
|
953
|
+
seen.set(credentialSet.resolvedCredentialSetId, analyzedFile.filePath);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
function assertNotReservedWorkflowId(artifact) {
|
|
957
|
+
const id = artifact.workflow.workflowId;
|
|
958
|
+
if (RESERVED_WORKFLOW_IDS.has(id)) throw new ReservedWorkflowIdError({
|
|
959
|
+
workflowId: id,
|
|
960
|
+
file: artifact.workflow.resolvedFilePath,
|
|
961
|
+
bindingKey: artifact.workflow.bindingKey
|
|
962
|
+
});
|
|
963
|
+
for (const prefix of RESERVED_WORKFLOW_ID_PREFIXES) if (id.startsWith(prefix)) throw new ReservedWorkflowIdError({
|
|
964
|
+
workflowId: id,
|
|
965
|
+
file: artifact.workflow.resolvedFilePath,
|
|
966
|
+
bindingKey: artifact.workflow.bindingKey
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
async function buildDiscoveredWorkflows(options) {
|
|
970
|
+
const emit = createProgressEmitter(options.onProgressEvent);
|
|
971
|
+
const emitLifecycleEvents = options.emitLifecycleEvents ?? true;
|
|
972
|
+
const startedAt = performance.now();
|
|
973
|
+
const workflowCount = options.discoveredWorkflows.length;
|
|
974
|
+
const workflowBuildCount = options.discoveredWorkflows.filter((discoveredWorkflow) => discoveredWorkflow.exportKind === "workflow").length;
|
|
975
|
+
const agentBuildCount = options.discoveredWorkflows.filter((discoveredWorkflow) => discoveredWorkflow.exportKind === "agent").length;
|
|
976
|
+
const taskBuildCount = options.discoveredWorkflows.filter((discoveredWorkflow) => discoveredWorkflow.exportKind === "task").length;
|
|
977
|
+
if (emitLifecycleEvents) emit({
|
|
978
|
+
phase: "build-start",
|
|
979
|
+
workflowCount: workflowBuildCount,
|
|
980
|
+
agentCount: agentBuildCount,
|
|
981
|
+
taskCount: taskBuildCount
|
|
982
|
+
});
|
|
983
|
+
const workflowsByKey = /* @__PURE__ */ new Map();
|
|
984
|
+
for (let i = 0; i < workflowCount; i++) {
|
|
985
|
+
const workflow = options.discoveredWorkflows[i];
|
|
986
|
+
if (workflow) workflowsByKey.set(workflow.bindingKey, {
|
|
987
|
+
workflow,
|
|
988
|
+
index: i
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
const batchResults = await loadWorkflowMetadataBatch([...options.discoveredWorkflows], { concurrency: options.metadataLoaderConcurrency });
|
|
992
|
+
const metadataByKey = /* @__PURE__ */ new Map();
|
|
993
|
+
for (const result of batchResults) metadataByKey.set(result.bindingKey, result);
|
|
994
|
+
const buildPlan = await createBuildPlan({
|
|
995
|
+
discoveredWorkflows: options.discoveredWorkflows,
|
|
996
|
+
metadataByKey
|
|
997
|
+
});
|
|
998
|
+
const artifacts = [];
|
|
999
|
+
const agentArtifacts = [];
|
|
1000
|
+
const taskArtifacts = [];
|
|
1001
|
+
const failures = [...buildPlan.failures];
|
|
1002
|
+
const warnings = [];
|
|
1003
|
+
if (buildPlan.workflows.length > 0) {
|
|
1004
|
+
const { buildWorkflowArtifacts } = await import("./build-workflows-CfxBnIWh-CdYPv8w2.mjs");
|
|
1005
|
+
const result = await buildWorkflowArtifacts({
|
|
1006
|
+
entries: buildPlan.workflows,
|
|
1007
|
+
workflowsByKey,
|
|
1008
|
+
metadataByKey,
|
|
1009
|
+
projectRoot: options.projectRoot,
|
|
1010
|
+
workflowCount: workflowBuildCount,
|
|
1011
|
+
sourceMaps: options.sourceMaps,
|
|
1012
|
+
onProgressEvent: options.onProgressEvent
|
|
1013
|
+
});
|
|
1014
|
+
artifacts.push(...result.artifacts);
|
|
1015
|
+
failures.push(...result.failures);
|
|
1016
|
+
warnings.push(...result.warnings);
|
|
1017
|
+
}
|
|
1018
|
+
if (buildPlan.agents.length > 0) {
|
|
1019
|
+
const { buildAgentArtifacts } = await import("./build-agents-BmM_AsSd-BGi9wtzt.mjs");
|
|
1020
|
+
const result = await buildAgentArtifacts({
|
|
1021
|
+
entries: buildPlan.agents,
|
|
1022
|
+
projectRoot: options.projectRoot
|
|
1023
|
+
});
|
|
1024
|
+
agentArtifacts.push(...result.agentArtifacts);
|
|
1025
|
+
failures.push(...result.failures);
|
|
1026
|
+
}
|
|
1027
|
+
if (buildPlan.tasks.length > 0) {
|
|
1028
|
+
const { buildTaskArtifacts } = await import("./build-tasks-CdihpudT-D5r5HUHe.mjs");
|
|
1029
|
+
const result = await buildTaskArtifacts({
|
|
1030
|
+
entries: buildPlan.tasks,
|
|
1031
|
+
projectRoot: options.projectRoot,
|
|
1032
|
+
sourceMaps: options.sourceMaps
|
|
1033
|
+
});
|
|
1034
|
+
taskArtifacts.push(...result.taskArtifacts);
|
|
1035
|
+
failures.push(...result.failures);
|
|
1036
|
+
}
|
|
1037
|
+
try {
|
|
1038
|
+
assertUniqueWorkflowIds(artifacts);
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
if (error instanceof ReservedWorkflowIdError) failures.push({
|
|
1041
|
+
kind: "workflow",
|
|
1042
|
+
workflow: {
|
|
1043
|
+
bindingKey: error.bindingKey,
|
|
1044
|
+
exportFilePath: error.file,
|
|
1045
|
+
resolvedFilePath: error.file,
|
|
1046
|
+
exportName: "",
|
|
1047
|
+
localExportName: ""
|
|
1048
|
+
},
|
|
1049
|
+
phase: "output",
|
|
1050
|
+
error: error.message
|
|
1051
|
+
});
|
|
1052
|
+
else {
|
|
1053
|
+
const duplicateFailure = createDuplicateWorkflowIdFailure(artifacts, error);
|
|
1054
|
+
emit({
|
|
1055
|
+
phase: "duplicate-id-conflict",
|
|
1056
|
+
workflowId: duplicateFailure.workflowId,
|
|
1057
|
+
files: duplicateFailure.files
|
|
1058
|
+
});
|
|
1059
|
+
failures.push(duplicateFailure);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
try {
|
|
1063
|
+
assertUniqueAgentIds(agentArtifacts);
|
|
1064
|
+
} catch (error) {
|
|
1065
|
+
if (error instanceof DuplicateAgentIdError) failures.push({
|
|
1066
|
+
kind: "duplicate-agent-id",
|
|
1067
|
+
agentId: error.agentId,
|
|
1068
|
+
files: error.files,
|
|
1069
|
+
bindingKeys: error.bindingKeys,
|
|
1070
|
+
phase: "output",
|
|
1071
|
+
error: error.message
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
const cycleDetection = runCycleDetection({
|
|
1075
|
+
workflowArtifacts: artifacts,
|
|
1076
|
+
agentArtifacts
|
|
1077
|
+
});
|
|
1078
|
+
for (const cycle of cycleDetection.detectedCycles) failures.push({
|
|
1079
|
+
kind: "agent-cycle",
|
|
1080
|
+
cyclePath: cycle.path.map((node) => `${node.kind}:${node.id}`),
|
|
1081
|
+
phase: "output",
|
|
1082
|
+
error: `Agent-in-path cycle detected: ${cycle.description}`
|
|
1083
|
+
});
|
|
1084
|
+
const successfulArtifacts = failures.some((failure) => failure.kind === "duplicate-workflow-id" || failure.kind === "duplicate-agent-id" || failure.kind === "agent-cycle") ? [] : artifacts;
|
|
1085
|
+
const totalMs = performance.now() - startedAt;
|
|
1086
|
+
if (emitLifecycleEvents) emit({
|
|
1087
|
+
phase: "build-complete",
|
|
1088
|
+
workflowBuiltCount: successfulArtifacts.length,
|
|
1089
|
+
agentBuiltCount: agentArtifacts.length,
|
|
1090
|
+
taskBuiltCount: taskArtifacts.length,
|
|
1091
|
+
cachedWorkflowCount: 0,
|
|
1092
|
+
cachedAgentCount: 0,
|
|
1093
|
+
cachedTaskCount: 0,
|
|
1094
|
+
builtCount: successfulArtifacts.length + agentArtifacts.length + taskArtifacts.length,
|
|
1095
|
+
failedCount: failures.length,
|
|
1096
|
+
cachedCount: 0,
|
|
1097
|
+
elapsedMs: totalMs
|
|
1098
|
+
});
|
|
1099
|
+
return {
|
|
1100
|
+
artifacts: successfulArtifacts,
|
|
1101
|
+
agentArtifacts,
|
|
1102
|
+
taskArtifacts,
|
|
1103
|
+
failures,
|
|
1104
|
+
warnings,
|
|
1105
|
+
totalMs,
|
|
1106
|
+
success: failures.length === 0
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
async function createBuildPlan(options) {
|
|
1110
|
+
const plan = {
|
|
1111
|
+
workflows: [],
|
|
1112
|
+
agents: [],
|
|
1113
|
+
tasks: [],
|
|
1114
|
+
failures: []
|
|
1115
|
+
};
|
|
1116
|
+
let workflowProgressIndex = 0;
|
|
1117
|
+
for (const discoveredWorkflow of options.discoveredWorkflows) {
|
|
1118
|
+
const loadResult = options.metadataByKey.get(discoveredWorkflow.bindingKey);
|
|
1119
|
+
if (loadResult && isAgentLoadResult(loadResult)) {
|
|
1120
|
+
plan.agents.push({
|
|
1121
|
+
discoveredWorkflow,
|
|
1122
|
+
agentMetadata: loadResult.agentMetadata
|
|
1123
|
+
});
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
if (loadResult && isTaskLoadResult(loadResult)) {
|
|
1127
|
+
plan.tasks.push({
|
|
1128
|
+
discoveredWorkflow,
|
|
1129
|
+
taskMetadata: loadResult.taskMetadata
|
|
1130
|
+
});
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
const currentWorkflowIndex = workflowProgressIndex;
|
|
1134
|
+
workflowProgressIndex += 1;
|
|
1135
|
+
if (!loadResult?.ok) {
|
|
1136
|
+
const { createWorkflowMetadataFailure } = await import("./build-workflows-CfxBnIWh-CdYPv8w2.mjs");
|
|
1137
|
+
plan.failures.push(createWorkflowMetadataFailure(discoveredWorkflow, loadResult?.error));
|
|
1138
|
+
continue;
|
|
1139
|
+
}
|
|
1140
|
+
if (isWorkflowLoadResult(loadResult)) plan.workflows.push({
|
|
1141
|
+
discoveredWorkflow,
|
|
1142
|
+
metadata: loadResult.metadata,
|
|
1143
|
+
workflowIndex: currentWorkflowIndex
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
return plan;
|
|
1147
|
+
}
|
|
1148
|
+
function countDiscoveredExports(discoveredWorkflows) {
|
|
1149
|
+
let workflowCount = 0;
|
|
1150
|
+
let agentCount = 0;
|
|
1151
|
+
let taskCount = 0;
|
|
1152
|
+
for (const discoveredWorkflow of discoveredWorkflows) if (discoveredWorkflow.exportKind === "agent") agentCount += 1;
|
|
1153
|
+
else if (discoveredWorkflow.exportKind === "task") taskCount += 1;
|
|
1154
|
+
else workflowCount += 1;
|
|
1155
|
+
return {
|
|
1156
|
+
workflowCount,
|
|
1157
|
+
agentCount,
|
|
1158
|
+
taskCount
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Main build entry point. Discovers workflow exports, builds each through the pipeline
|
|
1163
|
+
* (import, manifest, flow-graph, bundle), and writes output artifacts.
|
|
1164
|
+
* Returns all artifacts on success or a list of failures with output set to null.
|
|
1165
|
+
*/
|
|
1166
|
+
async function build(config) {
|
|
1167
|
+
return runBuild(config);
|
|
1168
|
+
}
|
|
1169
|
+
async function runBuild(config, initialTargetBindingKeys, metadataRebuildDecision) {
|
|
1170
|
+
const context = await prepareBuildContext(config);
|
|
1171
|
+
const { emit, startedAt, outputDir, builderFingerprint, buildCache } = context;
|
|
1172
|
+
const discoveryStage = await runDiscoveryStage(config, context);
|
|
1173
|
+
if (discoveryStage.result) return discoveryStage.result;
|
|
1174
|
+
const { cacheInvalidated, discovery } = discoveryStage;
|
|
1175
|
+
const targetResolution = resolveTargetedDiscovery({
|
|
1176
|
+
projectRoot: config.projectRoot,
|
|
1177
|
+
discovery,
|
|
1178
|
+
targetFiles: config.targetFiles
|
|
1179
|
+
});
|
|
1180
|
+
if (targetResolution && "failure" in targetResolution) {
|
|
1181
|
+
const result = createFailedExecutionResult({
|
|
1182
|
+
failure: targetResolution.failure,
|
|
1183
|
+
startedAt
|
|
1184
|
+
});
|
|
1185
|
+
emit({
|
|
1186
|
+
phase: "complete",
|
|
1187
|
+
success: false,
|
|
1188
|
+
totalMs: result.totalMs
|
|
1189
|
+
});
|
|
1190
|
+
return result;
|
|
1191
|
+
}
|
|
1192
|
+
let targetBindingKeys = targetResolution?.targetBindingKeys ?? initialTargetBindingKeys;
|
|
1193
|
+
let scopedPlan = null;
|
|
1194
|
+
if (targetResolution) scopedPlan = {
|
|
1195
|
+
scopedDiscoveredWorkflows: discovery.workflows.filter((workflow) => targetResolution.targetBindingKeys.has(workflow.bindingKey)),
|
|
1196
|
+
preservedArtifacts: [],
|
|
1197
|
+
targetBindingKeys: targetResolution.targetBindingKeys
|
|
1198
|
+
};
|
|
1199
|
+
else while (!scopedPlan) {
|
|
1200
|
+
scopedPlan = await buildScopedDiscoveryPlan({
|
|
1201
|
+
outputDir,
|
|
1202
|
+
buildCache,
|
|
1203
|
+
discovery,
|
|
1204
|
+
targetBindingKeys
|
|
1205
|
+
});
|
|
1206
|
+
if (!scopedPlan) targetBindingKeys = void 0;
|
|
1207
|
+
}
|
|
1208
|
+
const { preservedArtifacts, scopedDiscoveredWorkflows } = scopedPlan;
|
|
1209
|
+
const { workflowCount: scopedWorkflowCount, agentCount: scopedAgentCount, taskCount: scopedTaskCount } = countDiscoveredExports(scopedDiscoveredWorkflows);
|
|
1210
|
+
const { cachedArtifacts, cachedAgentArtifacts, workflowsToBuild, fingerprintByBinding, validatedHashesByBinding, warnings: cacheWarnings, cacheResolutionMs } = await resolveCachedArtifacts({
|
|
1211
|
+
config,
|
|
1212
|
+
scopedDiscoveredWorkflows,
|
|
1213
|
+
buildCache,
|
|
1214
|
+
outputDir,
|
|
1215
|
+
cacheInvalidated,
|
|
1216
|
+
scopedWorkflowCount,
|
|
1217
|
+
emit
|
|
1218
|
+
});
|
|
1219
|
+
const warnings = [...cacheWarnings];
|
|
1220
|
+
const duplicateBindingKeys = /* @__PURE__ */ new Set();
|
|
1221
|
+
const duplicateWorkflowIds = /* @__PURE__ */ new Set();
|
|
1222
|
+
const buildStartedAt = performance.now();
|
|
1223
|
+
emit({
|
|
1224
|
+
phase: "build-start",
|
|
1225
|
+
workflowCount: scopedWorkflowCount,
|
|
1226
|
+
agentCount: scopedAgentCount,
|
|
1227
|
+
taskCount: scopedTaskCount
|
|
1228
|
+
});
|
|
1229
|
+
const bundlePipelineStartedAt = performance.now();
|
|
1230
|
+
const pipelineResult = workflowsToBuild.length > 0 ? await buildDiscoveredWorkflows({
|
|
1231
|
+
discoveredWorkflows: workflowsToBuild,
|
|
1232
|
+
projectRoot: config.projectRoot,
|
|
1233
|
+
metadataLoaderConcurrency: config.metadataLoaderConcurrency,
|
|
1234
|
+
sourceMaps: config.sourceMaps ?? true,
|
|
1235
|
+
onProgressEvent: config.onProgressEvent,
|
|
1236
|
+
emitLifecycleEvents: false
|
|
1237
|
+
}) : {
|
|
1238
|
+
artifacts: [],
|
|
1239
|
+
agentArtifacts: [],
|
|
1240
|
+
taskArtifacts: [],
|
|
1241
|
+
failures: [],
|
|
1242
|
+
warnings: [],
|
|
1243
|
+
totalMs: 0,
|
|
1244
|
+
success: true
|
|
1245
|
+
};
|
|
1246
|
+
const bundlePipelineMs = performance.now() - bundlePipelineStartedAt;
|
|
1247
|
+
const failures = [...pipelineResult.failures];
|
|
1248
|
+
warnings.push(...pipelineResult.warnings);
|
|
1249
|
+
const artifacts = [
|
|
1250
|
+
...preservedArtifacts,
|
|
1251
|
+
...cachedArtifacts,
|
|
1252
|
+
...pipelineResult.artifacts
|
|
1253
|
+
];
|
|
1254
|
+
const agentArtifacts = [...cachedAgentArtifacts, ...pipelineResult.agentArtifacts];
|
|
1255
|
+
const taskArtifacts = [...pipelineResult.taskArtifacts];
|
|
1256
|
+
const finalizedScopedArtifacts = failures.length === 0 ? [...cachedArtifacts, ...pipelineResult.artifacts] : [];
|
|
1257
|
+
try {
|
|
1258
|
+
assertUniqueWorkflowIds(artifacts);
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
if (error instanceof ReservedWorkflowIdError) {
|
|
1261
|
+
const failure = {
|
|
1262
|
+
kind: "workflow",
|
|
1263
|
+
workflow: {
|
|
1264
|
+
bindingKey: error.bindingKey,
|
|
1265
|
+
exportFilePath: error.file,
|
|
1266
|
+
resolvedFilePath: error.file,
|
|
1267
|
+
exportName: "",
|
|
1268
|
+
localExportName: ""
|
|
1269
|
+
},
|
|
1270
|
+
phase: "output",
|
|
1271
|
+
error: error.message
|
|
1272
|
+
};
|
|
1273
|
+
failures.push(failure);
|
|
1274
|
+
} else {
|
|
1275
|
+
const duplicateFailure = createDuplicateWorkflowIdFailure(artifacts, error);
|
|
1276
|
+
duplicateWorkflowIds.add(duplicateFailure.workflowId);
|
|
1277
|
+
for (const bindingKey of duplicateFailure.bindingKeys) duplicateBindingKeys.add(bindingKey);
|
|
1278
|
+
emit({
|
|
1279
|
+
phase: "duplicate-id-conflict",
|
|
1280
|
+
workflowId: duplicateFailure.workflowId,
|
|
1281
|
+
files: duplicateFailure.files
|
|
1282
|
+
});
|
|
1283
|
+
failures.push(duplicateFailure);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
try {
|
|
1287
|
+
assertUniqueAgentIds(agentArtifacts);
|
|
1288
|
+
} catch (error) {
|
|
1289
|
+
if (error instanceof DuplicateAgentIdError) {
|
|
1290
|
+
for (const bindingKey of error.bindingKeys) duplicateBindingKeys.add(bindingKey);
|
|
1291
|
+
failures.push({
|
|
1292
|
+
kind: "duplicate-agent-id",
|
|
1293
|
+
agentId: error.agentId,
|
|
1294
|
+
files: error.files,
|
|
1295
|
+
bindingKeys: error.bindingKeys,
|
|
1296
|
+
phase: "output",
|
|
1297
|
+
error: error.message
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
const successfulArtifacts = failures.length === 0 ? artifacts : [];
|
|
1302
|
+
emit({
|
|
1303
|
+
phase: "build-complete",
|
|
1304
|
+
workflowBuiltCount: pipelineResult.artifacts.length,
|
|
1305
|
+
agentBuiltCount: pipelineResult.agentArtifacts.length,
|
|
1306
|
+
taskBuiltCount: pipelineResult.taskArtifacts.length,
|
|
1307
|
+
cachedWorkflowCount: cachedArtifacts.length,
|
|
1308
|
+
cachedAgentCount: cachedAgentArtifacts.length,
|
|
1309
|
+
cachedTaskCount: 0,
|
|
1310
|
+
builtCount: pipelineResult.artifacts.length + pipelineResult.agentArtifacts.length + pipelineResult.taskArtifacts.length,
|
|
1311
|
+
failedCount: failures.length,
|
|
1312
|
+
cachedCount: cachedArtifacts.length + cachedAgentArtifacts.length,
|
|
1313
|
+
elapsedMs: performance.now() - buildStartedAt,
|
|
1314
|
+
cacheResolutionMs,
|
|
1315
|
+
bundlePipelineMs
|
|
1316
|
+
});
|
|
1317
|
+
const finalizedArtifacts = failures.length === 0 ? successfulArtifacts : [];
|
|
1318
|
+
let output = null;
|
|
1319
|
+
let metadataCacheEntries = buildCache.metadata;
|
|
1320
|
+
if (failures.length === 0) {
|
|
1321
|
+
emit({
|
|
1322
|
+
phase: "output-start",
|
|
1323
|
+
artifactCount: finalizedArtifacts.length + agentArtifacts.length + taskArtifacts.length
|
|
1324
|
+
});
|
|
1325
|
+
const writeStartedAt = performance.now();
|
|
1326
|
+
const cacheResolvedBindingKeys = new Set([...cachedArtifacts.map((a) => a.workflow.bindingKey), ...cachedAgentArtifacts.map((a) => a.agent.bindingKey)]);
|
|
1327
|
+
const writeOptions = {
|
|
1328
|
+
skipUnchangedWrites: !config.force,
|
|
1329
|
+
buildCache,
|
|
1330
|
+
force: config.force,
|
|
1331
|
+
cacheResolvedBindingKeys,
|
|
1332
|
+
releaseBundleMemory: config.releaseBundleMemory
|
|
1333
|
+
};
|
|
1334
|
+
const { writeBuildOutput, writeTargetedBuildOutput } = await import("./writer-BG8poUm3-BbXlU2kI.mjs").then((n) => n.f).then((n) => n.t);
|
|
1335
|
+
const writeResult = targetBindingKeys ? await writeTargetedBuildOutput({
|
|
1336
|
+
artifacts: finalizedScopedArtifacts,
|
|
1337
|
+
agentArtifacts,
|
|
1338
|
+
taskArtifacts,
|
|
1339
|
+
failures: [],
|
|
1340
|
+
warnings,
|
|
1341
|
+
totalMs: pipelineResult.totalMs,
|
|
1342
|
+
success: true
|
|
1343
|
+
}, outputDir, collectPreviousWorkflowIds(buildCache, targetBindingKeys), writeOptions) : await writeBuildOutput({
|
|
1344
|
+
artifacts: finalizedArtifacts,
|
|
1345
|
+
agentArtifacts,
|
|
1346
|
+
taskArtifacts,
|
|
1347
|
+
failures: [],
|
|
1348
|
+
warnings,
|
|
1349
|
+
totalMs: pipelineResult.totalMs,
|
|
1350
|
+
success: true
|
|
1351
|
+
}, outputDir, writeOptions);
|
|
1352
|
+
emit({
|
|
1353
|
+
phase: "output-complete",
|
|
1354
|
+
writtenCount: writeResult.writtenCount,
|
|
1355
|
+
cleanedCount: writeResult.cleanedCount,
|
|
1356
|
+
elapsedMs: performance.now() - writeStartedAt,
|
|
1357
|
+
...writeResult.skippedWriteCount !== void 0 && writeResult.skippedWriteCount > 0 ? { skippedWriteCount: writeResult.skippedWriteCount } : {}
|
|
1358
|
+
});
|
|
1359
|
+
const { buildMetadataArtifacts } = await import("./build-metadata-BWS7uhd_-DR8gJjTX.mjs");
|
|
1360
|
+
const metadata = await buildMetadataArtifacts({
|
|
1361
|
+
projectRoot: config.projectRoot,
|
|
1362
|
+
outputDir,
|
|
1363
|
+
artifacts: finalizedArtifacts,
|
|
1364
|
+
cacheEntries: buildCache.metadata,
|
|
1365
|
+
cacheInvalidated,
|
|
1366
|
+
rebuildDecision: targetResolution && "affectedPaths" in targetResolution ? {
|
|
1367
|
+
action: "targeted",
|
|
1368
|
+
affectedPaths: targetResolution.affectedPaths
|
|
1369
|
+
} : metadataRebuildDecision,
|
|
1370
|
+
emit
|
|
1371
|
+
});
|
|
1372
|
+
const conventionErrors = [];
|
|
1373
|
+
for (const violation of metadata.conventionViolations) if (violation.level === "warning") warnings.push(violation.message);
|
|
1374
|
+
else {
|
|
1375
|
+
failures.push({
|
|
1376
|
+
kind: "convention",
|
|
1377
|
+
filePath: violation.filePath,
|
|
1378
|
+
error: violation.message
|
|
1379
|
+
});
|
|
1380
|
+
conventionErrors.push(violation.message);
|
|
1381
|
+
}
|
|
1382
|
+
if (conventionErrors.length > 0) emit({
|
|
1383
|
+
phase: "convention-errors",
|
|
1384
|
+
errorCount: conventionErrors.length,
|
|
1385
|
+
errors: conventionErrors
|
|
1386
|
+
});
|
|
1387
|
+
try {
|
|
1388
|
+
assertUniqueCredentialSetDefinitionResolvedIds(metadata.analyzedFacts);
|
|
1389
|
+
} catch (error) {
|
|
1390
|
+
if (error instanceof Error) failures.push({
|
|
1391
|
+
kind: "convention",
|
|
1392
|
+
filePath: error instanceof DuplicateCredentialSetIdError ? error.files[0] ?? "" : "",
|
|
1393
|
+
error: error.message
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
output = {
|
|
1397
|
+
writtenCount: writeResult.writtenCount,
|
|
1398
|
+
cleanedCount: writeResult.cleanedCount,
|
|
1399
|
+
outputDir: writeResult.outputDir,
|
|
1400
|
+
...writeResult.skippedWriteCount !== void 0 && writeResult.skippedWriteCount > 0 ? { skippedWriteCount: writeResult.skippedWriteCount } : {},
|
|
1401
|
+
metadata: metadata.result
|
|
1402
|
+
};
|
|
1403
|
+
metadataCacheEntries = metadata.cacheEntries;
|
|
1404
|
+
}
|
|
1405
|
+
if (failures.length === 0) {
|
|
1406
|
+
const cacheEntries = createWorkflowCacheEntries(targetBindingKeys ? finalizedScopedArtifacts : finalizedArtifacts, validatedHashesByBinding);
|
|
1407
|
+
const agentCacheEntries = createAgentCacheEntries(targetBindingKeys ? pipelineResult.agentArtifacts : agentArtifacts, validatedHashesByBinding);
|
|
1408
|
+
for (const artifact of finalizedArtifacts) {
|
|
1409
|
+
const fingerprint = fingerprintByBinding.get(artifact.workflow.bindingKey) ?? await computeWorkflowFingerprint(artifact.workflow.resolvedFilePath, artifact.bundle.localDependencies);
|
|
1410
|
+
const cacheEntry = cacheEntries[artifact.workflow.bindingKey];
|
|
1411
|
+
if (cacheEntry) cacheEntry.inputFingerprint = fingerprint;
|
|
1412
|
+
}
|
|
1413
|
+
for (const artifact of agentArtifacts) {
|
|
1414
|
+
const fingerprint = fingerprintByBinding.get(artifact.agent.bindingKey) ?? await computeWorkflowFingerprint(artifact.agent.resolvedFilePath, artifact.bundle.localDependencies);
|
|
1415
|
+
const cacheEntry = agentCacheEntries[artifact.agent.bindingKey];
|
|
1416
|
+
if (cacheEntry) cacheEntry.inputFingerprint = fingerprint;
|
|
1417
|
+
}
|
|
1418
|
+
await writeBuildCache(outputDir, {
|
|
1419
|
+
...buildCache,
|
|
1420
|
+
builderFingerprint,
|
|
1421
|
+
scanEntries: discovery.scanEntries,
|
|
1422
|
+
bindings: targetBindingKeys ? mergeScopedBindings(buildCache, cacheEntries, targetBindingKeys) : cacheEntries,
|
|
1423
|
+
agentBindings: targetBindingKeys ? mergeScopedAgentBindings(buildCache, agentCacheEntries, targetBindingKeys) : agentCacheEntries,
|
|
1424
|
+
metadata: metadataCacheEntries
|
|
1425
|
+
});
|
|
1426
|
+
} else await cleanupFailedBuild({
|
|
1427
|
+
buildCache,
|
|
1428
|
+
builderFingerprint,
|
|
1429
|
+
discoveryScanEntries: discovery.scanEntries,
|
|
1430
|
+
duplicateBindingKeys,
|
|
1431
|
+
duplicateWorkflowIds,
|
|
1432
|
+
failures,
|
|
1433
|
+
metadataRebuildDecision,
|
|
1434
|
+
outputDir
|
|
1435
|
+
});
|
|
1436
|
+
const totalMs = performance.now() - startedAt;
|
|
1437
|
+
const result = {
|
|
1438
|
+
artifacts: finalizedArtifacts,
|
|
1439
|
+
agentArtifacts,
|
|
1440
|
+
taskArtifacts,
|
|
1441
|
+
failures,
|
|
1442
|
+
warnings,
|
|
1443
|
+
totalMs,
|
|
1444
|
+
success: failures.length === 0,
|
|
1445
|
+
output
|
|
1446
|
+
};
|
|
1447
|
+
emit({
|
|
1448
|
+
phase: "complete",
|
|
1449
|
+
success: result.success,
|
|
1450
|
+
totalMs
|
|
1451
|
+
});
|
|
1452
|
+
return result;
|
|
1453
|
+
}
|
|
1454
|
+
async function prepareBuildContext(config) {
|
|
1455
|
+
const emit = createProgressEmitter(config.onProgressEvent);
|
|
1456
|
+
const startedAt = performance.now();
|
|
1457
|
+
await assertWorkflowProjectRoot(config.projectRoot);
|
|
1458
|
+
const outputDir = resolveBuildOutputDir(config);
|
|
1459
|
+
if (hasTargetFiles(config) && !config.outDir) await fs.rm(outputDir, {
|
|
1460
|
+
recursive: true,
|
|
1461
|
+
force: true
|
|
1462
|
+
});
|
|
1463
|
+
const builderFingerprint = await computeBuilderFingerprint(path$1.join(path$1.dirname(fileURLToPath(import.meta.url)), ".."));
|
|
1464
|
+
const existingCache = config.force ? null : await readBuildCache(outputDir);
|
|
1465
|
+
return {
|
|
1466
|
+
emit,
|
|
1467
|
+
startedAt,
|
|
1468
|
+
outputDir,
|
|
1469
|
+
builderFingerprint,
|
|
1470
|
+
buildCache: config.force || !existingCache || existingCache.builderFingerprint !== builderFingerprint ? createEmptyBuildCache(builderFingerprint) : existingCache
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
function hasTargetFiles(config) {
|
|
1474
|
+
return (config.targetFiles?.length ?? 0) > 0;
|
|
1475
|
+
}
|
|
1476
|
+
function resolveBuildOutputDir(config) {
|
|
1477
|
+
if (!hasTargetFiles(config)) return resolveOutputDir(config.projectRoot, config);
|
|
1478
|
+
if (config.outDir) return resolveOutputDir(config.projectRoot, config);
|
|
1479
|
+
const normalizedTargets = (config.targetFiles ?? []).map((target) => path$1.isAbsolute(target) ? target : path$1.resolve(config.projectRoot, target)).map((target) => path$1.normalize(target)).sort((left, right) => left.localeCompare(right));
|
|
1480
|
+
const targetHash = createHash("sha256").update(JSON.stringify(normalizedTargets)).digest("hex");
|
|
1481
|
+
return path$1.join(getKeystrokeTmpDir({ projectRoot: config.projectRoot }), "target-builds", targetHash);
|
|
1482
|
+
}
|
|
1483
|
+
async function runDiscoveryStage(config, context) {
|
|
1484
|
+
const existingCache = config.force ? null : await readBuildCache(context.outputDir);
|
|
1485
|
+
const cacheInvalidated = Boolean(existingCache && existingCache.builderFingerprint !== context.builderFingerprint);
|
|
1486
|
+
context.emit({
|
|
1487
|
+
phase: "discovery-start",
|
|
1488
|
+
filesTotal: 0
|
|
1489
|
+
});
|
|
1490
|
+
try {
|
|
1491
|
+
const discovery = await discoverWorkflows({
|
|
1492
|
+
projectRoot: config.projectRoot,
|
|
1493
|
+
scanEntries: context.buildCache.scanEntries,
|
|
1494
|
+
onProgress: ({ filesScanned, filesTotal }) => {
|
|
1495
|
+
context.emit({
|
|
1496
|
+
phase: "discovery-scan",
|
|
1497
|
+
filesScanned,
|
|
1498
|
+
filesTotal
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
context.emit({
|
|
1503
|
+
phase: "discovery-complete",
|
|
1504
|
+
workflowCount: discovery.workflowCount,
|
|
1505
|
+
agentCount: discovery.agentCount,
|
|
1506
|
+
filesScanned: discovery.filesScanned,
|
|
1507
|
+
elapsedMs: discovery.elapsedMs
|
|
1508
|
+
});
|
|
1509
|
+
return {
|
|
1510
|
+
cacheInvalidated,
|
|
1511
|
+
discovery
|
|
1512
|
+
};
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
const result = createFailedExecutionResult({
|
|
1515
|
+
failure: createDiscoveryFailure(error),
|
|
1516
|
+
startedAt: context.startedAt
|
|
1517
|
+
});
|
|
1518
|
+
context.emit({
|
|
1519
|
+
phase: "complete",
|
|
1520
|
+
success: false,
|
|
1521
|
+
totalMs: result.totalMs
|
|
1522
|
+
});
|
|
1523
|
+
return { result };
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
async function buildScopedDiscoveryPlan(options) {
|
|
1527
|
+
if (!options.targetBindingKeys) return {
|
|
1528
|
+
scopedDiscoveredWorkflows: options.discovery.workflows,
|
|
1529
|
+
preservedArtifacts: [],
|
|
1530
|
+
targetBindingKeys: void 0
|
|
1531
|
+
};
|
|
1532
|
+
const discoveredBindingKeys = new Set(options.discovery.workflows.map((workflow) => workflow.bindingKey));
|
|
1533
|
+
for (const bindingKey of Array.from(options.targetBindingKeys)) if (!discoveredBindingKeys.has(bindingKey)) return null;
|
|
1534
|
+
const preservedArtifacts = [];
|
|
1535
|
+
for (const discoveredWorkflow of options.discovery.workflows) {
|
|
1536
|
+
if (options.targetBindingKeys.has(discoveredWorkflow.bindingKey)) continue;
|
|
1537
|
+
const preservedArtifact = await loadPreservedArtifact(options.outputDir, discoveredWorkflow, options.buildCache);
|
|
1538
|
+
if (!preservedArtifact) return null;
|
|
1539
|
+
preservedArtifacts.push(preservedArtifact);
|
|
1540
|
+
}
|
|
1541
|
+
return {
|
|
1542
|
+
scopedDiscoveredWorkflows: options.discovery.workflows.filter((workflow) => options.targetBindingKeys?.has(workflow.bindingKey)),
|
|
1543
|
+
preservedArtifacts,
|
|
1544
|
+
targetBindingKeys: options.targetBindingKeys
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
function resolveTargetedDiscovery(options) {
|
|
1548
|
+
const targetFiles = options.targetFiles?.filter((target) => target.trim().length > 0) ?? [];
|
|
1549
|
+
if (targetFiles.length === 0) return null;
|
|
1550
|
+
const normalizedTargets = /* @__PURE__ */ new Map();
|
|
1551
|
+
for (const target of targetFiles) {
|
|
1552
|
+
const absolutePath = path$1.normalize(path$1.isAbsolute(target) ? target : path$1.resolve(options.projectRoot, target));
|
|
1553
|
+
normalizedTargets.set(absolutePath, target);
|
|
1554
|
+
}
|
|
1555
|
+
const matchedBindingKeys = /* @__PURE__ */ new Set();
|
|
1556
|
+
const affectedPaths = /* @__PURE__ */ new Set();
|
|
1557
|
+
const matchedTargets = /* @__PURE__ */ new Set();
|
|
1558
|
+
for (const discoveredWorkflow of options.discovery.workflows) {
|
|
1559
|
+
const resolvedPath = path$1.normalize(discoveredWorkflow.resolvedFilePath);
|
|
1560
|
+
if (!normalizedTargets.has(resolvedPath)) continue;
|
|
1561
|
+
matchedBindingKeys.add(discoveredWorkflow.bindingKey);
|
|
1562
|
+
affectedPaths.add(discoveredWorkflow.relativePath);
|
|
1563
|
+
matchedTargets.add(resolvedPath);
|
|
1564
|
+
}
|
|
1565
|
+
for (const [absolutePath, originalTarget] of normalizedTargets) {
|
|
1566
|
+
if (matchedTargets.has(absolutePath)) continue;
|
|
1567
|
+
return { failure: {
|
|
1568
|
+
kind: "discovery",
|
|
1569
|
+
code: "unknown-discovery-error",
|
|
1570
|
+
filePath: absolutePath,
|
|
1571
|
+
exportNames: [],
|
|
1572
|
+
error: `Target file "${originalTarget}" did not contain any deployable workflow, agent, or task exports.`
|
|
1573
|
+
} };
|
|
1574
|
+
}
|
|
1575
|
+
return {
|
|
1576
|
+
targetBindingKeys: matchedBindingKeys,
|
|
1577
|
+
affectedPaths: Array.from(affectedPaths).sort((left, right) => left.localeCompare(right))
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
function createFailedExecutionResult(options) {
|
|
1581
|
+
return {
|
|
1582
|
+
artifacts: [],
|
|
1583
|
+
agentArtifacts: [],
|
|
1584
|
+
taskArtifacts: [],
|
|
1585
|
+
failures: options.failures ?? (options.failure ? [options.failure] : []),
|
|
1586
|
+
warnings: options.warnings ?? [],
|
|
1587
|
+
totalMs: performance.now() - options.startedAt,
|
|
1588
|
+
success: false,
|
|
1589
|
+
output: null
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
function collectPreviousWorkflowIds(buildCache, targetBindingKeys) {
|
|
1593
|
+
const workflowIds = /* @__PURE__ */ new Set();
|
|
1594
|
+
for (const bindingKey of Array.from(targetBindingKeys)) {
|
|
1595
|
+
const workflowId = buildCache.bindings[bindingKey]?.workflowId;
|
|
1596
|
+
if (workflowId) workflowIds.add(workflowId);
|
|
1597
|
+
}
|
|
1598
|
+
return Array.from(workflowIds).sort((left, right) => left.localeCompare(right));
|
|
1599
|
+
}
|
|
1600
|
+
async function loadPreservedArtifact(outputDir, discoveredWorkflow, buildCache) {
|
|
1601
|
+
const cachedEntry = buildCache.bindings[discoveredWorkflow.bindingKey];
|
|
1602
|
+
if (!cachedEntry) return null;
|
|
1603
|
+
return loadCachedArtifact(outputDir, discoveredWorkflow, cachedEntry);
|
|
1604
|
+
}
|
|
1605
|
+
function mergeScopedBindings(buildCache, nextBindings, targetBindingKeys) {
|
|
1606
|
+
const mergedBindings = Object.fromEntries(typedEntries(buildCache.bindings).filter(([bindingKey]) => !targetBindingKeys.has(bindingKey)));
|
|
1607
|
+
for (const [bindingKey, entry] of Object.entries(nextBindings)) mergedBindings[bindingKey] = entry;
|
|
1608
|
+
return mergedBindings;
|
|
1609
|
+
}
|
|
1610
|
+
function mergeScopedAgentBindings(buildCache, nextBindings, targetBindingKeys) {
|
|
1611
|
+
const mergedBindings = Object.fromEntries(typedEntries(buildCache.agentBindings).filter(([bindingKey]) => !targetBindingKeys.has(bindingKey)));
|
|
1612
|
+
for (const [bindingKey, entry] of Object.entries(nextBindings)) mergedBindings[bindingKey] = entry;
|
|
1613
|
+
return mergedBindings;
|
|
1614
|
+
}
|
|
1615
|
+
async function cleanupFailedBuild(options) {
|
|
1616
|
+
const bindingKeysToRemove = new Set(options.duplicateBindingKeys);
|
|
1617
|
+
const workflowIdsToRemove = new Set(options.duplicateWorkflowIds);
|
|
1618
|
+
const agentIdsToRemove = /* @__PURE__ */ new Set();
|
|
1619
|
+
for (const failure of options.failures) {
|
|
1620
|
+
if (isWorkflowScopedBuildFailure(failure) && failure.workflow.bindingKey) bindingKeysToRemove.add(failure.workflow.bindingKey);
|
|
1621
|
+
if (isWorkflowScopedBuildFailure(failure) && failure.workflow.workflowId) workflowIdsToRemove.add(failure.workflow.workflowId);
|
|
1622
|
+
if (isDuplicateWorkflowIdFailure(failure)) {
|
|
1623
|
+
for (const bindingKey of failure.bindingKeys) {
|
|
1624
|
+
bindingKeysToRemove.add(bindingKey);
|
|
1625
|
+
const cachedEntry = options.buildCache.bindings[bindingKey];
|
|
1626
|
+
if (cachedEntry) workflowIdsToRemove.add(cachedEntry.workflowId);
|
|
1627
|
+
}
|
|
1628
|
+
workflowIdsToRemove.add(failure.workflowId);
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
if (isDuplicateAgentIdFailure(failure)) {
|
|
1632
|
+
for (const bindingKey of failure.bindingKeys) {
|
|
1633
|
+
bindingKeysToRemove.add(bindingKey);
|
|
1634
|
+
const cachedAgentEntry = options.buildCache.agentBindings[bindingKey];
|
|
1635
|
+
if (cachedAgentEntry) agentIdsToRemove.add(cachedAgentEntry.agentId);
|
|
1636
|
+
}
|
|
1637
|
+
agentIdsToRemove.add(failure.agentId);
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
if (!isWorkflowScopedBuildFailure(failure)) continue;
|
|
1641
|
+
const cachedEntry = options.buildCache.bindings[failure.workflow.bindingKey];
|
|
1642
|
+
if (cachedEntry) workflowIdsToRemove.add(cachedEntry.workflowId);
|
|
1643
|
+
const cachedAgentEntry = options.buildCache.agentBindings[failure.workflow.bindingKey];
|
|
1644
|
+
if (cachedAgentEntry) agentIdsToRemove.add(cachedAgentEntry.agentId);
|
|
1645
|
+
}
|
|
1646
|
+
await cleanupFailedBuildState({
|
|
1647
|
+
outputDir: options.outputDir,
|
|
1648
|
+
cache: options.buildCache,
|
|
1649
|
+
bindingKeysToRemove: Array.from(bindingKeysToRemove),
|
|
1650
|
+
workflowIdsToRemove: Array.from(workflowIdsToRemove),
|
|
1651
|
+
agentIdsToRemove: Array.from(agentIdsToRemove),
|
|
1652
|
+
metadataPathsToRemove: options.metadataRebuildDecision?.action === "targeted" ? options.metadataRebuildDecision.affectedPaths : void 0,
|
|
1653
|
+
builderFingerprint: options.builderFingerprint,
|
|
1654
|
+
scanEntries: options.discoveryScanEntries
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
//#endregion
|
|
1658
|
+
//#region ../../packages/workflow-builder/dist/build-format-06ylK1PX.mjs
|
|
1659
|
+
const RAW_OUTPUT_MAX_LENGTH = 500;
|
|
1660
|
+
function truncateRawOutput(raw) {
|
|
1661
|
+
const trimmed = raw.trim();
|
|
1662
|
+
if (trimmed.length <= RAW_OUTPUT_MAX_LENGTH) return trimmed;
|
|
1663
|
+
return `${trimmed.slice(0, RAW_OUTPUT_MAX_LENGTH)}… (truncated)`;
|
|
1664
|
+
}
|
|
1665
|
+
/** Formats a build failure into a human-readable single-line message. */
|
|
1666
|
+
function formatBuildFailure(failure) {
|
|
1667
|
+
switch (failure.kind) {
|
|
1668
|
+
case "workflow": return `${failure.workflow.resolvedFilePath}: ${failure.error}`;
|
|
1669
|
+
case "loader-protocol": {
|
|
1670
|
+
const raw = failure.rawOutput?.trim();
|
|
1671
|
+
if (raw && raw.length > 0 && !failure.error.includes(raw)) {
|
|
1672
|
+
const detail = truncateRawOutput(raw);
|
|
1673
|
+
return `${failure.workflow.resolvedFilePath}: ${failure.error}\n ${detail.split("\n").join("\n ")}`;
|
|
1674
|
+
}
|
|
1675
|
+
return `${failure.workflow.resolvedFilePath}: ${failure.error}`;
|
|
1676
|
+
}
|
|
1677
|
+
case "duplicate-workflow-id": return `${failure.workflowId}: ${failure.error}`;
|
|
1678
|
+
case "duplicate-agent-id": return `${failure.agentId}: ${failure.error}`;
|
|
1679
|
+
case "agent-cycle": return failure.error;
|
|
1680
|
+
case "discovery": return `${failure.filePath}: ${failure.error}`;
|
|
1681
|
+
case "trigger": return `trigger "${failure.triggerName}" (${failure.triggerExportName}) in workflow ${failure.workflowId}: ${failure.error}`;
|
|
1682
|
+
case "convention": return `${failure.filePath}: ${failure.error}`;
|
|
1683
|
+
case "agent": return `${failure.agent.resolvedFilePath}: ${failure.error}`;
|
|
1684
|
+
case "task": return `${failure.task.resolvedFilePath}: ${failure.error}`;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
//#endregion
|
|
1688
|
+
//#region src/lib/workflow-build.ts
|
|
1689
|
+
var workflow_build_exports = /* @__PURE__ */ __exportAll({
|
|
1690
|
+
WorkflowBuildExecutionError: () => WorkflowBuildExecutionError,
|
|
1691
|
+
WorkflowBuildFailedError: () => WorkflowBuildFailedError,
|
|
1692
|
+
WorkflowNotFoundError: () => WorkflowNotFoundError,
|
|
1693
|
+
renderBuildFailure: () => renderBuildFailure,
|
|
1694
|
+
renderBuildHeader: () => renderBuildHeader,
|
|
1695
|
+
renderBuildSummary: () => renderBuildSummary,
|
|
1696
|
+
runWorkflowBuild: () => runWorkflowBuild,
|
|
1697
|
+
workflowBuildDependencies: () => workflowBuildDependencies
|
|
1698
|
+
});
|
|
1699
|
+
const workflowBuildDependencies = {
|
|
1700
|
+
assertWorkflowProjectRoot,
|
|
1701
|
+
build
|
|
1702
|
+
};
|
|
1703
|
+
var WorkflowNotFoundError = class extends Error {
|
|
1704
|
+
workflowName;
|
|
1705
|
+
availableNames;
|
|
1706
|
+
constructor(workflowName, availableNames) {
|
|
1707
|
+
super(`Workflow "${workflowName}" not found.`);
|
|
1708
|
+
this.name = "WorkflowNotFoundError";
|
|
1709
|
+
this.workflowName = workflowName;
|
|
1710
|
+
this.availableNames = availableNames;
|
|
1711
|
+
}
|
|
1712
|
+
};
|
|
1713
|
+
var WorkflowBuildExecutionError = class extends Error {
|
|
1714
|
+
causeValue;
|
|
1715
|
+
constructor(causeValue) {
|
|
1716
|
+
const message = causeValue instanceof Error ? causeValue.message : String(causeValue);
|
|
1717
|
+
super(`Build error: ${message}`);
|
|
1718
|
+
this.name = "WorkflowBuildExecutionError";
|
|
1719
|
+
this.causeValue = causeValue;
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
var WorkflowBuildFailedError = class extends Error {
|
|
1723
|
+
errors;
|
|
1724
|
+
constructor(errors) {
|
|
1725
|
+
super("Build failed with errors.");
|
|
1726
|
+
this.name = "WorkflowBuildFailedError";
|
|
1727
|
+
this.errors = errors;
|
|
1728
|
+
}
|
|
1729
|
+
};
|
|
1730
|
+
async function runWorkflowBuild(options) {
|
|
1731
|
+
const projectConfig = await workflowBuildDependencies.assertWorkflowProjectRoot(options.workflowsDir);
|
|
1732
|
+
const outDir = resolveConfiguredBuildOutputDir(options.workflowsDir, projectConfig.build);
|
|
1733
|
+
let result;
|
|
1734
|
+
try {
|
|
1735
|
+
result = await workflowBuildDependencies.build({
|
|
1736
|
+
projectRoot: options.workflowsDir,
|
|
1737
|
+
outDir,
|
|
1738
|
+
force: options.force,
|
|
1739
|
+
targetFiles: options.targetFiles,
|
|
1740
|
+
metadataLoaderConcurrency: options.metadataLoaderConcurrency,
|
|
1741
|
+
releaseBundleMemory: options.releaseBundleMemory,
|
|
1742
|
+
sourceMaps: options.sourceMaps,
|
|
1743
|
+
onProgressEvent: options.onProgressEvent
|
|
1744
|
+
});
|
|
1745
|
+
} catch (error) {
|
|
1746
|
+
throw new WorkflowBuildExecutionError(error);
|
|
1747
|
+
}
|
|
1748
|
+
if (!result.success) throw new WorkflowBuildFailedError(result.failures);
|
|
1749
|
+
if (options.name) assertWorkflowRefExists(result, options.name);
|
|
1750
|
+
if (options.workflowRef) assertWorkflowRefExists(result, options.workflowRef);
|
|
1751
|
+
return {
|
|
1752
|
+
result,
|
|
1753
|
+
outDir: result.output?.outputDir ?? outDir
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
function renderBuildHeader(workflowName) {
|
|
1757
|
+
if (workflowName) {
|
|
1758
|
+
ui.header(`Building workflow "${workflowName}"...`);
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
ui.header("Building workflows and agents...");
|
|
1762
|
+
}
|
|
1763
|
+
function renderBuildSummary(result, outDir) {
|
|
1764
|
+
ui.success("Build complete");
|
|
1765
|
+
const check = style("✓", `${ANSI.bold}${ANSI.green}`);
|
|
1766
|
+
const workflowLine = `Workflows: ${result.artifacts.length}`;
|
|
1767
|
+
const agentLine = `Agents: ${result.agentArtifacts.length}`;
|
|
1768
|
+
originalConsole.info(` ${check} ${workflowLine}`);
|
|
1769
|
+
logger.info(` ✓ ${workflowLine}`);
|
|
1770
|
+
originalConsole.info(` ${check} ${agentLine}`);
|
|
1771
|
+
logger.info(` ✓ ${agentLine}`);
|
|
1772
|
+
if (result.output?.metadata) {
|
|
1773
|
+
const metadataLine = `Metadata: ${result.output.metadata.fileCount} file(s)`;
|
|
1774
|
+
originalConsole.info(` ${check} ${metadataLine}`);
|
|
1775
|
+
logger.info(` ✓ ${metadataLine}`);
|
|
1776
|
+
}
|
|
1777
|
+
const totalLine = `Total: ${formatTotalTime(result.totalMs)}`;
|
|
1778
|
+
originalConsole.info(` ${check} ${totalLine}`);
|
|
1779
|
+
logger.info(` ✓ ${totalLine}`);
|
|
1780
|
+
if (result.warnings.length > 0) {
|
|
1781
|
+
ui.warn(`Build produced ${result.warnings.length} warning(s):`);
|
|
1782
|
+
for (const warning of result.warnings) ui.hint(`- ${warning}`);
|
|
1783
|
+
}
|
|
1784
|
+
ui.hint(`Output: ${outDir}`);
|
|
1785
|
+
}
|
|
1786
|
+
function formatTotalTime(ms) {
|
|
1787
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
1788
|
+
const seconds = ms / 1e3;
|
|
1789
|
+
return seconds < 60 ? `${seconds.toFixed(1)}s` : `${Math.floor(seconds / 60)}m ${(seconds % 60).toFixed(1)}s`;
|
|
1790
|
+
}
|
|
1791
|
+
function renderBuildFailure(error) {
|
|
1792
|
+
if (error instanceof WorkflowNotFoundError) {
|
|
1793
|
+
ui.error(`Workflow "${error.workflowName}" not found.`);
|
|
1794
|
+
if (error.availableNames.length === 0) {
|
|
1795
|
+
ui.hint("No workflows were discovered in this project.");
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
ui.hint(`Available workflows: ${error.availableNames.join(", ")}`);
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (error instanceof WorkflowBuildExecutionError) {
|
|
1802
|
+
ui.error(error.message);
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
if (error instanceof WorkflowBuildFailedError) {
|
|
1806
|
+
ui.error("Build failed with errors:");
|
|
1807
|
+
for (const buildError of error.errors) ui.hint(`- ${formatBuildFailure(buildError)}`);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
ui.error(`Build error: ${toErrorMessage(error)}`);
|
|
1811
|
+
}
|
|
1812
|
+
function assertWorkflowRefExists(result, workflowRef) {
|
|
1813
|
+
if (result.artifacts.find((artifact) => artifact.manifest.id === workflowRef || artifact.manifest.name === workflowRef)) return;
|
|
1814
|
+
const availableNames = result.artifacts.map((artifact) => artifact.manifest.name).sort((left, right) => left.localeCompare(right));
|
|
1815
|
+
const availableIds = result.artifacts.map((artifact) => artifact.manifest.id).sort((left, right) => left.localeCompare(right));
|
|
1816
|
+
throw new WorkflowNotFoundError(workflowRef, availableNames.length > 0 ? availableNames : availableIds);
|
|
1817
|
+
}
|
|
1818
|
+
//#endregion
|
|
1819
|
+
export { runWorkflowBuild as a, renderBuildSummary as i, renderBuildFailure as n, workflow_build_exports as o, renderBuildHeader as r, build as s, WorkflowNotFoundError as t };
|