@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,426 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { n as __exportAll } from "./chunk-CH6r78ws.mjs";
4
+ import { f as getTriggersDir, n as BUILD_OUTPUT_DIR_NAME, p as getWorkflowArtifactPaths, t as BUILD_DIR_NAME } from "./layout-CbMtQ2tm.mjs";
5
+ import { t as TriggerBuildManifestSchema } from "./trigger-manifest-CY7brZeg.mjs";
6
+ import { t as __exportAll$1 } from "./rolldown-runtime-twds-ZHy-BWWzu8VG.mjs";
7
+ import { s as sha256String } from "./metadata-layout-GUYIUo0i-_aG2zjue.mjs";
8
+ import { t as runWithConcurrency } from "./concurrency-gXn9Rw8x-DNl2YtrS.mjs";
9
+ import { access, mkdir, readdir, rm, stat, writeFile } from "node:fs/promises";
10
+ import path from "node:path";
11
+ import { createHash } from "node:crypto";
12
+ //#region ../../packages/workflow-builder/dist/writer-BG8poUm3.mjs
13
+ var writer_BG8poUm3_exports = /* @__PURE__ */ __exportAll({
14
+ a: () => getAgentArtifactPaths,
15
+ d: () => allOutputFilesExist,
16
+ f: () => hashAgentManifestForDisk,
17
+ i: () => createAgentOutputFiles,
18
+ l: () => getWorkflowArtifactPaths,
19
+ m: () => hashWorkflowManifestForDisk,
20
+ n: () => resolveOutputDir,
21
+ o: () => removeAgentArtifacts,
22
+ p: () => hashWorkflowFlowForDisk,
23
+ r: () => AGENT_ARTIFACT_DIR_PREFIX,
24
+ s: () => removeWorkflowArtifacts,
25
+ t: () => writer_exports,
26
+ u: () => BUILD_CACHE_FILE_NAME
27
+ });
28
+ function markBundleDiskBacked(bundle, descriptor) {
29
+ bundle.outputPath = descriptor.outputPath;
30
+ if (descriptor.sourceMapPath) bundle.sourceMapPath = descriptor.sourceMapPath;
31
+ }
32
+ function releaseBundleCode(bundle) {
33
+ bundle.code = "";
34
+ if ("sourceMap" in bundle) bundle.sourceMap = null;
35
+ bundle.released = true;
36
+ }
37
+ function markCallbackBundleDiskBacked(bundle, outputPath) {
38
+ bundle.outputPath = outputPath;
39
+ }
40
+ function releaseCallbackBundleCode(bundle) {
41
+ bundle.code = "";
42
+ bundle.released = true;
43
+ }
44
+ /** Exact bytes written for workflow `manifest.json` (see `writeWorkflowArtifact`). */
45
+ function serializeWorkflowManifestForDisk(manifest) {
46
+ return `${JSON.stringify(manifest, null, 2)}\n`;
47
+ }
48
+ /** Exact bytes written for workflow `flow.json`. */
49
+ function serializeWorkflowFlowForDisk(flowGraph) {
50
+ return `${JSON.stringify(flowGraph, null, 2)}\n`;
51
+ }
52
+ /** Exact bytes written for agent `manifest.json`. */
53
+ function serializeAgentManifestForDisk(manifest) {
54
+ return `${JSON.stringify(manifest, null, 2)}\n`;
55
+ }
56
+ function hashWorkflowManifestForDisk(manifest) {
57
+ return sha256String(serializeWorkflowManifestForDisk(manifest));
58
+ }
59
+ function hashWorkflowFlowForDisk(flowGraph) {
60
+ return sha256String(serializeWorkflowFlowForDisk(flowGraph));
61
+ }
62
+ function hashAgentManifestForDisk(manifest) {
63
+ return sha256String(serializeAgentManifestForDisk(manifest));
64
+ }
65
+ async function allOutputFilesExist(outputDir, outputFiles) {
66
+ return (await Promise.all(outputFiles.map((relativePath) => stat(path.join(outputDir, relativePath)).then(() => true, () => false)))).every(Boolean);
67
+ }
68
+ function workflowArtifactHashesMatch(artifact, cached) {
69
+ const manifestOk = hashWorkflowManifestForDisk(artifact.manifest) === cached.manifestHash;
70
+ const flowOk = hashWorkflowFlowForDisk(artifact.flowGraph) === cached.flowGraphHash;
71
+ const bundleOk = (artifact.bundle.hash ?? sha256String(artifact.bundle.code)) === cached.bundleHash;
72
+ const sourceMapOk = cached.sourceMapHash ? artifact.bundle.sourceMap !== null && (artifact.bundle.sourceMapHash ?? sha256String(artifact.bundle.sourceMap)) === cached.sourceMapHash : artifact.bundle.sourceMap === null;
73
+ return manifestOk && flowOk && bundleOk && sourceMapOk;
74
+ }
75
+ function agentArtifactHashesMatch(artifact, cached) {
76
+ const manifestOk = hashAgentManifestForDisk(artifact.manifest) === cached.manifestHash;
77
+ const bundleOk = (artifact.bundle.hash ?? sha256String(artifact.bundle.code)) === cached.bundleHash;
78
+ const sandboxPackageOk = artifact.sandboxPackage.hash === cached.sandboxPackageHash;
79
+ return manifestOk && bundleOk && sandboxPackageOk;
80
+ }
81
+ async function shouldSkipWorkflowArtifactWrite(outputDir, artifact, cached, force) {
82
+ if (force || !cached || artifact.triggers.length > 0) return false;
83
+ if (!workflowArtifactHashesMatch(artifact, cached)) return false;
84
+ return allOutputFilesExist(outputDir, cached.outputFiles);
85
+ }
86
+ async function shouldSkipAgentArtifactWrite(outputDir, artifact, cached, force) {
87
+ if (force || !cached) return false;
88
+ if (!agentArtifactHashesMatch(artifact, cached)) return false;
89
+ return allOutputFilesExist(outputDir, cached.outputFiles);
90
+ }
91
+ const BUILD_CACHE_FILE_NAME = "build-cache.json";
92
+ async function cleanupStaleArtifacts(outputDir, currentWorkflowIds, currentAgentIds, currentTaskIds = []) {
93
+ const currentIds = new Set(currentWorkflowIds);
94
+ const currentAgentDirNames = new Set(currentAgentIds.map((agentId) => getAgentArtifactDirName(agentId)));
95
+ const currentTaskIds_ = new Set(currentTaskIds);
96
+ const entries = await readdir(outputDir, { withFileTypes: true });
97
+ let cleanedCount = 0;
98
+ for (const entry of entries) {
99
+ if (!entry.isDirectory()) continue;
100
+ if (entry.name === "build-cache.json" || entry.name === "metadata" || currentIds.has(entry.name) || currentAgentDirNames.has(entry.name) || entry.name === "tasks") continue;
101
+ if (!await isWorkflowArtifactDirectory(outputDir, entry.name)) {
102
+ if (!await isAgentArtifactDirectory(outputDir, entry.name)) continue;
103
+ }
104
+ await rm(`${outputDir}/${entry.name}`, {
105
+ recursive: true,
106
+ force: true
107
+ });
108
+ cleanedCount += 1;
109
+ }
110
+ if (currentTaskIds.length > 0) {
111
+ const tasksDir = `${outputDir}/${TASK_OUTPUT_DIR_NAME}`;
112
+ try {
113
+ const taskEntries = await readdir(tasksDir, { withFileTypes: true });
114
+ for (const taskEntry of taskEntries) if (taskEntry.isDirectory() && !currentTaskIds_.has(taskEntry.name)) {
115
+ await rm(`${tasksDir}/${taskEntry.name}`, {
116
+ recursive: true,
117
+ force: true
118
+ });
119
+ cleanedCount += 1;
120
+ }
121
+ } catch {}
122
+ }
123
+ return cleanedCount;
124
+ }
125
+ async function isWorkflowArtifactDirectory(outputDir, entryName) {
126
+ const paths = getWorkflowArtifactPaths(outputDir, entryName);
127
+ try {
128
+ await Promise.all([
129
+ access(paths.manifestPath),
130
+ access(paths.flowPath),
131
+ access(paths.bundlePath)
132
+ ]);
133
+ return true;
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
138
+ async function isAgentArtifactDirectory(outputDir, entryName) {
139
+ if (!entryName.startsWith("agent_")) return false;
140
+ try {
141
+ await Promise.all([access(`${outputDir}/${entryName}/manifest.json`), access(`${outputDir}/${entryName}/build/${AGENT_SANDBOX_PACKAGE_FILE_NAME}`)]);
142
+ return true;
143
+ } catch {
144
+ return false;
145
+ }
146
+ }
147
+ async function removeWorkflowArtifacts(outputDir, workflowIds) {
148
+ let removedCount = 0;
149
+ for (const workflowId of new Set(workflowIds)) {
150
+ await rm(getWorkflowArtifactPaths(outputDir, workflowId).workflowDir, {
151
+ recursive: true,
152
+ force: true
153
+ });
154
+ removedCount += 1;
155
+ }
156
+ return removedCount;
157
+ }
158
+ async function removeAgentArtifacts(outputDir, agentIds) {
159
+ let removedCount = 0;
160
+ for (const agentId of new Set(agentIds)) {
161
+ await rm(`${outputDir}/${getAgentArtifactDirName(agentId)}`, {
162
+ recursive: true,
163
+ force: true
164
+ });
165
+ removedCount += 1;
166
+ }
167
+ return removedCount;
168
+ }
169
+ /** Limits parallel dist writes so we do not overwhelm the filesystem on large projects. */
170
+ const ARTIFACT_WRITE_CONCURRENCY = 8;
171
+ async function writeWorkflowArtifact(artifact, outputDir, options) {
172
+ const artifactPaths = getWorkflowArtifactPaths(outputDir, artifact.workflow.workflowId);
173
+ await mkdir(artifactPaths.buildDir, { recursive: true });
174
+ const manifestJson = `${JSON.stringify(artifact.manifest, null, 2)}\n`;
175
+ const flowJson = `${JSON.stringify(artifact.flowGraph, null, 2)}\n`;
176
+ const writes = [
177
+ writeFile(artifactPaths.manifestPath, manifestJson, "utf-8"),
178
+ writeFile(artifactPaths.flowPath, flowJson, "utf-8"),
179
+ writeFile(artifactPaths.bundlePath, artifact.bundle.code, "utf-8")
180
+ ];
181
+ if (artifact.bundle.sourceMap) writes.push(writeFile(artifactPaths.sourceMapPath, artifact.bundle.sourceMap, "utf-8"));
182
+ await Promise.all(writes);
183
+ markBundleDiskBacked(artifact.bundle, {
184
+ outputPath: artifactPaths.bundlePath,
185
+ size: artifact.bundle.size,
186
+ hash: artifact.bundle.hash,
187
+ ...artifact.bundle.sourceMap ? { sourceMapPath: artifactPaths.sourceMapPath } : {},
188
+ ...artifact.bundle.sourceMapHash ? { sourceMapHash: artifact.bundle.sourceMapHash } : {}
189
+ });
190
+ if (artifact.triggers.length > 0) await writeTriggerArtifacts(artifact.triggers, artifactPaths.buildDir, options);
191
+ if (options?.releaseBundleMemory) releaseBundleCode(artifact.bundle);
192
+ }
193
+ const AGENT_ARTIFACT_DIR_PREFIX = "agent_";
194
+ const AGENT_SANDBOX_PACKAGE_FILE_NAME = "sandbox-bundle.tar.gz";
195
+ function getAgentArtifactDirName(agentId) {
196
+ return `${AGENT_ARTIFACT_DIR_PREFIX}${agentId}_${createHash("sha256").update(agentId).digest("hex").slice(0, 16)}`;
197
+ }
198
+ function getAgentArtifactPaths(outputDir, agentId) {
199
+ const agentDir = path.join(outputDir, getAgentArtifactDirName(agentId));
200
+ const buildDir = path.join(agentDir, BUILD_DIR_NAME);
201
+ return {
202
+ agentDir,
203
+ buildDir,
204
+ manifestPath: path.join(agentDir, "manifest.json"),
205
+ sandboxPackagePath: path.join(buildDir, AGENT_SANDBOX_PACKAGE_FILE_NAME)
206
+ };
207
+ }
208
+ function createAgentOutputFiles(agentId) {
209
+ const agentDir = getAgentArtifactDirName(agentId);
210
+ return [path.join(agentDir, "manifest.json"), path.join(agentDir, BUILD_DIR_NAME, AGENT_SANDBOX_PACKAGE_FILE_NAME)].sort((left, right) => left.localeCompare(right));
211
+ }
212
+ const TASK_OUTPUT_DIR_NAME = "tasks";
213
+ const TASK_BUNDLE_FILE_NAME = "bundle.js";
214
+ const TASK_SOURCE_MAP_FILE_NAME = "bundle.js.map";
215
+ function getTaskArtifactPaths(outputDir, taskId) {
216
+ const taskDir = path.join(outputDir, TASK_OUTPUT_DIR_NAME, taskId);
217
+ return {
218
+ taskDir,
219
+ buildDir: path.join(taskDir, "build"),
220
+ manifestPath: path.join(taskDir, "manifest.json"),
221
+ bundlePath: path.join(taskDir, TASK_BUNDLE_FILE_NAME),
222
+ sourceMapPath: path.join(taskDir, TASK_SOURCE_MAP_FILE_NAME)
223
+ };
224
+ }
225
+ async function writeTaskArtifact(artifact, outputDir, options) {
226
+ const artifactPaths = getTaskArtifactPaths(outputDir, artifact.task.taskId);
227
+ await mkdir(artifactPaths.taskDir, { recursive: true });
228
+ const manifestJson = `${JSON.stringify(artifact.manifest, null, 2)}\n`;
229
+ const writes = [writeFile(artifactPaths.manifestPath, manifestJson, "utf-8"), writeFile(artifactPaths.bundlePath, artifact.bundle.code, "utf-8")];
230
+ if (artifact.bundle.sourceMap) writes.push(writeFile(artifactPaths.sourceMapPath, artifact.bundle.sourceMap, "utf-8"));
231
+ await Promise.all(writes);
232
+ markBundleDiskBacked(artifact.bundle, {
233
+ outputPath: artifactPaths.bundlePath,
234
+ size: artifact.bundle.size,
235
+ hash: artifact.bundle.hash,
236
+ ...artifact.bundle.sourceMap ? { sourceMapPath: artifactPaths.sourceMapPath } : {},
237
+ ...artifact.bundle.sourceMapHash ? { sourceMapHash: artifact.bundle.sourceMapHash } : {}
238
+ });
239
+ if (artifact.triggers.length > 0) await writeTriggerArtifacts(artifact.triggers, artifactPaths.buildDir, options);
240
+ if (options?.releaseBundleMemory) releaseBundleCode(artifact.bundle);
241
+ }
242
+ async function writeAgentArtifact(artifact, outputDir, options) {
243
+ const artifactPaths = getAgentArtifactPaths(outputDir, artifact.agent.agentId);
244
+ await mkdir(artifactPaths.buildDir, { recursive: true });
245
+ const manifestJson = `${JSON.stringify(artifact.manifest, null, 2)}\n`;
246
+ const writes = [writeFile(artifactPaths.manifestPath, manifestJson, "utf-8"), writeFile(artifactPaths.sandboxPackagePath, artifact.sandboxPackage.buffer)];
247
+ await Promise.all(writes);
248
+ markBundleDiskBacked(artifact.bundle, {
249
+ outputPath: artifactPaths.sandboxPackagePath,
250
+ size: artifact.bundle.size,
251
+ hash: artifact.bundle.hash
252
+ });
253
+ if (options?.releaseBundleMemory) releaseBundleCode(artifact.bundle);
254
+ }
255
+ async function writeBuildOutput(result, outputDir, options) {
256
+ validateArtifactsForWrite(result.artifacts);
257
+ await mkdir(outputDir, { recursive: true });
258
+ const canSkipWrites = options?.buildCache !== void 0 && options.skipUnchangedWrites !== false && options?.force !== true;
259
+ let skippedWriteCount = 0;
260
+ const resolvedKeys = options?.cacheResolvedBindingKeys;
261
+ await runWithConcurrency(result.artifacts, ARTIFACT_WRITE_CONCURRENCY, async (artifact) => {
262
+ if (canSkipWrites) {
263
+ if (resolvedKeys?.has(artifact.workflow.bindingKey) && artifact.triggers.length === 0) {
264
+ skippedWriteCount += 1;
265
+ return;
266
+ }
267
+ const cached = options?.buildCache?.bindings[artifact.workflow.bindingKey];
268
+ if (await shouldSkipWorkflowArtifactWrite(outputDir, artifact, cached, false)) {
269
+ skippedWriteCount += 1;
270
+ return;
271
+ }
272
+ }
273
+ await writeWorkflowArtifact(artifact, outputDir, options);
274
+ });
275
+ await runWithConcurrency(result.agentArtifacts, ARTIFACT_WRITE_CONCURRENCY, async (agentArtifact) => {
276
+ if (canSkipWrites) {
277
+ if (resolvedKeys?.has(agentArtifact.agent.bindingKey)) {
278
+ skippedWriteCount += 1;
279
+ return;
280
+ }
281
+ const cached = options?.buildCache?.agentBindings[agentArtifact.agent.bindingKey];
282
+ if (await shouldSkipAgentArtifactWrite(outputDir, agentArtifact, cached, false)) {
283
+ skippedWriteCount += 1;
284
+ return;
285
+ }
286
+ }
287
+ await writeAgentArtifact(agentArtifact, outputDir, options);
288
+ });
289
+ const taskArtifacts = result.taskArtifacts;
290
+ await runWithConcurrency(taskArtifacts, ARTIFACT_WRITE_CONCURRENCY, async (taskArtifact) => {
291
+ await writeTaskArtifact(taskArtifact, outputDir, options);
292
+ });
293
+ const cleanedCount = await cleanupStaleArtifacts(outputDir, result.artifacts.map((artifact) => artifact.workflow.workflowId), result.agentArtifacts.map((artifact) => artifact.agent.agentId), taskArtifacts.map((artifact) => artifact.task.taskId));
294
+ return {
295
+ writtenCount: result.artifacts.length + result.agentArtifacts.length + taskArtifacts.length,
296
+ cleanedCount,
297
+ outputDir,
298
+ artifacts: [...result.artifacts],
299
+ ...skippedWriteCount > 0 ? { skippedWriteCount } : {}
300
+ };
301
+ }
302
+ async function writeTargetedBuildOutput(result, outputDir, previousWorkflowIds, options) {
303
+ validateArtifactsForWrite(result.artifacts);
304
+ await mkdir(outputDir, { recursive: true });
305
+ const canSkipWrites = options?.buildCache !== void 0 && options.skipUnchangedWrites !== false && options?.force !== true;
306
+ let skippedWriteCount = 0;
307
+ const resolvedKeys = options?.cacheResolvedBindingKeys;
308
+ await runWithConcurrency(result.artifacts, ARTIFACT_WRITE_CONCURRENCY, async (artifact) => {
309
+ if (canSkipWrites) {
310
+ if (resolvedKeys?.has(artifact.workflow.bindingKey) && artifact.triggers.length === 0) {
311
+ skippedWriteCount += 1;
312
+ return;
313
+ }
314
+ const cached = options?.buildCache?.bindings[artifact.workflow.bindingKey];
315
+ if (await shouldSkipWorkflowArtifactWrite(outputDir, artifact, cached, false)) {
316
+ skippedWriteCount += 1;
317
+ return;
318
+ }
319
+ }
320
+ await writeWorkflowArtifact(artifact, outputDir, options);
321
+ });
322
+ await runWithConcurrency(result.agentArtifacts, ARTIFACT_WRITE_CONCURRENCY, async (agentArtifact) => {
323
+ if (canSkipWrites) {
324
+ if (resolvedKeys?.has(agentArtifact.agent.bindingKey)) {
325
+ skippedWriteCount += 1;
326
+ return;
327
+ }
328
+ const cached = options?.buildCache?.agentBindings[agentArtifact.agent.bindingKey];
329
+ if (await shouldSkipAgentArtifactWrite(outputDir, agentArtifact, cached, false)) {
330
+ skippedWriteCount += 1;
331
+ return;
332
+ }
333
+ }
334
+ await writeAgentArtifact(agentArtifact, outputDir, options);
335
+ });
336
+ const taskArtifacts = result.taskArtifacts;
337
+ await runWithConcurrency(taskArtifacts, ARTIFACT_WRITE_CONCURRENCY, async (taskArtifact) => {
338
+ await writeTaskArtifact(taskArtifact, outputDir, options);
339
+ });
340
+ const currentWorkflowIds = new Set(result.artifacts.map((artifact) => artifact.workflow.workflowId));
341
+ const cleanedCount = await removeWorkflowArtifacts(outputDir, previousWorkflowIds.filter((workflowId) => !currentWorkflowIds.has(workflowId)));
342
+ return {
343
+ writtenCount: result.artifacts.length + result.agentArtifacts.length + taskArtifacts.length,
344
+ cleanedCount,
345
+ outputDir,
346
+ artifacts: [...result.artifacts],
347
+ ...skippedWriteCount > 0 ? { skippedWriteCount } : {}
348
+ };
349
+ }
350
+ function toTriggerWriteArtifact(trigger, triggerDir) {
351
+ return {
352
+ triggerId: trigger.triggerId,
353
+ triggerDir,
354
+ manifestPath: path.join(triggerDir, "manifest.json"),
355
+ ...trigger.callbackBundle ? { callbackBundlePath: path.join(triggerDir, "callback-functions.js") } : {},
356
+ ...trigger.transformCallbackBundle ? { transformCallbackBundlePath: path.join(triggerDir, "transform.js") } : {}
357
+ };
358
+ }
359
+ async function writeTriggerArtifacts(triggers, buildDir, options) {
360
+ const triggersDir = getTriggersDir(buildDir);
361
+ try {
362
+ await rm(triggersDir, {
363
+ recursive: true,
364
+ force: true
365
+ });
366
+ } catch {}
367
+ const results = [];
368
+ for (const trigger of triggers) {
369
+ const triggerDir = path.join(triggersDir, trigger.triggerId);
370
+ await mkdir(triggerDir, { recursive: true });
371
+ const triggerManifest = TriggerBuildManifestSchema.parse({
372
+ id: trigger.triggerId,
373
+ type: trigger.triggerType,
374
+ ...trigger.triggerSource ? { triggerSource: trigger.triggerSource } : {},
375
+ enabled: trigger.enabled,
376
+ ...trigger.schedule ? { schedule: trigger.schedule } : {},
377
+ ...trigger.timezone ? { timezone: trigger.timezone } : {},
378
+ ...trigger.path ? { path: trigger.path } : {},
379
+ ...trigger.method ? { method: trigger.method } : {},
380
+ config: trigger.config ?? (trigger.staticPayload !== void 0 ? { payload: trigger.staticPayload } : {}),
381
+ ...trigger.requiredCredentials ? { requiredCredentials: trigger.requiredCredentials } : {}
382
+ });
383
+ if (trigger.callbackExports && trigger.callbackBundle) triggerManifest.functions = Object.fromEntries(Object.entries(trigger.callbackExports).map(([key, exportName]) => [key, {
384
+ js: "callback-functions.js",
385
+ export: exportName
386
+ }]));
387
+ if (trigger.transformCallbackExports && trigger.transformCallbackBundle) triggerManifest.attachmentFunctions = Object.fromEntries(Object.entries(trigger.transformCallbackExports).map(([key, exportName]) => [key, {
388
+ js: "transform.js",
389
+ export: exportName
390
+ }]));
391
+ await writeFile(path.join(triggerDir, "manifest.json"), `${JSON.stringify(triggerManifest, null, 2)}\n`, "utf-8");
392
+ if (trigger.callbackBundle) {
393
+ const callbackBundlePath = path.join(triggerDir, "callback-functions.js");
394
+ await writeFile(callbackBundlePath, trigger.callbackBundle.code, "utf-8");
395
+ markCallbackBundleDiskBacked(trigger.callbackBundle, callbackBundlePath);
396
+ if (options?.releaseBundleMemory) releaseCallbackBundleCode(trigger.callbackBundle);
397
+ }
398
+ if (trigger.transformCallbackBundle) {
399
+ const transformBundlePath = path.join(triggerDir, "transform.js");
400
+ await writeFile(transformBundlePath, trigger.transformCallbackBundle.code, "utf-8");
401
+ markCallbackBundleDiskBacked(trigger.transformCallbackBundle, transformBundlePath);
402
+ if (options?.releaseBundleMemory) releaseCallbackBundleCode(trigger.transformCallbackBundle);
403
+ }
404
+ results.push(toTriggerWriteArtifact(trigger, triggerDir));
405
+ }
406
+ return results;
407
+ }
408
+ function validateArtifactsForWrite(artifacts) {
409
+ const workflowIdPattern = /^[^./\\][^/\\]*$/;
410
+ const seenIds = /* @__PURE__ */ new Set();
411
+ for (const artifact of artifacts) {
412
+ const { workflowId } = artifact.workflow;
413
+ if (!workflowIdPattern.test(workflowId) || workflowId.includes("..")) throw new Error(`Workflow id "${workflowId}" is not filesystem-safe`);
414
+ if (seenIds.has(workflowId)) throw new Error(`Duplicate workflow id "${workflowId}" detected during output validation`);
415
+ seenIds.add(workflowId);
416
+ }
417
+ }
418
+ function resolveOutputDir(projectRoot, config) {
419
+ return config?.outDir ? path.resolve(projectRoot, config.outDir) : path.join(projectRoot, BUILD_OUTPUT_DIR_NAME);
420
+ }
421
+ var writer_exports = /* @__PURE__ */ __exportAll$1({
422
+ writeBuildOutput: () => writeBuildOutput,
423
+ writeTargetedBuildOutput: () => writeTargetedBuildOutput
424
+ });
425
+ //#endregion
426
+ export { getAgentArtifactPaths as a, hashWorkflowManifestForDisk as c, resolveOutputDir as d, writer_BG8poUm3_exports as f, createAgentOutputFiles as i, removeAgentArtifacts as l, BUILD_CACHE_FILE_NAME as n, hashAgentManifestForDisk as o, allOutputFilesExist as r, hashWorkflowFlowForDisk as s, AGENT_ARTIFACT_DIR_PREFIX as t, removeWorkflowArtifacts as u };
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@keystrokehq/cli",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "Command-line interface for creating, managing, and deploying Keystroke automations.",
6
+ "type": "module",
7
+ "main": "./dist/keystroke.mjs",
8
+ "types": "./dist/keystroke.d.mts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/keystroke.d.mts",
12
+ "default": "./dist/keystroke.mjs"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
16
+ "bin": {
17
+ "keystroke": "./bin/keystroke.mjs"
18
+ },
19
+ "files": [
20
+ "AGENTS-blurb.md",
21
+ "bin",
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE",
25
+ "THIRD_PARTY_NOTICES.md"
26
+ ],
27
+ "dependencies": {
28
+ "@clack/prompts": "^1.2.0",
29
+ "cli-table3": "^0.6.5",
30
+ "commander": "^14.0.3",
31
+ "dayjs": "^1.11.20",
32
+ "dotenv": "^17.4.2",
33
+ "ky": "^1.14.3",
34
+ "oxc-parser": "^0.128.0",
35
+ "rolldown": "1.0.0-rc.17",
36
+ "tsx": "^4.21.0",
37
+ "zod": "^4.3.6"
38
+ },
39
+ "devDependencies": {
40
+ "tsdown": "0.21.10",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^4.1.5",
43
+ "@keystroke/env-utils": "0.0.0",
44
+ "@keystroke/local-memory": "0.0.0",
45
+ "@keystroke/project-config": "0.0.0",
46
+ "@keystroke/shared-types": "0.0.0",
47
+ "@keystroke/utils": "0.0.0",
48
+ "@keystroke/workflow-core": "0.0.1",
49
+ "@keystroke/workflow-builder": "0.0.1",
50
+ "@keystroke/test-utils": "0.0.0",
51
+ "@keystroke/workflow-deploy": "0.0.0",
52
+ "@keystroke/skills": "0.0.1",
53
+ "@keystroke/typescript-config": "0.0.0",
54
+ "@keystroke/workflow-sdk": "0.0.0"
55
+ },
56
+ "keywords": [
57
+ "automation",
58
+ "cli",
59
+ "keystroke",
60
+ "workflow"
61
+ ],
62
+ "homepage": "https://github.com/keystrokehq/keystroke#readme",
63
+ "bugs": {
64
+ "url": "https://github.com/keystrokehq/keystroke/issues"
65
+ },
66
+ "repository": {
67
+ "type": "git",
68
+ "url": "https://github.com/keystrokehq/keystroke",
69
+ "directory": "apps/cli"
70
+ },
71
+ "license": "MIT",
72
+ "publishConfig": {
73
+ "access": "public",
74
+ "registry": "https://registry.npmjs.org/"
75
+ },
76
+ "scripts": {
77
+ "dev:cli": "pnpm run build && node bin/keystroke.mjs",
78
+ "typecheck": "tsgo --build",
79
+ "build": "tsdown",
80
+ "check:command-imports": "node scripts/check-command-imports.mjs",
81
+ "dev:install-pack": "pnpm run build && node scripts/install-dev-pack.mjs",
82
+ "smoke:pack": "pnpm run build && node scripts/smoke-pack.mjs",
83
+ "lint": "biome check --write .",
84
+ "test:unit": "vitest run --passWithNoTests --project unit",
85
+ "test:int": "vitest run --passWithNoTests --project int"
86
+ }
87
+ }