@keystrokehq/cli 0.0.15 → 0.0.16

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 (81) hide show
  1. package/README.md +11 -1
  2. package/dist/{admin-CXQezpQA.mjs → admin-Bb9Hx-gO.mjs} +1 -1
  3. package/dist/{agents-CWGz8CR-.mjs → agents-CbmvvOAx.mjs} +2 -2
  4. package/dist/{api-keys-BZmUiIEr.mjs → api-keys-DJlyIf10.mjs} +1 -1
  5. package/dist/{auth-CGBgi6PG.mjs → auth-DpDEkJz7.mjs} +1 -1
  6. package/dist/{build-agents-DseUtzd4-DBQ82ErJ.mjs → build-agents-DseUtzd4-VYWtIZy9.mjs} +2 -2
  7. package/dist/{build-tasks-GVuMLS0h-CWrrj8SF.mjs → build-tasks-GVuMLS0h-p08mMOyK.mjs} +2 -2
  8. package/dist/{build-workflows-CV4tBo6S-B4SPp86e.mjs → build-workflows-CV4tBo6S-knCnBKTc.mjs} +2 -2
  9. package/dist/{build.handler-DqnngAkl.mjs → build.handler-BNSC_zhQ.mjs} +1 -1
  10. package/dist/{commander-i-7LgOyc.mjs → commander-D15UZVjp.mjs} +1 -1
  11. package/dist/{connect-CS6sqNfA.mjs → connect-DzSNDSmI.mjs} +1 -1
  12. package/dist/{credentials-1CPFwx-k.mjs → credentials-VidBoOd7.mjs} +1 -1
  13. package/dist/{current-deployment-workflow-CUBHcdZl.mjs → current-deployment-workflow-BRUEdPrN.mjs} +1 -1
  14. package/dist/{deploy-DwRwyVwR.mjs → deploy-eshEEiP-.mjs} +2 -2
  15. package/dist/{deploy.handler-zMb-BHLo.mjs → deploy.handler-BxxWI7nV.mjs} +6 -6
  16. package/dist/{diff.handler-C-XqswH5.mjs → diff.handler-CzrKCj7N.mjs} +1 -1
  17. package/dist/{init-QhRFud0x.mjs → init-PTwX63_P.mjs} +15 -3
  18. package/dist/{init.handler-Beu-vpIu.mjs → init.handler-CdytFiFt.mjs} +24 -61
  19. package/dist/{inspect.handler-ULT2jiVU.mjs → inspect.handler-umc7of-r.mjs} +1 -1
  20. package/dist/{integrations-6BiywCph.mjs → integrations-B0Gv-L0s.mjs} +4 -4
  21. package/dist/{invites-BlB-hKUE.mjs → invites-Cqi7iyIN.mjs} +4 -4
  22. package/dist/keystroke.mjs +21 -21
  23. package/dist/{list2.handler-L3BKR5ok.mjs → list2.handler-T5v4EK20.mjs} +1 -1
  24. package/dist/{listen-Tx2SrMyo.mjs → listen-rHLiCWbn.mjs} +2 -2
  25. package/dist/{listen.handler-C7AqsKLf.mjs → listen.handler-B9T58yAj.mjs} +1 -1
  26. package/dist/{logs-NI-DyeFY.mjs → logs-DUwdYZB-.mjs} +3 -3
  27. package/dist/{logs.handler-BGJU1p3H.mjs → logs.handler-DGcGN2qb.mjs} +1 -1
  28. package/dist/{org-8bkIZAJ4.mjs → org-DUCts2MV.mjs} +15 -15
  29. package/dist/{projects-B5MRnbHS.mjs → projects-CbquwUlm.mjs} +4 -4
  30. package/dist/{run-polling-BwyyKDwg.mjs → run-polling-BWcLQvm0.mjs} +1 -1
  31. package/dist/{run.handler-TJNyF_p_.mjs → run.handler-BiBDLoeH.mjs} +2 -2
  32. package/dist/{runs-Bs8VzL8P.mjs → runs-Bc3zjk7V.mjs} +1 -1
  33. package/dist/skill-installer-DkRJ6oLi.mjs +506 -0
  34. package/dist/{skills-sync.handler-DXF6IgEX.mjs → skills-sync.handler-C4ztv1Vu.mjs} +20 -7
  35. package/dist/skills.command-DuL4kLUi.mjs +49 -0
  36. package/dist/{skills.handler-CPKCf9ZK.mjs → skills.handler-R5KAbioE.mjs} +1 -1
  37. package/dist/{sync-BZj7Dkhq.mjs → sync-Pssitj6K.mjs} +2 -2
  38. package/dist/{sync.handler-Kk4R2lJ_.mjs → sync.handler-Be0U3x-n.mjs} +1 -1
  39. package/dist/{task-target-build-Du0ObGbb.mjs → task-target-build-BG6cC3bz.mjs} +3 -3
  40. package/dist/task-target-deploy-runner.mjs +4 -4
  41. package/dist/{test-CJ8Vx_h5.mjs → test-BISghlKg.mjs} +2 -2
  42. package/dist/{test.handler-BTn4NFmU.mjs → test.handler-DkizZhVu.mjs} +2 -2
  43. package/dist/{tool.handler-CuxoCstV.mjs → tool.handler-Bu130Vcz.mjs} +3 -3
  44. package/dist/{trigger-artifacts-RizI57RC-abdkW8-z.mjs → trigger-artifacts-RizI57RC-CxHwCkQ_.mjs} +2 -2
  45. package/dist/types-D04ah3uY.mjs +6 -0
  46. package/dist/{upgrade-CdA_Sw4F.mjs → upgrade-cH9I_pZq.mjs} +2 -2
  47. package/dist/{validate.handler-COJ53qWJ.mjs → validate.handler-I8LY-UkG.mjs} +1 -1
  48. package/dist/{workflow-build-kNNcU-R8.mjs → workflow-build-C9rQQ4qU.mjs} +5 -5
  49. package/dist/{workflow-bundler-BzHk73PM-CRcJvu9a.mjs → workflow-bundler-BzHk73PM-AIB4-u4Y.mjs} +1 -1
  50. package/dist/{workflows-D04CqpO-.mjs → workflows-CL1jYSLR.mjs} +12 -12
  51. package/package.json +6 -6
  52. package/dist/skills.command-B8yExFCn.mjs +0 -35
  53. package/dist/sync-keystroke-agent-skills-ChUj1LnK.mjs +0 -66
  54. /package/dist/{accept.handler-BsZQqmzU.mjs → accept.handler-BPwp_UAE.mjs} +0 -0
  55. /package/dist/{build-metadata-C8Ra_Gi--CTCBRjFA.mjs → build-metadata-C8Ra_Gi--BdoyLQMl.mjs} +0 -0
  56. /package/dist/{clear-cache.handler-Bkt6GKnF.mjs → clear-cache.handler-gr5VmEYB.mjs} +0 -0
  57. /package/dist/{clear.handler-BieI9Oix.mjs → clear.handler-CtOZ4aRn.mjs} +0 -0
  58. /package/dist/{current.handler-C48q2mBd.mjs → current.handler-QZQ-l84v.mjs} +0 -0
  59. /package/dist/{deploy-D4ILrWpx.mjs → deploy-CJbVB7e2.mjs} +0 -0
  60. /package/dist/{detect-env-access-CwkOYeYM-BLtKepjx.mjs → detect-env-access-CwkOYeYM-CZIixHeR.mjs} +0 -0
  61. /package/dist/{env.handler-DK3B7MLl.mjs → env.handler-B3YDQIVE.mjs} +0 -0
  62. /package/dist/{invites.list.handler-DmeMcezN.mjs → invites.list.handler-CErgY35S.mjs} +0 -0
  63. /package/dist/{invites.resend.handler-pJTPtKHE.mjs → invites.resend.handler-DRCRIA4F.mjs} +0 -0
  64. /package/dist/{invites.revoke.handler-4NgnnfiU.mjs → invites.revoke.handler-C0FZdAR0.mjs} +0 -0
  65. /package/dist/{list.handler-C7AChEPW.mjs → list.handler-BjutlIkE.mjs} +0 -0
  66. /package/dist/{list.handler-BuX-bb2y.mjs → list.handler-Cr_DFAae.mjs} +0 -0
  67. /package/dist/{list.handler-BSyrxCma.mjs → list.handler-FlchXrKz.mjs} +0 -0
  68. /package/dist/{list.handler-U9-KuVlh.mjs → list.handler-c-8RpgB9.mjs} +0 -0
  69. /package/dist/{logs.handler-BqmZ4eLx.mjs → logs.handler-dcRq-zoc.mjs} +0 -0
  70. /package/dist/{members.add.handler-B4H8Hn6x.mjs → members.add.handler-DmYI43rZ.mjs} +0 -0
  71. /package/dist/{members.invite.handler-D8ONlt4Y.mjs → members.invite.handler-B_KVxv5m.mjs} +0 -0
  72. /package/dist/{members.list.handler-BHJTMMiA.mjs → members.list.handler-BtuuIgQS.mjs} +0 -0
  73. /package/dist/{members.remove.handler-_hKd_sFd.mjs → members.remove.handler-Lvg-CqVv.mjs} +0 -0
  74. /package/dist/{members.update.handler-CC7J0k8n.mjs → members.update.handler-D-8izeso.mjs} +0 -0
  75. /package/dist/{paused.handler-9ND-i2EN.mjs → paused.handler-ST9dCe8E.mjs} +0 -0
  76. /package/dist/{read-credential-keys-77a91T8M-COvwpok_.mjs → read-credential-keys-77a91T8M-DMmY6oDW.mjs} +0 -0
  77. /package/dist/{register.handler-CttgzybN.mjs → register.handler-BAx0IC-u.mjs} +0 -0
  78. /package/dist/{run-polling-B4KvySvp.mjs → run-polling-CwlzB5-9.mjs} +0 -0
  79. /package/dist/{switch.handler-BFBM8rSi.mjs → switch.handler-CTwhIcaQ.mjs} +0 -0
  80. /package/dist/{task-target-deploy-OyxLvh3a.mjs → task-target-deploy-gMQC8kXU.mjs} +0 -0
  81. /package/dist/{upgrade.handler-C2eZ_tg3.mjs → upgrade.handler-CXEF4ue0.mjs} +0 -0
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { k as CliExitError, n as ui } from "./keystroke.mjs";
4
+ import { createRequire } from "node:module";
5
+ import { access, cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { autocompleteMultiselect, cancel, isCancel, select } from "@clack/prompts";
9
+ //#region src/lib/skill-installer/package.ts
10
+ const SKILLS_PACKAGE_CONTENT_DIR = "src";
11
+ const AGENTS_PACKAGE_PATH = "src/AGENTS.md";
12
+ async function resolveKeystrokeSkillsPackageRoot() {
13
+ try {
14
+ const require = createRequire(import.meta.url);
15
+ return path.dirname(require.resolve("@keystrokehq/skills/package.json"));
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ function getKeystrokeSkillsContentRoot(skillsPackageRoot) {
21
+ return path.join(skillsPackageRoot, SKILLS_PACKAGE_CONTENT_DIR);
22
+ }
23
+ async function listKeystrokeSkillDirectoryNames(skillsContentRoot) {
24
+ const entries = await readdir(skillsContentRoot, { withFileTypes: true });
25
+ const names = [];
26
+ for (const entry of entries) {
27
+ if (!entry.isDirectory()) continue;
28
+ if (entry.name.startsWith(".")) continue;
29
+ try {
30
+ await access(path.join(skillsContentRoot, entry.name, "SKILL.md"));
31
+ names.push(entry.name);
32
+ } catch {}
33
+ }
34
+ return names.sort();
35
+ }
36
+ function normalizeLineEndings$1(value) {
37
+ return value.replace(/\r\n/g, "\n");
38
+ }
39
+ function normalizeGuidanceBlurb(value) {
40
+ return `${normalizeLineEndings$1(value).trim()}\n`;
41
+ }
42
+ function resolveMonorepoSkillsBlurbPath() {
43
+ return fileURLToPath(new URL("../../../../../packages/skills/src/AGENTS.md", import.meta.url));
44
+ }
45
+ function resolveCliPackageSkillsBlurbPath() {
46
+ const relativePath = import.meta.url.includes("/dist/") ? "../AGENTS-blurb.md" : "../../../AGENTS-blurb.md";
47
+ return fileURLToPath(new URL(relativePath, import.meta.url));
48
+ }
49
+ function resolveBundledKeystrokeAgentsBlurbPath() {
50
+ const require = createRequire(import.meta.url);
51
+ try {
52
+ const skillsPackageJsonPath = require.resolve("@keystrokehq/skills/package.json");
53
+ return path.join(path.dirname(skillsPackageJsonPath), AGENTS_PACKAGE_PATH);
54
+ } catch {}
55
+ try {
56
+ return resolveCliPackageSkillsBlurbPath();
57
+ } catch {}
58
+ return resolveMonorepoSkillsBlurbPath();
59
+ }
60
+ async function loadKeystrokeAgentsBlurb() {
61
+ try {
62
+ return normalizeGuidanceBlurb(await readFile(resolveBundledKeystrokeAgentsBlurbPath(), "utf-8"));
63
+ } catch (error) {
64
+ throw new CliExitError("Could not load the bundled Keystroke AGENTS.md content. Reinstall the CLI or republish @keystrokehq/cli with @keystrokehq/skills/src/AGENTS.md.", { cause: error });
65
+ }
66
+ }
67
+ //#endregion
68
+ //#region src/lib/skill-installer/guidance.ts
69
+ function normalizeLineEndings(value) {
70
+ return value.replace(/\r\n/g, "\n");
71
+ }
72
+ async function ensureRootGuidanceFile(targetDir, relativePath, blurb) {
73
+ const normalizedPath = path.normalize(relativePath);
74
+ const filePath = path.join(targetDir, normalizedPath);
75
+ const normalizedBlurb = normalizeGuidanceBlurb(blurb);
76
+ try {
77
+ const normalizedExisting = normalizeLineEndings(await readFile(filePath, "utf-8"));
78
+ if (normalizedExisting.includes(normalizedBlurb.trim())) return {
79
+ path: normalizedPath,
80
+ action: "skipped"
81
+ };
82
+ await writeFile(filePath, normalizedExisting.trim().length > 0 ? `${normalizedExisting.trimEnd()}\n\n${normalizedBlurb}` : normalizedBlurb, "utf-8");
83
+ return {
84
+ path: normalizedPath,
85
+ action: "updated"
86
+ };
87
+ } catch {
88
+ await mkdir(path.dirname(filePath), { recursive: true });
89
+ await writeFile(filePath, normalizedBlurb, "utf-8");
90
+ return {
91
+ path: normalizedPath,
92
+ action: "created"
93
+ };
94
+ }
95
+ }
96
+ async function ensureRootGuidanceFiles(targetDir, relativePaths, blurb) {
97
+ const uniquePaths = [...new Set(relativePaths.map((filePath) => path.normalize(filePath)))];
98
+ const results = [];
99
+ for (const relativePath of uniquePaths) results.push(await ensureRootGuidanceFile(targetDir, relativePath, blurb));
100
+ return results;
101
+ }
102
+ //#endregion
103
+ //#region src/lib/skill-installer/path.ts
104
+ function normalizeProjectPath(value) {
105
+ return path.normalize(value).replace(/\/+$/, "");
106
+ }
107
+ //#endregion
108
+ //#region src/lib/skill-installer/adapters/agents-md.ts
109
+ function agentsMdAdapter(slug, label, projectSkillDir) {
110
+ return {
111
+ slug,
112
+ label,
113
+ compatibilityGroup: "agents-md",
114
+ projectSkillDir,
115
+ rootGuidanceTargets: [{
116
+ path: "AGENTS.md",
117
+ kind: "root-file"
118
+ }]
119
+ };
120
+ }
121
+ const AGENTS_MD_AGENT_ADAPTERS = [
122
+ agentsMdAdapter("cortex", "Cortex Code", ".cortex/skills"),
123
+ agentsMdAdapter("droid", "Droid", ".factory/skills"),
124
+ agentsMdAdapter("forgecode", "ForgeCode", ".forge/skills"),
125
+ agentsMdAdapter("kode", "Kode", ".kode/skills"),
126
+ agentsMdAdapter("mistral-vibe", "Mistral Vibe", ".vibe/skills"),
127
+ agentsMdAdapter("neovate", "Neovate", ".neovate/skills"),
128
+ agentsMdAdapter("adal", "AdaL", ".adal/skills")
129
+ ];
130
+ //#endregion
131
+ //#region src/lib/skill-installer/adapters/claude.ts
132
+ const CLAUDE_AGENT_ADAPTERS = [{
133
+ slug: "claude-code",
134
+ label: "Claude Code",
135
+ compatibilityGroup: "claude",
136
+ projectSkillDir: ".claude/skills",
137
+ rootGuidanceTargets: [{
138
+ path: "CLAUDE.md",
139
+ kind: "root-file"
140
+ }]
141
+ }];
142
+ //#endregion
143
+ //#region src/lib/skill-installer/adapters/priority-context.ts
144
+ function priorityContextAdapter(slug, label, projectSkillDir, guidancePath) {
145
+ return {
146
+ slug,
147
+ label,
148
+ compatibilityGroup: "priority-context",
149
+ projectSkillDir,
150
+ rootGuidanceTargets: [{
151
+ path: guidancePath,
152
+ kind: "root-file"
153
+ }]
154
+ };
155
+ }
156
+ const PRIORITY_CONTEXT_AGENT_ADAPTERS = [
157
+ priorityContextAdapter("codestudio", "Code Studio", ".agents/skills", ".codestudio/codestudio-instructions.md"),
158
+ priorityContextAdapter("goose", "Goose", ".agents/skills", ".goosehints"),
159
+ priorityContextAdapter("hermes-agent", "Hermes Agent", ".hermes/skills", ".hermes.md"),
160
+ priorityContextAdapter("junie", "Junie", ".junie/skills", ".junie/AGENTS.md")
161
+ ];
162
+ //#endregion
163
+ //#region src/lib/skill-installer/adapters/product-files.ts
164
+ function productFileAdapter(slug, label, projectSkillDir, guidancePath) {
165
+ return {
166
+ slug,
167
+ label,
168
+ compatibilityGroup: "product-file",
169
+ projectSkillDir,
170
+ rootGuidanceTargets: [{
171
+ path: guidancePath,
172
+ kind: "root-file"
173
+ }]
174
+ };
175
+ }
176
+ const PRODUCT_FILE_AGENT_ADAPTERS = [
177
+ productFileAdapter("gemini-cli", "Gemini CLI", ".agents/skills", "GEMINI.md"),
178
+ productFileAdapter("github-copilot", "GitHub Copilot", ".agents/skills", ".github/copilot-instructions.md"),
179
+ productFileAdapter("iflow-cli", "iFlow CLI", ".iflow/skills", "IFLOW.md"),
180
+ productFileAdapter("pochi", "Pochi", ".agents/skills", "README.pochi.md"),
181
+ productFileAdapter("windsurf", "Windsurf", ".agents/skills", ".windsurfrules")
182
+ ];
183
+ //#endregion
184
+ //#region src/lib/skill-installer/adapters/rules-directories.ts
185
+ function rulesDirectoryAdapter(slug, label, projectSkillDir, guidancePath) {
186
+ return {
187
+ slug,
188
+ label,
189
+ compatibilityGroup: "rules-directory",
190
+ projectSkillDir,
191
+ rootGuidanceTargets: [{
192
+ path: guidancePath,
193
+ kind: "rules-file"
194
+ }]
195
+ };
196
+ }
197
+ const RULES_DIRECTORY_AGENT_ADAPTERS = [
198
+ rulesDirectoryAdapter("augment", "Augment", ".agents/skills", ".augment/rules/keystroke.md"),
199
+ rulesDirectoryAdapter("bob", "IBM Bob", ".bob/skills", ".bob/rules/keystroke.md"),
200
+ rulesDirectoryAdapter("codebuddy", "CodeBuddy", ".codebuddy/skills", ".codebuddy/rules/keystroke/RULE.mdc"),
201
+ rulesDirectoryAdapter("kiro-cli", "Kiro CLI", ".kiro/skills", ".kiro/steering/keystroke.md"),
202
+ rulesDirectoryAdapter("tabnine-cli", "Tabnine CLI", ".agents/skills", ".tabnine/guidelines/keystroke.md"),
203
+ rulesDirectoryAdapter("trae", "Trae", ".trae/skills", ".trae/project_rules.md"),
204
+ rulesDirectoryAdapter("trae-cn", "Trae CN", ".trae/skills", ".trae/project_rules.md"),
205
+ rulesDirectoryAdapter("zencoder", "Zencoder", ".agents/skills", ".zencoder/rules/keystroke.md")
206
+ ];
207
+ //#endregion
208
+ //#region src/lib/skill-installer/adapters/skill-only.ts
209
+ function skillOnlyAdapter(slug, label, projectSkillDir) {
210
+ return {
211
+ slug,
212
+ label,
213
+ compatibilityGroup: "skill-only",
214
+ projectSkillDir,
215
+ rootGuidanceTargets: []
216
+ };
217
+ }
218
+ const SKILL_ONLY_AGENT_ADAPTERS = [
219
+ skillOnlyAdapter("cline", "Cline", ".cline/skills"),
220
+ skillOnlyAdapter("aider-desk", "AiderDesk", ".aider-desk/skills"),
221
+ skillOnlyAdapter("openclaw", "OpenClaw", ".agents/skills"),
222
+ skillOnlyAdapter("codearts-agent", "CodeArts Agent", ".codeartsdoer/skills"),
223
+ skillOnlyAdapter("codemaker", "Codemaker", ".codemaker/skills"),
224
+ skillOnlyAdapter("continue", "Continue", ".continue/skills"),
225
+ skillOnlyAdapter("kilo", "Kilo Code", ".agents/skills"),
226
+ skillOnlyAdapter("mcpjam", "MCPJam", ".agents/skills"),
227
+ skillOnlyAdapter("qoder", "Qoder", ".qoder/skills"),
228
+ skillOnlyAdapter("qwen-code", "Qwen Code", ".agents/skills"),
229
+ skillOnlyAdapter("roo", "Roo Code", ".agents/skills")
230
+ ];
231
+ //#endregion
232
+ //#region src/lib/skill-installer/adapters/universal.ts
233
+ const UNIVERSAL_SKILL_DIR = ".agents/skills";
234
+ const UNIVERSAL_GUIDANCE = [{
235
+ path: "AGENTS.md",
236
+ kind: "root-file"
237
+ }];
238
+ function universalAdapter(slug, label) {
239
+ return {
240
+ slug,
241
+ label,
242
+ compatibilityGroup: "universal",
243
+ projectSkillDir: UNIVERSAL_SKILL_DIR,
244
+ rootGuidanceTargets: [...UNIVERSAL_GUIDANCE]
245
+ };
246
+ }
247
+ const UNIVERSAL_AGENT_ADAPTERS = [
248
+ universalAdapter("universal", "Universal"),
249
+ universalAdapter("amp", "Amp"),
250
+ universalAdapter("antigravity", "Antigravity"),
251
+ universalAdapter("command-code", "Command Code"),
252
+ universalAdapter("codex", "Codex"),
253
+ universalAdapter("crush", "Crush"),
254
+ universalAdapter("cursor", "Cursor"),
255
+ universalAdapter("deepagents", "Deep Agents"),
256
+ universalAdapter("devin", "Devin for Terminal"),
257
+ universalAdapter("dexto", "Dexto"),
258
+ universalAdapter("firebender", "Firebender"),
259
+ universalAdapter("kimi-cli", "Kimi Code CLI"),
260
+ universalAdapter("mux", "Mux"),
261
+ universalAdapter("opencode", "OpenCode"),
262
+ universalAdapter("openhands", "OpenHands"),
263
+ universalAdapter("pi", "Pi"),
264
+ universalAdapter("replit", "Replit"),
265
+ universalAdapter("rovodev", "Rovo Dev"),
266
+ universalAdapter("warp", "Warp")
267
+ ];
268
+ //#endregion
269
+ //#region src/lib/skill-installer/router.ts
270
+ const UNIVERSAL_AGENT_SLUG = "universal";
271
+ const WILDCARD_AGENT_SLUG = "*";
272
+ const AGENT_ADAPTERS = [
273
+ ...UNIVERSAL_AGENT_ADAPTERS,
274
+ ...AGENTS_MD_AGENT_ADAPTERS,
275
+ ...CLAUDE_AGENT_ADAPTERS,
276
+ ...PRODUCT_FILE_AGENT_ADAPTERS,
277
+ ...RULES_DIRECTORY_AGENT_ADAPTERS,
278
+ ...PRIORITY_CONTEXT_AGENT_ADAPTERS,
279
+ ...SKILL_ONLY_AGENT_ADAPTERS
280
+ ];
281
+ var UnknownSkillAgentError = class extends Error {
282
+ unknownAgents;
283
+ supportedAgents;
284
+ constructor(unknownAgents, supportedAgents) {
285
+ super(`Unknown skill agent${unknownAgents.length === 1 ? "" : "s"}: ${unknownAgents.join(", ")}. Supported agents: ${supportedAgents.join(", ")}`);
286
+ this.name = "UnknownSkillAgentError";
287
+ this.unknownAgents = unknownAgents;
288
+ this.supportedAgents = supportedAgents;
289
+ }
290
+ };
291
+ function getSupportedAgentAdapters() {
292
+ return [...AGENT_ADAPTERS];
293
+ }
294
+ function getSupportedAgentSlugs() {
295
+ return AGENT_ADAPTERS.map((adapter) => adapter.slug).sort();
296
+ }
297
+ function resolveAgentAdapters(requestedAgentSlugs = []) {
298
+ const bySlug = new Map(AGENT_ADAPTERS.map((adapter) => [adapter.slug, adapter]));
299
+ const supportedAgents = getSupportedAgentSlugs();
300
+ const requested = [...new Set(requestedAgentSlugs.map((slug) => slug.trim()).filter(Boolean))];
301
+ const slugs = [UNIVERSAL_AGENT_SLUG, ...requested.includes(WILDCARD_AGENT_SLUG) ? AGENT_ADAPTERS.map((adapter) => adapter.slug) : requested];
302
+ const unknown = slugs.filter((slug) => !bySlug.has(slug));
303
+ if (unknown.length > 0) throw new UnknownSkillAgentError([...new Set(unknown)], supportedAgents);
304
+ const selected = [];
305
+ const seenSlugs = /* @__PURE__ */ new Set();
306
+ for (const slug of slugs) {
307
+ if (seenSlugs.has(slug)) continue;
308
+ seenSlugs.add(slug);
309
+ const adapter = bySlug.get(slug);
310
+ if (adapter) selected.push(adapter);
311
+ }
312
+ return selected;
313
+ }
314
+ function getUniqueSkillDirs(adapters) {
315
+ const seen = /* @__PURE__ */ new Set();
316
+ const dirs = [];
317
+ for (const adapter of adapters) {
318
+ const normalized = normalizeProjectPath(adapter.projectSkillDir);
319
+ if (seen.has(normalized)) continue;
320
+ seen.add(normalized);
321
+ dirs.push(normalized);
322
+ }
323
+ return dirs;
324
+ }
325
+ function getUniqueRootGuidanceTargets(adapters) {
326
+ const seen = /* @__PURE__ */ new Set();
327
+ const targets = [];
328
+ for (const adapter of adapters) for (const target of adapter.rootGuidanceTargets) {
329
+ const normalizedPath = path.normalize(target.path);
330
+ if (seen.has(normalizedPath)) continue;
331
+ seen.add(normalizedPath);
332
+ targets.push({
333
+ ...target,
334
+ path: normalizedPath
335
+ });
336
+ }
337
+ return targets;
338
+ }
339
+ //#endregion
340
+ //#region src/lib/skill-installer/installer.ts
341
+ const CANONICAL_SKILL_DIR = ".agents/skills";
342
+ async function replaceWithCopy(src, dest) {
343
+ await rm(dest, {
344
+ recursive: true,
345
+ force: true
346
+ });
347
+ await mkdir(path.dirname(dest), { recursive: true });
348
+ await cp(src, dest, {
349
+ recursive: true,
350
+ force: true
351
+ });
352
+ }
353
+ async function replaceWithSymlink(src, dest) {
354
+ await rm(dest, {
355
+ recursive: true,
356
+ force: true
357
+ });
358
+ await mkdir(path.dirname(dest), { recursive: true });
359
+ await symlink(path.relative(path.dirname(dest), src) || ".", dest, process.platform === "win32" ? "junction" : "dir");
360
+ }
361
+ function toAgentTargets(adapters, method) {
362
+ return adapters.map((adapter) => {
363
+ const normalized = normalizeProjectPath(adapter.projectSkillDir);
364
+ const action = normalized === CANONICAL_SKILL_DIR ? "canonical" : method === "symlink" ? "symlinked" : "copied";
365
+ return {
366
+ slug: adapter.slug,
367
+ label: adapter.label,
368
+ path: normalized,
369
+ action
370
+ };
371
+ });
372
+ }
373
+ async function installKeystrokeAgentSkills(options) {
374
+ const packageRoot = await resolveKeystrokeSkillsPackageRoot();
375
+ if (!packageRoot) return {
376
+ ok: false,
377
+ reason: "not_installed"
378
+ };
379
+ const skillsContentRoot = getKeystrokeSkillsContentRoot(packageRoot);
380
+ const skills = await listKeystrokeSkillDirectoryNames(skillsContentRoot);
381
+ if (skills.length === 0) return {
382
+ ok: false,
383
+ reason: "no_skills_found",
384
+ packageRoot
385
+ };
386
+ const projectDir = path.resolve(options.projectDir);
387
+ const adapters = resolveAgentAdapters(options.agentSlugs);
388
+ const skillDirs = getUniqueSkillDirs(adapters);
389
+ const canonicalDir = path.join(projectDir, CANONICAL_SKILL_DIR);
390
+ for (const skill of skills) await replaceWithCopy(path.join(skillsContentRoot, skill), path.join(projectDir, CANONICAL_SKILL_DIR, skill));
391
+ for (const skillDir of skillDirs) {
392
+ if (skillDir === CANONICAL_SKILL_DIR) continue;
393
+ for (const skill of skills) {
394
+ const canonicalSkillDir = path.join(canonicalDir, skill);
395
+ const dest = path.join(projectDir, skillDir, skill);
396
+ if (options.method === "symlink") await replaceWithSymlink(canonicalSkillDir, dest);
397
+ else await replaceWithCopy(canonicalSkillDir, dest);
398
+ }
399
+ }
400
+ const guidanceTargets = getUniqueRootGuidanceTargets(adapters);
401
+ const blurb = await loadKeystrokeAgentsBlurb();
402
+ const guidanceFiles = await ensureRootGuidanceFiles(projectDir, guidanceTargets.map((target) => target.path), blurb);
403
+ return {
404
+ ok: true,
405
+ packageRoot,
406
+ skills,
407
+ canonicalDir: CANONICAL_SKILL_DIR,
408
+ method: options.method,
409
+ agentTargets: toAgentTargets(adapters, options.method),
410
+ guidanceFiles
411
+ };
412
+ }
413
+ //#endregion
414
+ //#region src/lib/skill-installer/prompts.ts
415
+ const POPULAR_AGENT_SLUGS = [
416
+ "amp",
417
+ "claude-code",
418
+ "codex",
419
+ "cursor",
420
+ "droid",
421
+ "github-copilot",
422
+ "opencode",
423
+ "pi"
424
+ ];
425
+ function isInteractive(options) {
426
+ return options.interactive ?? process.stdin.isTTY;
427
+ }
428
+ function promptLabelForAdapter(adapter) {
429
+ if (adapter.slug === "droid") return "Factory (Droid)";
430
+ return adapter.label;
431
+ }
432
+ function comparePromptLabels(a, b) {
433
+ return promptLabelForAdapter(a).localeCompare(promptLabelForAdapter(b));
434
+ }
435
+ function toPromptOption(adapter, isPopular) {
436
+ return {
437
+ value: adapter.slug,
438
+ label: promptLabelForAdapter(adapter),
439
+ hint: isPopular ? `popular, ${adapter.projectSkillDir}` : adapter.projectSkillDir
440
+ };
441
+ }
442
+ function createAgentPromptOptions(adapters) {
443
+ const selectableAdapters = adapters.filter((adapter) => adapter.slug !== "universal");
444
+ const popularSlugSet = new Set(POPULAR_AGENT_SLUGS);
445
+ const popular = selectableAdapters.filter((adapter) => popularSlugSet.has(adapter.slug)).sort(comparePromptLabels);
446
+ const rest = selectableAdapters.filter((adapter) => !popularSlugSet.has(adapter.slug)).sort(comparePromptLabels);
447
+ return [...popular.map((adapter) => toPromptOption(adapter, true)), ...rest.map((adapter) => toPromptOption(adapter, false))];
448
+ }
449
+ async function promptAgentSlugs() {
450
+ const answer = await autocompleteMultiselect({
451
+ message: "Which agents do you want to install Keystroke skills to? Popular agents are listed first. Type to search, Space to select, Enter to confirm.",
452
+ required: false,
453
+ maxItems: 14,
454
+ placeholder: "Start typing to search agents",
455
+ options: createAgentPromptOptions(getSupportedAgentAdapters())
456
+ });
457
+ if (isCancel(answer)) {
458
+ cancel("Skill installation cancelled.");
459
+ throw new CliExitError("Skill installation cancelled.", {
460
+ exitCode: 0,
461
+ reported: true
462
+ });
463
+ }
464
+ return answer;
465
+ }
466
+ async function promptMethod() {
467
+ const answer = await select({
468
+ message: "Installation method",
469
+ initialValue: "symlink",
470
+ options: [{
471
+ value: "symlink",
472
+ label: "Symlink (recommended)",
473
+ hint: "Single source of truth, easy updates"
474
+ }, {
475
+ value: "copy",
476
+ label: "Copy to all agents",
477
+ hint: "Use when symlinks are not desirable"
478
+ }]
479
+ });
480
+ if (isCancel(answer)) {
481
+ cancel("Skill installation cancelled.");
482
+ throw new CliExitError("Skill installation cancelled.", {
483
+ exitCode: 0,
484
+ reported: true
485
+ });
486
+ }
487
+ return answer;
488
+ }
489
+ async function resolveSkillInstallChoices(options) {
490
+ const interactive = isInteractive(options);
491
+ return {
492
+ agentSlugs: options.agentSlugs !== void 0 ? options.agentSlugs : interactive ? await promptAgentSlugs() : [],
493
+ method: options.method ?? (interactive ? await promptMethod() : "symlink")
494
+ };
495
+ }
496
+ //#endregion
497
+ //#region src/lib/skill-installer/summary.ts
498
+ function summarizeSkillInstall(result, verb) {
499
+ ui.success(`${verb} ${result.skills.length} Keystroke skill(s) to ${result.canonicalDir}: ${result.skills.join(", ")}`);
500
+ const additionalTargets = result.agentTargets.filter((target) => target.action !== "canonical");
501
+ if (additionalTargets.length > 0) ui.success(`Provisioned ${additionalTargets.length} agent target(s): ${additionalTargets.map((target) => `${target.label} (${target.path}, ${target.action})`).join(", ")}`);
502
+ const changedGuidance = result.guidanceFiles.filter((file) => file.action !== "skipped");
503
+ if (changedGuidance.length > 0) ui.success(`Updated agent guidance: ${changedGuidance.map((file) => `${file.path} ${file.action}`).join(", ")}`);
504
+ }
505
+ //#endregion
506
+ export { UnknownSkillAgentError as i, resolveSkillInstallChoices as n, installKeystrokeAgentSkills as r, summarizeSkillInstall as t };
@@ -2,16 +2,29 @@
2
2
 
3
3
  import { k as CliExitError, n as ui } from "./keystroke.mjs";
4
4
  import { i as writeJson, r as isJsonMode } from "./output-CGdYhH0p.mjs";
5
- import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-ChUj1LnK.mjs";
5
+ import { i as UnknownSkillAgentError, n as resolveSkillInstallChoices, r as installKeystrokeAgentSkills, t as summarizeSkillInstall } from "./skill-installer-DkRJ6oLi.mjs";
6
6
  import path from "node:path";
7
7
  //#region src/commands/skills/skills-sync.handler.ts
8
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
9
+ const projectDir = path.resolve(options.path ?? process.cwd());
10
+ let result;
11
+ try {
12
+ const choices = await resolveSkillInstallChoices({
13
+ agentSlugs: options.agent,
14
+ method: options.method,
15
+ interactive: process.stdin.isTTY && !isJsonMode(options)
16
+ });
17
+ result = await installKeystrokeAgentSkills({
18
+ projectDir,
19
+ agentSlugs: choices.agentSlugs,
20
+ method: choices.method
14
21
  });
22
+ } catch (error) {
23
+ if (error instanceof UnknownSkillAgentError) throw new CliExitError(error.message, { cause: error });
24
+ throw error;
25
+ }
26
+ if (isJsonMode(options)) {
27
+ if (result.ok) writeJson(result);
15
28
  else if (result.reason === "not_installed") writeJson({
16
29
  ok: false,
17
30
  reason: "not_installed"
@@ -24,7 +37,7 @@ async function handleSkillsSync(options, _ctx) {
24
37
  return;
25
38
  }
26
39
  if (result.ok) {
27
- ui.success(`Synced ${result.copied.length} skill(s) to .cursor/skills and .claude/skills: ${result.copied.join(", ")}`);
40
+ summarizeSkillInstall(result, "Synced");
28
41
  return;
29
42
  }
30
43
  if (result.reason === "not_installed") throw new CliExitError("Could not resolve @keystrokehq/skills from this project or the installed CLI. Reinstall the CLI or add @keystrokehq/skills to devDependencies, run install, then run `keystroke skills sync`.", { exitCode: 1 });
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { n as JsonOptionSchema, t as JSON_OPTION_CONFIG } from "./output-CGdYhH0p.mjs";
4
+ import { t as createTypedCommand } from "./commander-D15UZVjp.mjs";
5
+ import { t as SKILL_INSTALL_METHODS } from "./types-D04ah3uY.mjs";
6
+ import { z } from "zod";
7
+ //#region src/commands/skills/skills.command.ts
8
+ const SkillsCommandOptionsSchema = JsonOptionSchema.extend({
9
+ path: z.string().optional().describe("Project root (default: current directory)"),
10
+ agent: z.array(z.string()).optional().describe("Agent target to install Keystroke skills for. Repeat for multiple agents; '*' selects all."),
11
+ method: z.enum(SKILL_INSTALL_METHODS).optional().describe("Skill install method for agent-specific targets")
12
+ });
13
+ const SKILLS_OPTIONS_CONFIG = {
14
+ ...JSON_OPTION_CONFIG,
15
+ path: {
16
+ flag: "--path <dir>",
17
+ description: "Project root (directory containing package.json; default: cwd)"
18
+ },
19
+ agent: {
20
+ flag: "--agent <agent>",
21
+ description: "Install Keystroke skills for an agent target. Repeat for multiple agents; '*' selects all.",
22
+ collect: true
23
+ },
24
+ method: {
25
+ flag: "--method <symlink|copy>",
26
+ description: "Skill install method for agent-specific targets"
27
+ }
28
+ };
29
+ function createSkillsCommand() {
30
+ const cmd = createTypedCommand({
31
+ name: "skills",
32
+ description: "Sync Keystroke agent skills (SKILL.md) from @keystrokehq/skills",
33
+ schema: SkillsCommandOptionsSchema,
34
+ optionsConfig: SKILLS_OPTIONS_CONFIG,
35
+ loadHandler: async () => (await import("./skills.handler-R5KAbioE.mjs")).handleSkillsParent,
36
+ subcommands: [createTypedCommand({
37
+ name: "sync",
38
+ description: "Install bundled Keystroke skills into selected agent skill directories",
39
+ schema: SkillsCommandOptionsSchema,
40
+ optionsConfig: SKILLS_OPTIONS_CONFIG,
41
+ loadHandler: async () => (await import("./skills-sync.handler-C4ztv1Vu.mjs")).handleSkillsSync
42
+ })]
43
+ });
44
+ cmd.enablePositionalOptions();
45
+ cmd.passThroughOptions();
46
+ return cmd;
47
+ }
48
+ //#endregion
49
+ export { createSkillsCommand };
@@ -3,7 +3,7 @@
3
3
  import { n as ui } from "./keystroke.mjs";
4
4
  //#region src/commands/skills/skills.handler.ts
5
5
  async function handleSkillsParent(_options, _ctx) {
6
- ui.hint("Run `keystroke skills sync` to copy @keystrokehq/skills into .cursor/skills and .claude/skills.");
6
+ ui.hint("Run `keystroke skills sync --agent claude-code --method symlink` to install bundled Keystroke skills for selected agents.");
7
7
  }
8
8
  //#endregion
9
9
  export { handleSkillsParent };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { t as createTypedCommand } from "./commander-i-7LgOyc.mjs";
3
+ import { t as createTypedCommand } from "./commander-D15UZVjp.mjs";
4
4
  import { z } from "zod";
5
5
  //#region src/commands/sync/sync.command.ts
6
6
  /**
@@ -32,7 +32,7 @@ function createSyncCommand() {
32
32
  description: "Sync local workflows with Keystroke",
33
33
  schema: SyncOptionsSchema,
34
34
  optionsConfig: SYNC_OPTIONS_CONFIG,
35
- loadHandler: async () => (await import("./sync.handler-Kk4R2lJ_.mjs")).handleSync
35
+ loadHandler: async () => (await import("./sync.handler-Be0U3x-n.mjs")).handleSync
36
36
  });
37
37
  }
38
38
  //#endregion
@@ -5,7 +5,7 @@ import { d as trackProject } from "./dist-BF6r1hfv.mjs";
5
5
  import { a as validateApiKey, i as requireClient } from "./context-B1L8pZsH.mjs";
6
6
  import { n as deployFromDir } from "./dist-FQYQ2FLm.mjs";
7
7
  import { t as requireWorkflowsDir } from "./resolve-project-CURYMjex.mjs";
8
- import { a as runWorkflowBuild, n as renderBuildFailure, r as renderBuildHeader } from "./workflow-build-kNNcU-R8.mjs";
8
+ import { a as runWorkflowBuild, n as renderBuildFailure, r as renderBuildHeader } from "./workflow-build-C9rQQ4qU.mjs";
9
9
  import { t as createBuildProgress } from "./build-progress-BZivcVz4.mjs";
10
10
  import { t as createDeployProgress } from "./deploy-progress-DJHph1Fz.mjs";
11
11
  //#region src/commands/sync/sync.handler.ts
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { t as readCredentialKeysFromSchemaObject } from "./read-credential-keys-77a91T8M-COvwpok_.mjs";
3
+ import { t as readCredentialKeysFromSchemaObject } from "./read-credential-keys-77a91T8M-DMmY6oDW.mjs";
4
4
  import { mkdir, writeFile } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
@@ -109,7 +109,7 @@ async function buildTaskTargetFile(options) {
109
109
  return builtTasks;
110
110
  }
111
111
  async function bundleTaskTargetModule(options) {
112
- const [{ rolldown }, { createEnvAccessPlugin, formatEnvAccessError }] = await Promise.all([import("rolldown"), import("./detect-env-access-CwkOYeYM-BLtKepjx.mjs").then((n) => n.n).then((n) => n.n)]);
112
+ const [{ rolldown }, { createEnvAccessPlugin, formatEnvAccessError }] = await Promise.all([import("rolldown"), import("./detect-env-access-CwkOYeYM-CZIixHeR.mjs").then((n) => n.n).then((n) => n.n)]);
113
113
  const entryId = "\0virtual:task-target-entry";
114
114
  const trackedDependencies = /* @__PURE__ */ new Set();
115
115
  const envViolations = [];
@@ -216,7 +216,7 @@ async function attachTaskTargetTriggers(options) {
216
216
  options.artifact.triggers.push(...buildTaskTriggerArtifactsWithoutBundles(options.entry.taskMetadata.triggers, options.artifact.task.taskId, options.artifact.task.taskName));
217
217
  return [];
218
218
  }
219
- const { buildTriggerArtifacts } = await import("./trigger-artifacts-RizI57RC-abdkW8-z.mjs").then((n) => n.n);
219
+ const { buildTriggerArtifacts } = await import("./trigger-artifacts-RizI57RC-CxHwCkQ_.mjs").then((n) => n.n);
220
220
  const triggerResult = await buildTriggerArtifacts(options.entry.taskMetadata.triggers, options.artifact.task.taskId, options.artifact.task.taskName, options.projectRoot, {
221
221
  workflowExportName: options.entry.source.localExportName,
222
222
  workflowFilePath: options.entry.runtimeBundlePath