@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,18 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { z } from "zod";
4
+ //#region ../../packages/shared-types/src/credentials/models/schema.ts
5
+ const CredentialScopeValues = [
6
+ "organization",
7
+ "user",
8
+ "project"
9
+ ];
10
+ const CredentialScopeSchema = z.enum(CredentialScopeValues);
11
+ const ConnectionStatusSchema = z.enum([
12
+ "connected",
13
+ "broken",
14
+ "needs_reconnect",
15
+ "disconnected"
16
+ ]);
17
+ //#endregion
18
+ export { CredentialScopeSchema as n, CredentialScopeValues as r, ConnectionStatusSchema as t };
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+
3
+ //#region src/lib/schema-display.ts
4
+ /**
5
+ * Returns true when the schema is the fallback "unknown" sentinel emitted
6
+ * by zodSchemaToJsonSchema when a schema cannot be converted.
7
+ */
8
+ function isUnknownSchema(schema) {
9
+ return schema != null && schema.type === "unknown";
10
+ }
11
+ /**
12
+ * Generates a minimal placeholder JSON object for a given JSON Schema.
13
+ * Walks `properties` recursively to produce sensible default values so the
14
+ * user has a copy-pasteable `--input` example.
15
+ *
16
+ * Examples:
17
+ * { type: "number" } => 0
18
+ * { type: "string" } => ""
19
+ * { type: "boolean" } => false
20
+ * { type: "array" } => []
21
+ * { type: "object", properties: { x: { type: "number" } } } => { x: 0 }
22
+ * { enum: ["a", "b"] } => "a"
23
+ */
24
+ function generateExampleJson(schema) {
25
+ if (schema == null || typeof schema !== "object") return null;
26
+ return generateValue(schema);
27
+ }
28
+ function generateValue(schema) {
29
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
30
+ switch (Array.isArray(schema.type) ? schema.type[0] : schema.type) {
31
+ case "object": {
32
+ if (!schema.properties) return {};
33
+ const result = {};
34
+ for (const [key, propSchema] of Object.entries(schema.properties)) result[key] = generateValue(propSchema);
35
+ return result;
36
+ }
37
+ case "array": return [];
38
+ case "string": return "";
39
+ case "number":
40
+ case "integer": return 0;
41
+ case "boolean": return false;
42
+ case "null": return null;
43
+ default: return null;
44
+ }
45
+ }
46
+ /**
47
+ * Validates input against a JSON Schema by checking required fields.
48
+ * This is a lightweight structural check that works without `z.fromJSONSchema`.
49
+ * Only checks top-level required fields — sufficient for the "did you forget
50
+ * to provide input?" use case.
51
+ */
52
+ function validateRequiredFields(input, schema) {
53
+ if (schema == null || typeof schema !== "object") return {
54
+ valid: true,
55
+ missingRequired: []
56
+ };
57
+ const missingRequired = (Array.isArray(schema.required) ? schema.required : []).filter((field) => !(field in input));
58
+ return {
59
+ valid: missingRequired.length === 0,
60
+ missingRequired
61
+ };
62
+ }
63
+ /**
64
+ * Returns a short human-readable type hint from a JSON Schema field definition.
65
+ * e.g. { type: "number" } → "number"
66
+ * { type: "string", enum: ["a","b"] } → "string: a | b"
67
+ * { type: ["string", "null"] } → "string | null"
68
+ * { $ref: "..." } → "object"
69
+ */
70
+ function resolveTypeHint(fieldSchema) {
71
+ if (!fieldSchema) return "any";
72
+ if (Array.isArray(fieldSchema.enum) && fieldSchema.enum.length > 0) return `${typeof fieldSchema.type === "string" ? `${fieldSchema.type}: ` : ""}${fieldSchema.enum.map(String).join(" | ")}`;
73
+ if (Array.isArray(fieldSchema.type)) return fieldSchema.type.join(" | ");
74
+ if (typeof fieldSchema.type === "string" && fieldSchema.type !== "unknown") return fieldSchema.type;
75
+ if (fieldSchema.$ref) return "object";
76
+ return "any";
77
+ }
78
+ /**
79
+ * Formats a missing-required-fields error into a descriptive CLI message.
80
+ */
81
+ function formatMissingInputError(workflowName, missingFields, inputSchema) {
82
+ const lines = [];
83
+ lines.push(`Missing required input for workflow "${workflowName}"\n`);
84
+ if (inputSchema == null || typeof inputSchema !== "object") {
85
+ lines.push(" (input schema unavailable)\n");
86
+ lines.push(` $ keystroke workflows try-deploy "${workflowName}" --input '{}'`);
87
+ return lines.join("\n");
88
+ }
89
+ const properties = inputSchema.properties && typeof inputSchema.properties === "object" ? inputSchema.properties : {};
90
+ for (const field of missingFields) {
91
+ const fieldSchema = properties[field];
92
+ const typeHint = resolveTypeHint(fieldSchema);
93
+ lines.push(` ${field} (${typeHint}): Required`);
94
+ }
95
+ lines.push("");
96
+ const exampleValue = generateExampleJson(inputSchema);
97
+ const exampleJson = JSON.stringify(exampleValue);
98
+ lines.push("Expected input:");
99
+ lines.push(` $ keystroke workflows try-deploy "${workflowName}" --input '${exampleJson}'`);
100
+ return lines.join("\n");
101
+ }
102
+ /**
103
+ * Formats validation issues into a descriptive CLI message.
104
+ *
105
+ * Example output:
106
+ *
107
+ * Invalid input for workflow "Addition"
108
+ *
109
+ * num: Required
110
+ * num2: Required
111
+ *
112
+ * Expected input:
113
+ * $ keystroke workflows try-deploy "Addition" --input '{"num":0,"num2":0}'
114
+ */
115
+ function formatValidationError(workflowName, issues, inputSchema) {
116
+ const lines = [];
117
+ lines.push(`Invalid input for workflow "${workflowName}"\n`);
118
+ for (const issue of issues) {
119
+ const fieldPath = issue.path.length === 0 || issue.path.length === 1 && issue.path[0] === "" ? "(root)" : issue.path.join(".");
120
+ lines.push(` ${fieldPath}: ${issue.message}`);
121
+ }
122
+ lines.push("");
123
+ const exampleValue = inputSchema != null && typeof inputSchema === "object" ? generateExampleJson(inputSchema) : null;
124
+ const exampleJson = JSON.stringify(exampleValue);
125
+ lines.push(`Expected input:`);
126
+ lines.push(` $ keystroke workflows try-deploy "${workflowName}" --input '${exampleJson}'`);
127
+ return lines.join("\n");
128
+ }
129
+ //#endregion
130
+ export { validateRequiredFields as a, resolveTypeHint as i, formatValidationError as n, isUnknownSchema as r, formatMissingInputError as t };
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { A as idNoSpacesString, C as CredentialSetManifestSchema, I as trimmedNonEmptyString, L as trimmedNonEmptyStringUnbounded, N as optionalDescriptionString, O as createStructuralSchema, V as SHA256HashSchema, f as TriggerTypeSchema, j as jsonSchemaObject, k as descriptionString, s as ExecutionIdentityPolicySchema, t as DurationSchema } from "./schedule-BXx3uXwr.mjs";
4
+ import { z } from "zod";
5
+ //#region ../../packages/workflow-core/src/trigger/schemas.ts
6
+ const credentialSetInstanceSchema = createStructuralSchema([
7
+ "id",
8
+ "auth",
9
+ "needsResolve"
10
+ ], "a CredentialSet instance");
11
+ const TriggerModeDefaultSchema = z.enum(["managed", "subscribable"]);
12
+ const TriggerCallbackPresenceSchema = z.object({
13
+ filter: z.boolean(),
14
+ idempotencyKey: z.boolean(),
15
+ poll: z.boolean().optional(),
16
+ transformAllowed: z.boolean(),
17
+ verify: z.boolean().optional()
18
+ });
19
+ const TriggerRuntimeDescriptorSchema = z.object({ callbacks: TriggerCallbackPresenceSchema });
20
+ const TriggerManifestSchema = z.object({
21
+ manifestVersion: z.literal(1),
22
+ type: z.literal("trigger"),
23
+ triggerType: TriggerTypeSchema,
24
+ name: trimmedNonEmptyString("Trigger name"),
25
+ description: descriptionString("Trigger description"),
26
+ enabled: z.boolean(),
27
+ modeDefault: TriggerModeDefaultSchema,
28
+ executionIdentityPolicy: ExecutionIdentityPolicySchema.optional(),
29
+ credentialSets: z.array(CredentialSetManifestSchema).optional(),
30
+ runtime: TriggerRuntimeDescriptorSchema
31
+ });
32
+ const triggerBaseConfigSchema = z.object({
33
+ credentialSets: z.array(credentialSetInstanceSchema).optional(),
34
+ description: descriptionString("Trigger description"),
35
+ enabled: z.boolean().default(true),
36
+ executionIdentityPolicy: ExecutionIdentityPolicySchema.optional(),
37
+ modeDefault: TriggerModeDefaultSchema.default("managed"),
38
+ name: trimmedNonEmptyString("Trigger name")
39
+ });
40
+ //#endregion
41
+ //#region ../../packages/workflow-core/src/task/schemas.ts
42
+ const agentInstanceSchema = createStructuralSchema([
43
+ "id",
44
+ "name",
45
+ "systemPrompt",
46
+ "model",
47
+ "input",
48
+ "output",
49
+ "workflowSafeReference"
50
+ ], "an Agent instance");
51
+ const triggerInstanceSchema = createStructuralSchema([
52
+ "isTrigger",
53
+ "name",
54
+ "description",
55
+ "enabled"
56
+ ], "a trigger instance (use cronTrigger(), pollingTrigger(), or webhookTrigger())");
57
+ const taskLifecycleSchema = z.object({
58
+ maxExecutions: z.number().int().positive().optional(),
59
+ expiresAt: z.union([z.date(), z.string().datetime()]).optional(),
60
+ expiresAfter: DurationSchema.optional()
61
+ }).strict();
62
+ z.object({
63
+ id: idNoSpacesString("Task ID"),
64
+ name: trimmedNonEmptyString("Task name"),
65
+ description: optionalDescriptionString("Task description"),
66
+ agent: agentInstanceSchema,
67
+ prompt: trimmedNonEmptyStringUnbounded("Task prompt"),
68
+ triggers: z.array(triggerInstanceSchema).min(1, { message: "At least one trigger is required" }),
69
+ lifecycle: taskLifecycleSchema.optional(),
70
+ tags: z.array(z.string()).optional()
71
+ }).strict();
72
+ const WorkflowSafeAgentReferenceSchema = z.object({
73
+ kind: z.literal("agent"),
74
+ authoredAgentId: z.string(),
75
+ displayName: z.string(),
76
+ runtimeKind: z.enum(["declarative", "runnable"]),
77
+ inputSchema: jsonSchemaObject.optional(),
78
+ outputSchema: jsonSchemaObject.optional(),
79
+ authoredExport: z.object({
80
+ exportName: z.string().optional(),
81
+ filePath: z.string().optional()
82
+ }).optional(),
83
+ metadata: jsonSchemaObject.optional()
84
+ }).strict();
85
+ const TaskBuildInfoStubSchema = z.object({
86
+ hash: SHA256HashSchema.optional(),
87
+ size: z.number().optional(),
88
+ metadata: jsonSchemaObject.optional()
89
+ }).strict();
90
+ /**
91
+ * Extended trigger manifest schema for tasks.
92
+ * Preserves runtime fields (schedule, timezone, path, method) that the base
93
+ * TriggerManifestSchema strips. Tasks need these for trigger evaluation at runtime.
94
+ */
95
+ const TaskTriggerManifestSchema = TriggerManifestSchema.extend({
96
+ runtime: TriggerRuntimeDescriptorSchema.extend({
97
+ schedule: z.string().optional(),
98
+ timezone: z.string().optional(),
99
+ path: z.string().optional(),
100
+ method: z.string().optional(),
101
+ input: z.unknown().optional(),
102
+ payloadMode: z.string().optional()
103
+ }),
104
+ /** Static payload for cron triggers */
105
+ payload: z.unknown().optional()
106
+ });
107
+ const TaskBuildManifestSchema = z.object({
108
+ manifestVersion: z.literal(1),
109
+ type: z.literal("task"),
110
+ id: z.string().min(1),
111
+ name: z.string().min(1),
112
+ description: z.string().optional(),
113
+ agentRef: WorkflowSafeAgentReferenceSchema,
114
+ prompt: z.string().min(1),
115
+ triggers: z.array(TaskTriggerManifestSchema),
116
+ lifecycle: z.object({
117
+ maxExecutions: z.number().int().positive().optional(),
118
+ expiresAt: z.string().optional(),
119
+ expiresAfter: z.string().optional()
120
+ }).strict().optional(),
121
+ tags: z.array(z.string()).optional(),
122
+ buildInfo: TaskBuildInfoStubSchema
123
+ }).strict();
124
+ //#endregion
125
+ export { TriggerRuntimeDescriptorSchema as n, triggerBaseConfigSchema as r, TaskBuildManifestSchema as t };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { C as CliExitError, t as ui } from "./keystroke.mjs";
4
+ import { i as writeJson, r as isJsonMode } from "./output-DM4b7KgY.mjs";
5
+ import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-Kx_H7UTd.mjs";
6
+ import path from "node:path";
7
+ //#region src/commands/skills/skills-sync.handler.ts
8
+ async function handleSkillsSync(options, _ctx) {
9
+ const result = await syncKeystrokeAgentSkills(path.resolve(options.path ?? process.cwd()));
10
+ if (isJsonMode(options)) {
11
+ if (result.ok) writeJson({
12
+ ok: true,
13
+ copied: result.copied
14
+ });
15
+ else if (result.reason === "not_installed") writeJson({
16
+ ok: false,
17
+ reason: "not_installed"
18
+ });
19
+ else writeJson({
20
+ ok: false,
21
+ reason: "no_skills_found",
22
+ packageRoot: result.packageRoot
23
+ });
24
+ return;
25
+ }
26
+ if (result.ok) {
27
+ ui.success(`Synced ${result.copied.length} skill(s) to .cursor/skills and .claude/skills: ${result.copied.join(", ")}`);
28
+ return;
29
+ }
30
+ if (result.reason === "not_installed") throw new CliExitError("Could not resolve @keystroke/skills. Add it to devDependencies, run install, then run `keystroke skills sync`.", { exitCode: 1 });
31
+ ui.warn(`@keystroke/skills is installed at ${result.packageRoot} but no skill directories with SKILL.md were found.`);
32
+ }
33
+ //#endregion
34
+ export { handleSkillsSync };
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-DM4b7KgY.mjs";
4
+ import { t as createTypedCommand } from "./commander-DfTVqQ-3.mjs";
5
+ import { z } from "zod";
6
+ //#region src/commands/skills/skills.command.ts
7
+ const SkillsCommandOptionsSchema = JsonOptionSchema.extend({ path: z.string().optional().describe("Project root (default: current directory)") });
8
+ const SKILLS_OPTIONS_CONFIG = {
9
+ ...JSON_OPTION_CONFIG,
10
+ path: {
11
+ flag: "--path <dir>",
12
+ description: "Project root (directory containing package.json; default: cwd)"
13
+ }
14
+ };
15
+ function createSkillsCommand() {
16
+ const cmd = createTypedCommand({
17
+ name: "skills",
18
+ description: "Sync Keystroke agent skills (SKILL.md) from @keystroke/skills",
19
+ schema: SkillsCommandOptionsSchema,
20
+ optionsConfig: SKILLS_OPTIONS_CONFIG,
21
+ loadHandler: async () => (await import("./skills.handler-Bz8bJKql.mjs")).handleSkillsParent,
22
+ subcommands: [createTypedCommand({
23
+ name: "sync",
24
+ description: "Copy installed @keystroke/skills into .cursor/skills and .claude/skills",
25
+ schema: SkillsCommandOptionsSchema,
26
+ optionsConfig: SKILLS_OPTIONS_CONFIG,
27
+ loadHandler: async () => (await import("./skills-sync.handler-DIy8GR16.mjs")).handleSkillsSync
28
+ })]
29
+ });
30
+ cmd.enablePositionalOptions();
31
+ cmd.passThroughOptions();
32
+ return cmd;
33
+ }
34
+ //#endregion
35
+ export { createSkillsCommand };
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { t as ui } from "./keystroke.mjs";
4
+ //#region src/commands/skills/skills.handler.ts
5
+ async function handleSkillsParent(_options, _ctx) {
6
+ ui.hint("Run `keystroke skills sync` to copy @keystroke/skills into .cursor/skills and .claude/skills.");
7
+ }
8
+ //#endregion
9
+ export { handleSkillsParent };
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { d as getMetadataRoot } from "./layout-CbMtQ2tm.mjs";
4
+ import { t as BASE_IGNORE_PATTERNS } from "./metadata-layout-GUYIUo0i-_aG2zjue.mjs";
5
+ import { a as literalString, l as unwrapExpression, n as identifierName, r as isNode } from "./oxc-B3KI3rf_-n9d1hKNq.mjs";
6
+ import { readFile, readdir, rm } from "node:fs/promises";
7
+ import path from "node:path";
8
+ //#region ../../packages/workflow-builder/dist/source-analysis-Cj-ADyu-.mjs
9
+ async function removeAllMetadataArtifacts(outputDir) {
10
+ await rm(getMetadataRoot(outputDir), {
11
+ recursive: true,
12
+ force: true
13
+ });
14
+ }
15
+ async function removeMetadataArtifacts(outputDir, outputFiles) {
16
+ for (const outputFile of new Set(outputFiles)) await rm(path.join(outputDir, outputFile), { force: true });
17
+ await removeEmptyMetadataDirectories(getMetadataRoot(outputDir));
18
+ }
19
+ async function removeEmptyMetadataDirectories(directoryPath) {
20
+ try {
21
+ const entries = await readdir(directoryPath, { withFileTypes: true });
22
+ for (const entry of entries) {
23
+ if (!entry.isDirectory()) continue;
24
+ await removeEmptyMetadataDirectories(path.join(directoryPath, entry.name));
25
+ }
26
+ if ((await readdir(directoryPath, { withFileTypes: true })).length === 0) {
27
+ await rm(directoryPath, {
28
+ recursive: true,
29
+ force: true
30
+ });
31
+ return true;
32
+ }
33
+ } catch {
34
+ return false;
35
+ }
36
+ return false;
37
+ }
38
+ const DISCOVERY_GLOB = [
39
+ "**/*.ts",
40
+ "**/*.tsx",
41
+ "**/*.mts"
42
+ ];
43
+ const DISCOVERY_IGNORE = [...BASE_IGNORE_PATTERNS, "**/dist/**"];
44
+ const WORKFLOW_IMPORT_SOURCES = ["@keystroke/workflow-core"];
45
+ const AGENT_FACTORY_IMPORT_SOURCES = ["@keystroke/integration-ai"];
46
+ const AGENT_FACTORY_NAMES = ["agent"];
47
+ function getLocalModuleSpecifier(moduleSpecifier) {
48
+ if (!moduleSpecifier) return null;
49
+ return moduleSpecifier.startsWith(".") ? moduleSpecifier : null;
50
+ }
51
+ async function resolveLocalModulePath(fromFilePath, specifier) {
52
+ const basePath = path.resolve(path.dirname(fromFilePath), specifier);
53
+ const candidates = [
54
+ basePath,
55
+ `${basePath}.ts`,
56
+ `${basePath}.tsx`,
57
+ `${basePath}.mts`,
58
+ path.join(basePath, "index.ts"),
59
+ path.join(basePath, "index.tsx"),
60
+ path.join(basePath, "index.mts")
61
+ ];
62
+ for (const candidate of candidates) try {
63
+ await readFile(candidate, "utf-8");
64
+ return candidate;
65
+ } catch {}
66
+ return null;
67
+ }
68
+ function collectWorkflowImportNames(sourceFile) {
69
+ const names = new Map([
70
+ ["Workflow", "workflow"],
71
+ ["Agent", "agent"],
72
+ ["Task", "task"]
73
+ ]);
74
+ for (const statement of sourceFile.statements) {
75
+ if (statement.type !== "ImportDeclaration") continue;
76
+ const moduleSpecifier = literalString(statement.source);
77
+ if (!moduleSpecifier || !Array.isArray(statement.specifiers)) continue;
78
+ if (WORKFLOW_IMPORT_SOURCES.includes(moduleSpecifier)) for (const specifier of statement.specifiers) {
79
+ if (!isNode(specifier) || specifier.type !== "ImportSpecifier") continue;
80
+ const importedName = identifierName(specifier.imported);
81
+ const localName = identifierName(specifier.local);
82
+ if (!importedName || !localName) continue;
83
+ if (importedName === "Workflow") names.set(localName, "workflow");
84
+ else if (importedName === "Agent") names.set(localName, "agent");
85
+ else if (importedName === "Task") names.set(localName, "task");
86
+ }
87
+ if (AGENT_FACTORY_IMPORT_SOURCES.includes(moduleSpecifier)) for (const specifier of statement.specifiers) {
88
+ if (!isNode(specifier) || specifier.type !== "ImportSpecifier") continue;
89
+ const importedName = identifierName(specifier.imported);
90
+ const localName = identifierName(specifier.local);
91
+ if (!importedName || !localName) continue;
92
+ if (AGENT_FACTORY_NAMES.includes(importedName)) names.set(localName, "agent");
93
+ }
94
+ }
95
+ return names;
96
+ }
97
+ function collectLocalWorkflowBindings(sourceFile, workflowImportNames) {
98
+ const bindings = /* @__PURE__ */ new Map();
99
+ for (const statement of sourceFile.statements) for (const declaration of getVariableDeclarators(statement)) {
100
+ const bindingName = identifierName(declaration.id);
101
+ if (!bindingName || !isNode(declaration.init)) continue;
102
+ const exportKind = classifyDiscoverableExpression(declaration.init, workflowImportNames);
103
+ if (exportKind) bindings.set(bindingName, exportKind);
104
+ }
105
+ return bindings;
106
+ }
107
+ function resolveDefaultExportAssignment(expression, filePath, localWorkflowBindings, workflowImportNames) {
108
+ const exportKind = classifyDiscoverableExpression(expression, workflowImportNames);
109
+ if (exportKind) return {
110
+ resolvedFilePath: filePath,
111
+ localExportName: "default",
112
+ exportKind
113
+ };
114
+ const bindingName = identifierName(expression);
115
+ const bindingKind = bindingName ? localWorkflowBindings.get(bindingName) : void 0;
116
+ if (bindingKind) return {
117
+ resolvedFilePath: filePath,
118
+ localExportName: "default",
119
+ exportKind: bindingKind
120
+ };
121
+ return null;
122
+ }
123
+ function isExportedVariableStatement(statement) {
124
+ return statement.type === "ExportNamedDeclaration" && isNode(statement.declaration) && statement.declaration.type === "VariableDeclaration";
125
+ }
126
+ function classifyDiscoverableExpression(expression, workflowImportNames) {
127
+ const unwrapped = unwrapExpression(expression);
128
+ if (unwrapped.type === "NewExpression") {
129
+ const callee = identifierName(unwrapped.callee);
130
+ return callee ? workflowImportNames.get(callee) ?? null : null;
131
+ }
132
+ if (unwrapped.type === "CallExpression") {
133
+ const callee = identifierName(unwrapped.callee);
134
+ return callee ? workflowImportNames.get(callee) ?? null : null;
135
+ }
136
+ return null;
137
+ }
138
+ function getVariableDeclarators(statement) {
139
+ const declaration = statement.type === "VariableDeclaration" ? statement : statement.type === "ExportNamedDeclaration" && isNode(statement.declaration) ? statement.declaration : null;
140
+ if (!declaration || declaration.type !== "VariableDeclaration") return [];
141
+ return Array.isArray(declaration.declarations) ? declaration.declarations.filter((node) => isNode(node)) : [];
142
+ }
143
+ //#endregion
144
+ export { getLocalModuleSpecifier as a, removeAllMetadataArtifacts as c, resolveDefaultExportAssignment as d, resolveLocalModulePath as f, collectWorkflowImportNames as i, removeEmptyMetadataDirectories as l, DISCOVERY_IGNORE as n, getVariableDeclarators as o, collectLocalWorkflowBindings as r, isExportedVariableStatement as s, DISCOVERY_GLOB as t, removeMetadataArtifacts as u };
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { a as originalConsole, c as isTTY, i as logger, o as ANSI, s as style } from "./keystroke.mjs";
4
+ import { writeSync } from "node:fs";
5
+ import { Worker } from "node:worker_threads";
6
+ //#region src/lib/spinner-progress.ts
7
+ /** Match `spinner-worker` (stdout) so `stopAll` clears the same stream as the worker. */
8
+ const SPINNER_OUTPUT_FD = 1;
9
+ const DEFAULT_PHASE_ID = "__default__";
10
+ function formatProgressDuration(ms) {
11
+ if (ms < 1e3) return `${Math.round(ms)}ms`;
12
+ return `${(ms / 1e3).toFixed(1)}s`;
13
+ }
14
+ function printCompletedLine(label, elapsed) {
15
+ const check = style("✓", `${ANSI.bold}${ANSI.green}`);
16
+ if (elapsed) {
17
+ const timeStr = style(elapsed, ANSI.dim);
18
+ originalConsole.info(` ${check} ${label} ${timeStr}`);
19
+ return;
20
+ }
21
+ originalConsole.info(` ${check} ${label}`);
22
+ }
23
+ function printFailedLine(label, elapsed) {
24
+ const cross = style("✗", `${ANSI.bold}${ANSI.red}`);
25
+ if (elapsed) {
26
+ const timeStr = style(elapsed, ANSI.dim);
27
+ originalConsole.info(` ${cross} ${label} ${timeStr}`);
28
+ return;
29
+ }
30
+ originalConsole.info(` ${cross} ${label}`);
31
+ }
32
+ function printSkippedLine(label) {
33
+ const dash = style("-", ANSI.dim);
34
+ originalConsole.info(` ${dash} ${label}`);
35
+ }
36
+ function createWorker() {
37
+ if (!isTTY()) return null;
38
+ try {
39
+ return new Worker(new URL("./spinner-worker.ts", import.meta.url));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+ function createSpinnerProgress(logPrefix, options = {}) {
45
+ const worker = createWorker();
46
+ const phaseStartTimes = /* @__PURE__ */ new Map();
47
+ const visiblePhaseIds = /* @__PURE__ */ new Set();
48
+ const showElapsed = options.showElapsed ?? true;
49
+ let defaultLabel = "";
50
+ function addPendingPhase(id, label) {
51
+ visiblePhaseIds.add(id);
52
+ worker?.postMessage({
53
+ type: "addPendingPhase",
54
+ id,
55
+ label,
56
+ showElapsed
57
+ });
58
+ }
59
+ function startPhase(id, label) {
60
+ visiblePhaseIds.add(id);
61
+ phaseStartTimes.set(id, Date.now());
62
+ logger.info(`${logPrefix} → [${id}] ${label}`);
63
+ worker?.postMessage({
64
+ type: "addPhase",
65
+ id,
66
+ label,
67
+ showElapsed
68
+ });
69
+ }
70
+ function updatePhase(id, label) {
71
+ worker?.postMessage({
72
+ type: "updateLabel",
73
+ id,
74
+ label
75
+ });
76
+ }
77
+ function completePhase(id, label, elapsedMs) {
78
+ const phaseStart = phaseStartTimes.get(id);
79
+ const elapsed = formatProgressDuration(elapsedMs ?? (phaseStart ? Date.now() - phaseStart : 0));
80
+ phaseStartTimes.delete(id);
81
+ visiblePhaseIds.delete(id);
82
+ logger.info(`${logPrefix} ✓ [${id}] ${label} ${elapsed}`);
83
+ if (worker) worker.postMessage({
84
+ type: "completePhase",
85
+ id,
86
+ label,
87
+ elapsed,
88
+ showElapsed
89
+ });
90
+ else printCompletedLine(label, showElapsed ? elapsed : void 0);
91
+ }
92
+ function failPhase(id, label, elapsedMs, error) {
93
+ const phaseStart = phaseStartTimes.get(id);
94
+ const elapsed = formatProgressDuration(elapsedMs ?? (phaseStart ? Date.now() - phaseStart : 0));
95
+ phaseStartTimes.delete(id);
96
+ visiblePhaseIds.delete(id);
97
+ const msg = error ? `${label}: ${error}` : label;
98
+ logger.info(`${logPrefix} ✗ [${id}] ${msg} ${elapsed}`);
99
+ if (worker) worker.postMessage({
100
+ type: "failPhase",
101
+ id,
102
+ label: msg,
103
+ elapsed,
104
+ showElapsed
105
+ });
106
+ else printFailedLine(msg, showElapsed ? elapsed : void 0);
107
+ }
108
+ function skipPhase(id, label) {
109
+ phaseStartTimes.delete(id);
110
+ visiblePhaseIds.delete(id);
111
+ logger.info(`${logPrefix} - [${id}] ${label}`);
112
+ if (worker) worker.postMessage({
113
+ type: "skipPhase",
114
+ id,
115
+ label
116
+ });
117
+ else printSkippedLine(label);
118
+ }
119
+ function stopAll() {
120
+ const lineCount = visiblePhaseIds.size;
121
+ phaseStartTimes.clear();
122
+ visiblePhaseIds.clear();
123
+ worker?.postMessage({ type: "stopAll" });
124
+ if (isTTY() && lineCount > 0) {
125
+ let clearOutput = "";
126
+ if (lineCount > 1) clearOutput += "\x1B[A".repeat(lineCount - 1);
127
+ for (let i = 0; i < lineCount; i++) {
128
+ clearOutput += "\r\x1B[2K";
129
+ if (i < lineCount - 1) clearOutput += "\n";
130
+ }
131
+ if (lineCount > 1) clearOutput += "\x1B[A".repeat(lineCount - 1);
132
+ writeSync(SPINNER_OUTPUT_FD, clearOutput);
133
+ }
134
+ }
135
+ function start(label) {
136
+ defaultLabel = label;
137
+ startPhase(DEFAULT_PHASE_ID, label);
138
+ }
139
+ function setLabel(label) {
140
+ defaultLabel = label;
141
+ updatePhase(DEFAULT_PHASE_ID, label);
142
+ }
143
+ function complete(label, elapsedMs) {
144
+ completePhase(DEFAULT_PHASE_ID, label, elapsedMs);
145
+ }
146
+ function fail(label, elapsedMs, error) {
147
+ failPhase(DEFAULT_PHASE_ID, label, elapsedMs, error);
148
+ }
149
+ function skip(label) {
150
+ skipPhase(DEFAULT_PHASE_ID, label);
151
+ }
152
+ function stop() {
153
+ stopAll();
154
+ }
155
+ return {
156
+ start,
157
+ setLabel,
158
+ complete,
159
+ fail,
160
+ skip,
161
+ stop,
162
+ isRunning: () => visiblePhaseIds.size > 0,
163
+ currentLabel: () => defaultLabel,
164
+ addPendingPhase,
165
+ startPhase,
166
+ updatePhase,
167
+ completePhase,
168
+ failPhase,
169
+ skipPhase
170
+ };
171
+ }
172
+ //#endregion
173
+ export { formatProgressDuration as n, createSpinnerProgress as t };