@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.
Files changed (122) hide show
  1. package/AGENTS-blurb.md +123 -0
  2. package/LICENSE +42 -0
  3. package/README.md +177 -0
  4. package/THIRD_PARTY_NOTICES.md +16 -0
  5. package/bin/keystroke.mjs +107 -0
  6. package/dist/_manifest-JSRE3H8k.mjs +385 -0
  7. package/dist/agent-bundle-package-DWV6B_5q-BtV7Xycc.mjs +2344 -0
  8. package/dist/agent-manifest-CDnbkR2f.mjs +245 -0
  9. package/dist/agents-CZJGxVqV.mjs +228 -0
  10. package/dist/api-keys-D2lgguuY.mjs +40 -0
  11. package/dist/auth-DN2VusyU.mjs +59 -0
  12. package/dist/auth.handler-CT1BQUvu.mjs +340 -0
  13. package/dist/browser-qwFrUH82.mjs +24 -0
  14. package/dist/build-agents-BmM_AsSd-BGi9wtzt.mjs +514 -0
  15. package/dist/build-metadata-BWS7uhd_-DR8gJjTX.mjs +1422 -0
  16. package/dist/build-progress-DgYKb4hB.mjs +183 -0
  17. package/dist/build-tasks-CdihpudT-D5r5HUHe.mjs +91 -0
  18. package/dist/build-workflows-CfxBnIWh-CdYPv8w2.mjs +370 -0
  19. package/dist/build.handler-4799CjWH.mjs +36 -0
  20. package/dist/chunk-CH6r78ws.mjs +37 -0
  21. package/dist/clear-cache.handler-B9tqSoSM.mjs +11 -0
  22. package/dist/clear.handler-BTIXXPTJ.mjs +42 -0
  23. package/dist/clear.handler-BydlX-zE.mjs +11 -0
  24. package/dist/commander-DfTVqQ-3.mjs +133 -0
  25. package/dist/concurrency-gXn9Rw8x-DNl2YtrS.mjs +20 -0
  26. package/dist/connect-BUXkeH0F.mjs +43 -0
  27. package/dist/connect.handler-CYel9cy6.mjs +430 -0
  28. package/dist/constants-CPpPdSNg.mjs +8 -0
  29. package/dist/context-T7HZuB97.mjs +138 -0
  30. package/dist/credential-env-map-CI8yWHVy.mjs +28 -0
  31. package/dist/credential-schema-mismatch-BKo5PjcQ.mjs +76 -0
  32. package/dist/credentials-CvmjU0lK.mjs +171 -0
  33. package/dist/credentials-OfVHOtG3.mjs +151216 -0
  34. package/dist/current-deployment-workflow-poHt27i3.mjs +94 -0
  35. package/dist/current.handler-B8zKzfPp.mjs +21 -0
  36. package/dist/delete.handler-bAu1iXVQ.mjs +17 -0
  37. package/dist/deploy-7Jjls436.mjs +26 -0
  38. package/dist/deploy-BOPIpRWm.mjs +74 -0
  39. package/dist/deploy-progress-BmGUNFKg.mjs +70 -0
  40. package/dist/deploy.handler-BAzgiNhd.mjs +370 -0
  41. package/dist/detect-env-access-CwkOYeYM-D_BCZqV6.mjs +209 -0
  42. package/dist/diff-utils-NEfcjqxt.mjs +185 -0
  43. package/dist/diff.handler-Du7SY8K4.mjs +47 -0
  44. package/dist/dist-BkJUoBiG.mjs +1116 -0
  45. package/dist/dist-CUK7yBM0.mjs +308 -0
  46. package/dist/env-91KwMKov.mjs +140 -0
  47. package/dist/env.handler-BAzBuMzQ.mjs +277 -0
  48. package/dist/error-boundary-VL-JLfIa.mjs +34 -0
  49. package/dist/file-metadata-D1vm-XY2.mjs +191 -0
  50. package/dist/get-intrinsic-zLxwtrLK.mjs +658 -0
  51. package/dist/import-module-CV84H5fZ-B_CBCmb4.mjs +1747 -0
  52. package/dist/init-DpMCotSK.mjs +45 -0
  53. package/dist/init.handler-CPRnif52.mjs +585 -0
  54. package/dist/inspect.handler-DT_cD036.mjs +146 -0
  55. package/dist/integration-catalog-Bt-L3GjF.mjs +104 -0
  56. package/dist/integrations-DlatPK4W.mjs +79 -0
  57. package/dist/keystroke.d.mts +3 -0
  58. package/dist/keystroke.mjs +707 -0
  59. package/dist/layout-CbMtQ2tm.mjs +67 -0
  60. package/dist/list-enrichment-y-cwizLr.mjs +189 -0
  61. package/dist/list.handler-BTWvCyjA.mjs +52 -0
  62. package/dist/list.handler-CWF_Dj15.mjs +24 -0
  63. package/dist/list.handler-CZ6G2x_G.mjs +75 -0
  64. package/dist/list.handler-DWaQkJaR.mjs +51 -0
  65. package/dist/list.handler-DqbFcBW7.mjs +180 -0
  66. package/dist/list.handler-lq3ZGAn4.mjs +104 -0
  67. package/dist/logs-BEg9L5l8.mjs +28 -0
  68. package/dist/logs.handler-6hoMBzqw.mjs +35 -0
  69. package/dist/logs.handler-BD_dXiL1.mjs +231 -0
  70. package/dist/metadata-layout-GUYIUo0i-_aG2zjue.mjs +5877 -0
  71. package/dist/normalize-path-CojS-CgQ-DLCOvnD1.mjs +20 -0
  72. package/dist/options-CeaTcFxP.mjs +43 -0
  73. package/dist/org-xLzBtt2_.mjs +41 -0
  74. package/dist/output-DM4b7KgY.mjs +72 -0
  75. package/dist/oxc-B3KI3rf_-n9d1hKNq.mjs +119 -0
  76. package/dist/paused.handler-BMFm9Cff.mjs +94 -0
  77. package/dist/project-config-D1qsQlO7.mjs +107 -0
  78. package/dist/projects-CHkRE9rS.mjs +1574 -0
  79. package/dist/projects-Cjb7sovS.mjs +30 -0
  80. package/dist/read-credential-keys-77a91T8M-KA0Iw0Z1.mjs +9 -0
  81. package/dist/register.handler-BPCdor1_.mjs +86 -0
  82. package/dist/requirements.handler-DPXdSks3.mjs +201 -0
  83. package/dist/resolve-project-DDJ29sCF.mjs +35 -0
  84. package/dist/rolldown-runtime-twds-ZHy-BWWzu8VG.mjs +15 -0
  85. package/dist/run-polling-CAgFRdK3.mjs +20 -0
  86. package/dist/runs-D9hNLb9A.mjs +259 -0
  87. package/dist/schedule-BXx3uXwr.mjs +1142 -0
  88. package/dist/schema-17qMfNyI.mjs +18 -0
  89. package/dist/schema-display-CgmeKigW.mjs +130 -0
  90. package/dist/schemas-CDib1RhE.mjs +125 -0
  91. package/dist/skills-sync.handler-DIy8GR16.mjs +34 -0
  92. package/dist/skills.command-CrjI2dN9.mjs +35 -0
  93. package/dist/skills.handler-Bz8bJKql.mjs +9 -0
  94. package/dist/source-analysis-Cj-ADyu--BJQcFPCG.mjs +144 -0
  95. package/dist/spinner-progress-DMVwgqO9.mjs +173 -0
  96. package/dist/src-C0X6u_Mw.mjs +1340 -0
  97. package/dist/src-eHwu-Gfw.mjs +369 -0
  98. package/dist/status.handler-BO4nwvWn.mjs +101 -0
  99. package/dist/switch.handler-D_9213Vf.mjs +51 -0
  100. package/dist/sync-BL_Mo5st.mjs +39 -0
  101. package/dist/sync-keystroke-agent-skills-Kx_H7UTd.mjs +70 -0
  102. package/dist/sync.handler-BUFPdzWz.mjs +82 -0
  103. package/dist/task-B2sZMaZu.mjs +8 -0
  104. package/dist/task-target-build-CBeCKbu2.mjs +432 -0
  105. package/dist/task-target-deploy-C5X-USeR.mjs +4 -0
  106. package/dist/task-target-deploy-CA6elFpF-BEr4gkol.mjs +271 -0
  107. package/dist/task-target-deploy-runner.d.mts +3 -0
  108. package/dist/task-target-deploy-runner.mjs +202 -0
  109. package/dist/test-BHTgR3UA.mjs +698 -0
  110. package/dist/test.handler-BcPQ8b74.mjs +13 -0
  111. package/dist/trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs +239 -0
  112. package/dist/trigger-manifest-CY7brZeg.mjs +30 -0
  113. package/dist/try-deploy.handler-DqybNhXx.mjs +490 -0
  114. package/dist/upload-CkU--iDC.mjs +207 -0
  115. package/dist/upload.handler-DCtiznQp.mjs +441 -0
  116. package/dist/utils-CywxCDM7.mjs +14 -0
  117. package/dist/validate.handler-DOcTaJL0.mjs +280 -0
  118. package/dist/workflow-build-DBQaBfnn.mjs +1819 -0
  119. package/dist/workflow-bundler-BPiqVscj-X1PFFAuP.mjs +167 -0
  120. package/dist/workflows-g9z87AJJ.mjs +799 -0
  121. package/dist/writer-BG8poUm3-BbXlU2kI.mjs +426 -0
  122. package/package.json +87 -0
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { i as logger } from "./keystroke.mjs";
4
+ import { n as formatProgressDuration, t as createSpinnerProgress } from "./spinner-progress-DMVwgqO9.mjs";
5
+ //#region src/lib/build-progress.ts
6
+ const NEW_STAGE_LABELS = {
7
+ start: "Starting build",
8
+ cached: "Using cached artifact",
9
+ success: "Complete",
10
+ failure: "Failed"
11
+ };
12
+ const PHASE_SCAN = "scan";
13
+ const PHASE_BUILD = "build";
14
+ const PHASE_OUTPUT = "output";
15
+ const PHASE_METADATA = "metadata";
16
+ function formatArtifactCount(count, kind) {
17
+ return `${count} ${kind}(s)`;
18
+ }
19
+ function formatArtifactSummaryCount(count, kind) {
20
+ return `${count} ${kind}${count === 1 ? "" : "s"}`;
21
+ }
22
+ function formatArtifactSummary(workflowCount, agentCount) {
23
+ const parts = [];
24
+ if (workflowCount > 0 || agentCount === 0) parts.push(formatArtifactSummaryCount(workflowCount, "workflow"));
25
+ if (agentCount > 0) parts.push(formatArtifactSummaryCount(agentCount, "agent"));
26
+ return parts.length > 1 ? `${parts.slice(0, -1).join(", ")} and ${parts.at(-1)}` : parts[0] ?? formatArtifactSummaryCount(0, "workflow");
27
+ }
28
+ function formatOutputCompleteLabel(event) {
29
+ const { writtenCount, skippedWriteCount } = event;
30
+ if (skippedWriteCount === void 0 || skippedWriteCount === 0) return writtenCount === 1 ? "Wrote 1 artifact" : `Wrote ${writtenCount} artifact(s)`;
31
+ return `Wrote ${writtenCount - skippedWriteCount} of ${writtenCount} artifact(s)\n${skippedWriteCount === 1 ? "1 unchanged on disk" : `${skippedWriteCount} unchanged on disk`}`;
32
+ }
33
+ /**
34
+ * Multi-line label: line 1 is short; following lines are dim detail (see spinner-worker).
35
+ * Avoids one huge truncated line in narrow terminals.
36
+ */
37
+ function formatBuildCompleteLabel(event) {
38
+ const workflowTotal = event.workflowBuiltCount + event.cachedWorkflowCount;
39
+ const agentTotal = event.agentBuiltCount + event.cachedAgentCount;
40
+ const builtParts = [];
41
+ if (workflowTotal > 0 || agentTotal === 0) builtParts.push(formatArtifactCount(workflowTotal, "workflow"));
42
+ if (agentTotal > 0) builtParts.push(formatArtifactCount(agentTotal, "agent"));
43
+ const lines = [`Bundled ${builtParts.length > 1 ? `${builtParts.slice(0, -1).join(", ")} and ${builtParts.at(-1)}` : builtParts[0] ?? formatArtifactCount(0, "workflow")}`];
44
+ const hasTiming = event.cacheResolutionMs !== void 0 && event.bundlePipelineMs !== void 0;
45
+ if (event.cacheResolutionMs !== void 0 && event.bundlePipelineMs !== void 0) lines.push(`cache ${formatProgressDuration(event.cacheResolutionMs)} · bundle ${formatProgressDuration(event.bundlePipelineMs)}`);
46
+ const builtWf = event.workflowBuiltCount;
47
+ const builtAg = event.agentBuiltCount;
48
+ const cachedWf = event.cachedWorkflowCount;
49
+ const cachedAg = event.cachedAgentCount;
50
+ if (builtWf === 0 && builtAg === 0 && cachedWf + cachedAg > 0) {
51
+ if (!hasTiming) lines.push("all bundle cache hits");
52
+ } else if (cachedWf > 0 || cachedAg > 0) {
53
+ const fromCacheParts = [];
54
+ if (cachedWf > 0) fromCacheParts.push(`${cachedWf} workflow${cachedWf === 1 ? "" : "s"}`);
55
+ if (cachedAg > 0) fromCacheParts.push(`${cachedAg} agent${cachedAg === 1 ? "" : "s"}`);
56
+ const fromCacheStr = `from cache: ${fromCacheParts.join(", ")}`;
57
+ if (builtWf > 0 || builtAg > 0) {
58
+ const rebuiltParts = [];
59
+ if (builtWf > 0) rebuiltParts.push(`${builtWf} workflow${builtWf === 1 ? "" : "s"}`);
60
+ if (builtAg > 0) rebuiltParts.push(`${builtAg} agent${builtAg === 1 ? "" : "s"}`);
61
+ lines.push(`${fromCacheStr} · rebuilt: ${rebuiltParts.join(", ")}`);
62
+ }
63
+ }
64
+ return lines.join("\n");
65
+ }
66
+ function formatDiscoveryStartLabel(filesTotal) {
67
+ return filesTotal === 1 ? "Scanning 1 file for workflows and agents..." : `Scanning ${filesTotal} files for workflows and agents...`;
68
+ }
69
+ function formatDiscoveryScanLabel(filesScanned, filesTotal) {
70
+ return `Scanning files for workflows and agents... (${filesScanned}/${filesTotal})`;
71
+ }
72
+ function formatDiscoveryCompleteLabel(workflowCount, agentCount, filesScanned) {
73
+ return `Found ${formatArtifactSummary(workflowCount, agentCount)} in ${filesScanned} file(s)`;
74
+ }
75
+ function formatBuildStartLabel(workflowName, workflowCount, agentCount) {
76
+ return workflowCount === 1 && agentCount === 0 ? `Building "${workflowName}"...` : `Building ${formatArtifactSummary(workflowCount, agentCount)}...`;
77
+ }
78
+ function formatMetadataStartLabel(fileCount) {
79
+ if (fileCount === 0) return "Discovering metadata files...";
80
+ if (fileCount === 1) return "Generating metadata for 1 file...";
81
+ return `Generating metadata for ${fileCount} file(s)...`;
82
+ }
83
+ function createBuildProgress(workflowName) {
84
+ logger.info(`[build] Starting: "${workflowName}"`);
85
+ const spinner = createSpinnerProgress("[build]");
86
+ let buildStartTime;
87
+ function getStageLabel(stage) {
88
+ return NEW_STAGE_LABELS[stage];
89
+ }
90
+ function getFailureMessage(event) {
91
+ let message = "Build failed";
92
+ if ("failure" in event) message = event.failure.error;
93
+ else if ("error" in event && typeof event.error === "string" && event.error.length > 0) message = event.error;
94
+ const firstLine = message.split("\n")[0] ?? message;
95
+ return firstLine.length > 120 ? `${firstLine.slice(0, 120)}…` : firstLine;
96
+ }
97
+ spinner.addPendingPhase(PHASE_SCAN, "Scan workflows and agents");
98
+ spinner.addPendingPhase(PHASE_BUILD, "Build workflows and agents");
99
+ spinner.addPendingPhase(PHASE_OUTPUT, "Write build output");
100
+ spinner.addPendingPhase(PHASE_METADATA, "File metadata");
101
+ function handleWorkflowStage(event) {
102
+ const { stage, workflowIndex, workflowCount } = event;
103
+ if (stage === "start") {
104
+ logger.info(`[build] → workflow ${workflowIndex}/${workflowCount}: ${stage}`);
105
+ return;
106
+ }
107
+ if (stage === "cached" || stage === "success") {
108
+ logger.info(`[build] ✓ workflow ${workflowIndex}/${workflowCount} ${stage === "cached" ? "cached" : "succeeded"} (${formatProgressDuration(event.elapsedMs)})`);
109
+ return;
110
+ }
111
+ if (stage === "failure") {
112
+ spinner.failPhase(PHASE_BUILD, "Build failed", event.elapsedMs, getFailureMessage(event));
113
+ logger.info(`[build] ✗ workflow ${workflowIndex}/${workflowCount} failed: ${getFailureMessage(event)}`);
114
+ return;
115
+ }
116
+ spinner.updatePhase(PHASE_BUILD, getStageLabel(stage));
117
+ }
118
+ function handleEvent(event) {
119
+ switch (event.phase) {
120
+ case "discovery-start":
121
+ spinner.startPhase(PHASE_SCAN, formatDiscoveryStartLabel(event.filesTotal));
122
+ return;
123
+ case "discovery-scan":
124
+ spinner.updatePhase(PHASE_SCAN, formatDiscoveryScanLabel(event.filesScanned, event.filesTotal));
125
+ return;
126
+ case "discovery-complete":
127
+ spinner.completePhase(PHASE_SCAN, formatDiscoveryCompleteLabel(event.workflowCount, event.agentCount, event.filesScanned), event.elapsedMs);
128
+ return;
129
+ case "cache-stats":
130
+ logger.info(`[build] cache stats: cacheHits=${event.cacheHits}, cacheMisses=${event.cacheMisses}, invalidated=${event.invalidated}`);
131
+ return;
132
+ case "build-start":
133
+ buildStartTime = Date.now();
134
+ spinner.startPhase(PHASE_BUILD, formatBuildStartLabel(workflowName, event.workflowCount, event.agentCount));
135
+ return;
136
+ case "workflow-stage":
137
+ handleWorkflowStage(event);
138
+ return;
139
+ case "build-complete":
140
+ if (buildStartTime !== void 0 && event.failedCount === 0) spinner.completePhase(PHASE_BUILD, formatBuildCompleteLabel(event), event.elapsedMs);
141
+ return;
142
+ case "duplicate-id-conflict":
143
+ logger.info(`[build] duplicate workflow id conflict: ${event.workflowId} (${event.files.join(", ")})`);
144
+ return;
145
+ case "output-start":
146
+ spinner.startPhase(PHASE_OUTPUT, event.artifactCount === 1 ? "Writing 1 artifact to disk..." : `Writing ${event.artifactCount} artifact(s) to disk...`);
147
+ return;
148
+ case "output-complete":
149
+ spinner.completePhase(PHASE_OUTPUT, formatOutputCompleteLabel(event), event.elapsedMs);
150
+ return;
151
+ case "metadata-start":
152
+ spinner.startPhase(PHASE_METADATA, formatMetadataStartLabel(event.fileCount));
153
+ return;
154
+ case "metadata-scan":
155
+ spinner.updatePhase(PHASE_METADATA, `Generating metadata... (${event.filesProcessed}/${event.filesTotal})`);
156
+ return;
157
+ case "metadata-cache-stats":
158
+ spinner.updatePhase(PHASE_METADATA, "Merging metadata...");
159
+ logger.info(`[build] metadata cache stats: cacheHits=${event.cacheHits}, cacheMisses=${event.cacheMisses}, invalidated=${event.invalidated}`);
160
+ return;
161
+ case "metadata-complete":
162
+ spinner.completePhase(PHASE_METADATA, `Generated metadata for ${event.fileCount} file(s)`, event.elapsedMs);
163
+ return;
164
+ case "metadata-output-complete":
165
+ logger.info(`[build] metadata output: written=${event.writtenCount}, cleaned=${event.cleanedCount} (${formatProgressDuration(event.elapsedMs)})`);
166
+ return;
167
+ case "convention-errors":
168
+ spinner.failPhase(PHASE_METADATA, `${event.errorCount} file convention error(s)`, 0);
169
+ return;
170
+ case "complete": return;
171
+ }
172
+ }
173
+ function stop() {
174
+ if (spinner.isRunning()) logger.info(`[build] stopped (phase: "${spinner.currentLabel()}")`);
175
+ spinner.stop();
176
+ }
177
+ return {
178
+ handleEvent,
179
+ stop
180
+ };
181
+ }
182
+ //#endregion
183
+ export { createBuildProgress as t };
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { t as TaskBuildManifestSchema } from "./schemas-CDib1RhE.mjs";
4
+ import "./task-B2sZMaZu.mjs";
5
+ import { n as bundleWorkflowTarget } from "./workflow-bundler-BPiqVscj-X1PFFAuP.mjs";
6
+ import { t as buildTriggerArtifacts } from "./trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs";
7
+ import { performance } from "node:perf_hooks";
8
+ //#region ../../packages/workflow-builder/dist/build-tasks-CdihpudT.mjs
9
+ async function buildTaskArtifact(options) {
10
+ const { discoveredWorkflow, taskMetadata, projectRoot } = options;
11
+ const totalStartedAt = performance.now();
12
+ const bundle = await bundleWorkflowTarget({
13
+ filePath: discoveredWorkflow.resolvedFilePath,
14
+ localExportName: discoveredWorkflow.localExportName,
15
+ projectRoot,
16
+ sourceMap: options.sourceMaps
17
+ });
18
+ const bundleMs = performance.now() - totalStartedAt - taskMetadata.timing.importMs;
19
+ const manifestData = TaskBuildManifestSchema.parse(taskMetadata.manifest);
20
+ const triggerStartedAt = performance.now();
21
+ const triggerResult = await buildTriggerArtifacts(taskMetadata.triggers, manifestData.id, manifestData.name, projectRoot, {
22
+ workflowExportName: discoveredWorkflow.localExportName,
23
+ workflowFilePath: discoveredWorkflow.resolvedFilePath
24
+ });
25
+ const triggerMs = performance.now() - triggerStartedAt;
26
+ return {
27
+ artifact: {
28
+ task: {
29
+ bindingKey: discoveredWorkflow.bindingKey,
30
+ exportFilePath: discoveredWorkflow.exportFilePath,
31
+ resolvedFilePath: discoveredWorkflow.resolvedFilePath,
32
+ exportName: discoveredWorkflow.exportName,
33
+ localExportName: discoveredWorkflow.localExportName,
34
+ taskId: manifestData.id,
35
+ taskName: manifestData.name
36
+ },
37
+ manifest: manifestData,
38
+ bundle: {
39
+ code: bundle.code,
40
+ sourceMap: bundle.sourceMap,
41
+ localDependencies: bundle.localDependencies,
42
+ externalImports: bundle.externalImports,
43
+ size: bundle.size
44
+ },
45
+ triggers: triggerResult.artifacts,
46
+ timing: {
47
+ importMs: taskMetadata.timing.importMs,
48
+ manifestMs: taskMetadata.timing.manifestMs,
49
+ bundleMs,
50
+ triggerMs,
51
+ totalMs: performance.now() - totalStartedAt
52
+ }
53
+ },
54
+ triggerFailures: triggerResult.failures
55
+ };
56
+ }
57
+ async function buildTaskArtifacts(options) {
58
+ const taskArtifacts = [];
59
+ const failures = [];
60
+ for (const entry of options.entries) try {
61
+ const result = await buildTaskArtifact({
62
+ discoveredWorkflow: entry.discoveredWorkflow,
63
+ taskMetadata: entry.taskMetadata,
64
+ projectRoot: options.projectRoot,
65
+ sourceMaps: options.sourceMaps
66
+ });
67
+ taskArtifacts.push(result.artifact);
68
+ failures.push(...result.triggerFailures);
69
+ } catch (error) {
70
+ failures.push({
71
+ kind: "task",
72
+ task: {
73
+ bindingKey: entry.discoveredWorkflow.bindingKey,
74
+ exportFilePath: entry.discoveredWorkflow.exportFilePath,
75
+ resolvedFilePath: entry.discoveredWorkflow.resolvedFilePath,
76
+ exportName: entry.discoveredWorkflow.exportName,
77
+ localExportName: entry.discoveredWorkflow.localExportName,
78
+ taskId: entry.discoveredWorkflow.exportName,
79
+ taskName: entry.discoveredWorkflow.exportName
80
+ },
81
+ phase: "bundle",
82
+ error: `Task bundle failed: ${error instanceof Error ? error.message : String(error)}`
83
+ });
84
+ }
85
+ return {
86
+ taskArtifacts,
87
+ failures
88
+ };
89
+ }
90
+ //#endregion
91
+ export { buildTaskArtifacts };
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { _ as deduplicateCredentialRequirementEntries } from "./schedule-BXx3uXwr.mjs";
4
+ import { i as WORKFLOW_MANIFEST_GENERATOR, s as WorkflowManifestSchema } from "./_manifest-JSRE3H8k.mjs";
5
+ import { a as MANIFEST_FILE_NAME, i as FLOW_FILE_NAME, r as BUNDLE_FILE_NAME, s as SOURCE_MAP_FILE_NAME, t as BUILD_DIR_NAME } from "./layout-CbMtQ2tm.mjs";
6
+ import { t as runWithConcurrency } from "./concurrency-gXn9Rw8x-DNl2YtrS.mjs";
7
+ import { n as WorkflowLoaderProtocolError, r as WorkflowMetadataLoadError, s as createLoaderProtocolFailure } from "./import-module-CV84H5fZ-B_CBCmb4.mjs";
8
+ import { r as toRelativeFilePath } from "./normalize-path-CojS-CgQ-DLCOvnD1.mjs";
9
+ import { n as bundleWorkflowTarget } from "./workflow-bundler-BPiqVscj-X1PFFAuP.mjs";
10
+ import { t as buildTriggerArtifacts } from "./trigger-artifacts-DQPbQNqC-B4yeeFBY.mjs";
11
+ import { realpathSync } from "node:fs";
12
+ import { readFile } from "node:fs/promises";
13
+ import * as path$1 from "node:path";
14
+ import { createHash } from "node:crypto";
15
+ import { performance } from "node:perf_hooks";
16
+ //#region ../../packages/workflow-builder/dist/build-workflows-CfxBnIWh.mjs
17
+ /**
18
+ * Resolves and categorizes all dependencies for a workflow manifest.
19
+ * - Local files: relative paths with SHA256 content hashes
20
+ * - npm packages: package name -> declared version
21
+ * - Workspace packages: @keystroke/* -> version specifier
22
+ * - Builtins: node:* specifiers
23
+ */
24
+ async function resolveDependencies(options) {
25
+ const { projectRoot, localDependencies, externalImports } = options;
26
+ const localFiles = {};
27
+ await Promise.all(localDependencies.map(async (absPath) => {
28
+ const relPath = path$1.relative(projectRoot, absPath);
29
+ try {
30
+ const content = await readFile(absPath);
31
+ localFiles[relPath] = createHash("sha256").update(content).digest("hex");
32
+ } catch {
33
+ localFiles[relPath] = "unknown";
34
+ }
35
+ }));
36
+ const builtins = [];
37
+ const packageSpecifiers = [];
38
+ for (const specifier of externalImports) if (specifier.startsWith("node:")) builtins.push(specifier);
39
+ else packageSpecifiers.push(specifier);
40
+ const packageVersions = options.packageVersionCache ?? await readPackageVersions(projectRoot);
41
+ const packages = {};
42
+ const workspacePackages = {};
43
+ for (const specifier of packageSpecifiers) {
44
+ const packageName = extractPackageName(specifier);
45
+ const version = packageVersions.get(packageName);
46
+ if (specifier.startsWith("@keystroke/")) workspacePackages[packageName] = version ?? "workspace:*";
47
+ else packages[packageName] = version ?? "unknown";
48
+ }
49
+ return {
50
+ localFiles: sortRecord(localFiles),
51
+ packages: sortRecord(packages),
52
+ workspacePackages: sortRecord(workspacePackages),
53
+ builtins: builtins.sort()
54
+ };
55
+ }
56
+ /**
57
+ * Extracts the npm package name from a module specifier.
58
+ * Handles scoped packages: `@scope/pkg/subpath` -> `@scope/pkg`
59
+ * Handles regular packages: `lodash/fp` -> `lodash`
60
+ */
61
+ function extractPackageName(specifier) {
62
+ if (specifier.startsWith("@")) {
63
+ const [scope, name] = specifier.split("/");
64
+ if (scope && name) return `${scope}/${name}`;
65
+ return specifier;
66
+ }
67
+ const [name] = specifier.split("/");
68
+ return name ?? specifier;
69
+ }
70
+ /**
71
+ * Reads package.json files starting from projectRoot and walking up to find
72
+ * all declared dependency versions. Merges dependencies and devDependencies.
73
+ */
74
+ async function readPackageVersions(projectRoot) {
75
+ const versions = /* @__PURE__ */ new Map();
76
+ let currentDir = path$1.resolve(projectRoot);
77
+ while (true) {
78
+ const candidate = path$1.join(currentDir, "package.json");
79
+ try {
80
+ const content = await readFile(candidate, "utf8");
81
+ const pkg = JSON.parse(content);
82
+ if (pkg.dependencies) {
83
+ for (const [name, version] of Object.entries(pkg.dependencies)) if (!versions.has(name)) versions.set(name, version);
84
+ }
85
+ if (pkg.devDependencies) {
86
+ for (const [name, version] of Object.entries(pkg.devDependencies)) if (!versions.has(name)) versions.set(name, version);
87
+ }
88
+ } catch {}
89
+ const parentDir = path$1.dirname(currentDir);
90
+ if (parentDir === currentDir) break;
91
+ currentDir = parentDir;
92
+ }
93
+ return versions;
94
+ }
95
+ function sortRecord(record) {
96
+ return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
97
+ }
98
+ function resolveBundleConcurrencyLimit() {
99
+ const raw = process.env.KEYSTROKE_WORKFLOW_BUNDLE_CONCURRENCY?.trim();
100
+ if (!raw) return Number.POSITIVE_INFINITY;
101
+ const parsed = Number.parseInt(raw, 10);
102
+ if (!Number.isFinite(parsed) || parsed < 1) return Number.POSITIVE_INFINITY;
103
+ return parsed;
104
+ }
105
+ function createWorkflowMetadataFailure(discoveredWorkflow, error) {
106
+ const message = error instanceof Error ? error.message : "No metadata loaded";
107
+ return error instanceof WorkflowMetadataLoadError ? {
108
+ kind: "workflow",
109
+ workflow: discoveredWorkflow,
110
+ phase: error.phase,
111
+ error: message
112
+ } : error instanceof WorkflowLoaderProtocolError ? createLoaderProtocolFailure(discoveredWorkflow, error.source, message, error.rawOutput) : {
113
+ kind: "workflow",
114
+ workflow: discoveredWorkflow,
115
+ phase: "import",
116
+ error: message
117
+ };
118
+ }
119
+ async function buildWorkflowArtifacts(options) {
120
+ const artifacts = [];
121
+ const failures = [];
122
+ const warnings = [];
123
+ const packageVersionCache = await readPackageVersions(options.projectRoot);
124
+ const workflowDelegateRegistry = buildWorkflowDelegateRegistry({
125
+ workflowsByKey: options.workflowsByKey,
126
+ metadataByKey: options.metadataByKey
127
+ });
128
+ const bundleJobs = options.entries.map((entry) => async () => {
129
+ const { discoveredWorkflow, metadata, workflowIndex } = entry;
130
+ const totalStartedAt = performance.now();
131
+ options.onProgressEvent?.({
132
+ phase: "workflow-stage",
133
+ stage: "start",
134
+ workflow: discoveredWorkflow,
135
+ workflowIndex,
136
+ workflowCount: options.workflowCount,
137
+ elapsedMs: 0
138
+ });
139
+ try {
140
+ const { manifest: loadedManifest, flowGraph, triggers: sameFileTriggers, credentialsByCallsiteFingerprint, credentialAttributionWarnings, timing } = metadata;
141
+ const nestingErrors = flowGraph.diagnostics?.filter((d) => d.startsWith("[nesting-error]"));
142
+ if (nestingErrors && nestingErrors.length > 0) {
143
+ for (const nestingError of nestingErrors) failures.push({
144
+ kind: "workflow",
145
+ workflow: discoveredWorkflow,
146
+ phase: "flow-graph",
147
+ error: nestingError.replace("[nesting-error] ", "")
148
+ });
149
+ return;
150
+ }
151
+ warnings.push(...credentialAttributionWarnings.map((warning) => `${discoveredWorkflow.resolvedFilePath}: [${warning.category}] Could not match declared credential requirements for "${warning.bindingName}" (${warning.credentialSetIds.join(", ")}) to a static callsite fingerprint.`));
152
+ const bundle = await bundleWorkflowTarget({
153
+ filePath: discoveredWorkflow.resolvedFilePath,
154
+ localExportName: discoveredWorkflow.localExportName,
155
+ projectRoot: options.projectRoot,
156
+ delegateRegistry: workflowDelegateRegistry,
157
+ sourceMap: options.sourceMaps
158
+ });
159
+ const bundleMs = performance.now() - totalStartedAt - timing.importMs;
160
+ const manifest = await finalizeWorkflowManifest({
161
+ coreManifest: loadedManifest,
162
+ flowGraph,
163
+ exportName: discoveredWorkflow.exportName,
164
+ workflowFilePath: discoveredWorkflow.resolvedFilePath,
165
+ bundle,
166
+ credentialsByCallsiteFingerprint,
167
+ projectRoot: options.projectRoot,
168
+ packageVersionCache
169
+ });
170
+ const triggerStartedAt = performance.now();
171
+ const triggerResult = await buildTriggerArtifacts(sameFileTriggers, manifest.id, manifest.name, options.projectRoot, {
172
+ workflowExportName: discoveredWorkflow.localExportName,
173
+ workflowFilePath: discoveredWorkflow.resolvedFilePath
174
+ });
175
+ failures.push(...triggerResult.failures);
176
+ const triggerMs = performance.now() - triggerStartedAt;
177
+ const artifact = {
178
+ workflow: {
179
+ ...discoveredWorkflow,
180
+ workflowId: manifest.id
181
+ },
182
+ manifest,
183
+ flowGraph,
184
+ bundle,
185
+ triggers: triggerResult.artifacts,
186
+ timing: {
187
+ importMs: timing.importMs,
188
+ manifestMs: timing.manifestMs,
189
+ flowGraphMs: timing.flowGraphMs,
190
+ bundleMs,
191
+ triggerMs,
192
+ totalMs: performance.now() - totalStartedAt
193
+ }
194
+ };
195
+ artifacts.push(artifact);
196
+ options.onProgressEvent?.({
197
+ phase: "workflow-stage",
198
+ stage: "success",
199
+ workflow: artifact.workflow,
200
+ workflowIndex,
201
+ workflowCount: options.workflowCount,
202
+ elapsedMs: artifact.timing.totalMs
203
+ });
204
+ } catch (error) {
205
+ const failure = {
206
+ kind: "workflow",
207
+ workflow: discoveredWorkflow,
208
+ phase: "bundle",
209
+ error: error instanceof Error ? error.message : String(error)
210
+ };
211
+ failures.push(failure);
212
+ options.onProgressEvent?.({
213
+ phase: "workflow-stage",
214
+ stage: "failure",
215
+ workflow: discoveredWorkflow,
216
+ workflowIndex,
217
+ workflowCount: options.workflowCount,
218
+ elapsedMs: 0,
219
+ failure
220
+ });
221
+ }
222
+ });
223
+ const bundleLimit = resolveBundleConcurrencyLimit();
224
+ const effectiveBundleConcurrency = Number.isFinite(bundleLimit) ? Math.min(bundleLimit, bundleJobs.length) : bundleJobs.length;
225
+ await runWithConcurrency(bundleJobs, Math.max(1, effectiveBundleConcurrency), (job) => job());
226
+ return {
227
+ artifacts,
228
+ failures,
229
+ warnings
230
+ };
231
+ }
232
+ /** @internal Exported for tests. */
233
+ function buildCredentialRequirements(flowGraph, credentialsByCallsiteFingerprint) {
234
+ const byStep = {};
235
+ const allCredentialSetIds = /* @__PURE__ */ new Set();
236
+ const toCredentialRequirementEntries = (entries) => entries.map((entry) => ({
237
+ credentialSetId: entry.resolvedCredentialSetId,
238
+ credentialKeys: entry.credentialKeys,
239
+ ...entry.optionalCredentialKeys && entry.optionalCredentialKeys.length > 0 ? { optionalCredentialKeys: entry.optionalCredentialKeys } : {},
240
+ ...entry.storedCredentialKeys && entry.storedCredentialKeys.length > 0 ? { storedCredentialKeys: entry.storedCredentialKeys } : {},
241
+ ...entry.optionalStoredCredentialKeys && entry.optionalStoredCredentialKeys.length > 0 ? { optionalStoredCredentialKeys: entry.optionalStoredCredentialKeys } : {},
242
+ ...entry.schemaFingerprint ? { schemaFingerprint: entry.schemaFingerprint } : {},
243
+ ...entry.proxy ? { proxy: entry.proxy } : {},
244
+ ...entry.needsRawSecret === true ? { needsRawSecret: true } : {},
245
+ ...entry.needsResolve === true ? { needsResolve: true } : {},
246
+ ...typeof entry.resolveCacheMs === "number" && entry.resolveCacheMs > 0 ? { resolveCacheMs: entry.resolveCacheMs } : {},
247
+ ...entry.onCredentialRevoked ? { onCredentialRevoked: entry.onCredentialRevoked } : {},
248
+ ...entry.requiredOAuthScopes?.length ? { requiredOAuthScopes: entry.requiredOAuthScopes } : {}
249
+ }));
250
+ for (const node of flowGraph.nodes) {
251
+ if (node.type !== "step" || node.data.kind !== "call") continue;
252
+ const operationScopes = "requiredOAuthScopes" in node.data && node.data.requiredOAuthScopes?.length ? node.data.requiredOAuthScopes : void 0;
253
+ const nodeEntries = node.data.credentialSets?.map((entry) => ({
254
+ credentialSetId: entry.resolvedId,
255
+ credentialKeys: entry.credentialKeys,
256
+ ...entry.optionalCredentialKeys && entry.optionalCredentialKeys.length > 0 ? { optionalCredentialKeys: entry.optionalCredentialKeys } : {},
257
+ ...entry.storedCredentialKeys && entry.storedCredentialKeys.length > 0 ? { storedCredentialKeys: entry.storedCredentialKeys } : {},
258
+ ...entry.optionalStoredCredentialKeys && entry.optionalStoredCredentialKeys.length > 0 ? { optionalStoredCredentialKeys: entry.optionalStoredCredentialKeys } : {},
259
+ ...entry.schemaFingerprint ? { schemaFingerprint: entry.schemaFingerprint } : {},
260
+ ...entry.proxy ? { proxy: entry.proxy } : {},
261
+ ...entry.needsRawSecret === true ? { needsRawSecret: true } : {},
262
+ ...entry.needsResolve === true ? { needsResolve: true } : {},
263
+ ...typeof entry.resolveCacheMs === "number" && entry.resolveCacheMs > 0 ? { resolveCacheMs: entry.resolveCacheMs } : {},
264
+ ...entry.onCredentialRevoked ? { onCredentialRevoked: entry.onCredentialRevoked } : {},
265
+ ...operationScopes ? { requiredOAuthScopes: [...operationScopes] } : {}
266
+ })) ?? [];
267
+ const callsiteEntries = node.data.callsiteFingerprint ? toCredentialRequirementEntries(credentialsByCallsiteFingerprint[node.data.callsiteFingerprint] ?? []) : [];
268
+ const entries = deduplicateCredentialRequirementEntries([...nodeEntries, ...callsiteEntries]);
269
+ if (entries.length === 0) continue;
270
+ byStep[node.id] = entries;
271
+ for (const entry of entries) allCredentialSetIds.add(entry.credentialSetId);
272
+ }
273
+ if (allCredentialSetIds.size === 0) return void 0;
274
+ return {
275
+ required: [...allCredentialSetIds].sort(),
276
+ byStep
277
+ };
278
+ }
279
+ function extractStepsFromFlowGraph(flowGraph) {
280
+ const steps = {};
281
+ for (const node of flowGraph.nodes) if (node.type === "step" && node.data.kind === "call") steps[node.id] = {
282
+ nodeId: node.id,
283
+ stepName: node.data.stepName,
284
+ label: node.label,
285
+ callKind: node.data.callKind,
286
+ ...node.data.exportName ? { exportName: node.data.exportName } : {},
287
+ ...node.data.stepId ? { stepId: node.data.stepId } : {},
288
+ ...node.data.source ? { source: node.data.source } : {},
289
+ ...node.data.astKind ? { astKind: node.data.astKind } : {},
290
+ ...node.data.importSource ? { importSource: node.data.importSource } : {},
291
+ ...node.data.outputBinding ? { outputBinding: node.data.outputBinding } : {},
292
+ ...node.data.scopeOverride ? { scopeOverride: node.data.scopeOverride } : {},
293
+ ...node.data.description ? { description: node.data.description } : {},
294
+ ...node.data.inputSchema ? { inputSchema: node.data.inputSchema } : {},
295
+ ...node.data.outputSchema ? { outputSchema: node.data.outputSchema } : {},
296
+ ..."credentialSets" in node.data && node.data.credentialSets ? { credentialSets: node.data.credentialSets } : {}
297
+ };
298
+ return steps;
299
+ }
300
+ async function finalizeWorkflowManifest(options) {
301
+ const credentials = buildCredentialRequirements(options.flowGraph, options.credentialsByCallsiteFingerprint);
302
+ const workflowSourceFilePath = toRelativeFilePath(options.projectRoot, options.workflowFilePath);
303
+ const dependencies = await resolveDependencies({
304
+ projectRoot: options.projectRoot,
305
+ localDependencies: options.bundle.localDependencies,
306
+ externalImports: options.bundle.externalImports,
307
+ packageVersionCache: options.packageVersionCache
308
+ });
309
+ return WorkflowManifestSchema.parse({
310
+ ...options.coreManifest,
311
+ exportName: options.exportName,
312
+ workflowSource: {
313
+ filePath: workflowSourceFilePath,
314
+ line: 1,
315
+ column: 1,
316
+ endLine: 1,
317
+ endColumn: 1,
318
+ synthetic: true
319
+ },
320
+ dependencies,
321
+ steps: extractStepsFromFlowGraph(options.flowGraph),
322
+ ...credentials ? { credentials } : {},
323
+ buildInfo: {
324
+ ...options.coreManifest.buildInfo,
325
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
326
+ builderVersion: "workflow-builder",
327
+ generatedBy: WORKFLOW_MANIFEST_GENERATOR,
328
+ nodeVersion: process.version,
329
+ platform: process.platform,
330
+ sourceChecksumAlgorithm: "sha256",
331
+ sourceChecksum: "0".repeat(64),
332
+ generatedFiles: [
333
+ MANIFEST_FILE_NAME,
334
+ FLOW_FILE_NAME,
335
+ `${BUILD_DIR_NAME}/${BUNDLE_FILE_NAME}`,
336
+ ...options.bundle.sourceMap ? [`${BUILD_DIR_NAME}/${SOURCE_MAP_FILE_NAME}`] : []
337
+ ]
338
+ }
339
+ });
340
+ }
341
+ function buildWorkflowDelegateRegistry(options) {
342
+ const registry = {};
343
+ for (const [bindingKey, { workflow }] of options.workflowsByKey) {
344
+ const metadata = options.metadataByKey.get(bindingKey);
345
+ if (!metadata?.ok) continue;
346
+ const entry = "agentMetadata" in metadata ? {
347
+ exportName: workflow.localExportName,
348
+ kind: "agent",
349
+ authoredId: typeof metadata.agentMetadata.manifest.authoredAgentId === "string" ? metadata.agentMetadata.manifest.authoredAgentId : typeof metadata.agentMetadata.manifest.id === "string" ? metadata.agentMetadata.manifest.id : workflow.exportName,
350
+ displayName: typeof metadata.agentMetadata.manifest.name === "string" ? metadata.agentMetadata.manifest.name : workflow.exportName
351
+ } : "taskMetadata" in metadata ? {
352
+ exportName: workflow.localExportName,
353
+ kind: "task",
354
+ authoredId: metadata.taskMetadata.manifest.id,
355
+ displayName: metadata.taskMetadata.manifest.name
356
+ } : {
357
+ exportName: workflow.localExportName,
358
+ kind: "workflow",
359
+ authoredId: metadata.metadata.manifest.id,
360
+ displayName: metadata.metadata.manifest.name
361
+ };
362
+ const resolvedFilePath = realpathSync.native(workflow.resolvedFilePath);
363
+ const existing = registry[resolvedFilePath] ?? [];
364
+ existing.push(entry);
365
+ registry[resolvedFilePath] = existing;
366
+ }
367
+ return registry;
368
+ }
369
+ //#endregion
370
+ export { buildWorkflowArtifacts, createWorkflowMetadataFailure };
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { C as CliExitError } from "./keystroke.mjs";
4
+ import { d as trackProject } from "./dist-CUK7yBM0.mjs";
5
+ import { t as requireWorkflowsDir } from "./resolve-project-DDJ29sCF.mjs";
6
+ import { a as runWorkflowBuild, i as renderBuildSummary, n as renderBuildFailure, r as renderBuildHeader } from "./workflow-build-DBQaBfnn.mjs";
7
+ import { t as createBuildProgress } from "./build-progress-DgYKb4hB.mjs";
8
+ import { t as withErrorBoundary } from "./error-boundary-VL-JLfIa.mjs";
9
+ //#region src/commands/workflows/build.handler.ts
10
+ async function handleWorkflowsBuild(options, _ctx) {
11
+ return withErrorBoundary("Build", async () => {
12
+ const workflowsDir = await requireWorkflowsDir(options.path);
13
+ trackProject(workflowsDir);
14
+ renderBuildHeader(options.name);
15
+ const progress = createBuildProgress(options.name ?? "workflow");
16
+ try {
17
+ const { result, outDir } = await runWorkflowBuild({
18
+ workflowsDir,
19
+ verbose: options.verbose,
20
+ name: options.name,
21
+ force: options.force,
22
+ targetFiles: options.target,
23
+ ...options.disableSourcemaps ? { sourceMaps: false } : {},
24
+ onProgressEvent: progress.handleEvent
25
+ });
26
+ renderBuildSummary(result, outDir);
27
+ } catch (error) {
28
+ renderBuildFailure(error);
29
+ throw new CliExitError("Build failed");
30
+ } finally {
31
+ progress.stop();
32
+ }
33
+ });
34
+ }
35
+ //#endregion
36
+ export { handleWorkflowsBuild };