@keystrokehq/cli 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/{auth-DS3C07ib.mjs → auth-D2vYD0E8.mjs} +1 -1
- package/dist/{auth.handler-CbhiLOG1.mjs → auth.handler-BFnFI2fQ.mjs} +1 -1
- package/dist/{init-CWFlBuxT.mjs → init-BXwx0QA4.mjs} +2 -7
- package/dist/{init.handler-HRdgViGH.mjs → init.handler-Cs5YXM5Z.mjs} +17 -128
- package/dist/keystroke.d.mts +0 -0
- package/dist/keystroke.mjs +4 -4
- package/dist/{skills-sync.handler-IB73kEeA.mjs → skills-sync.handler-CwwnzDiO.mjs} +3 -3
- package/dist/{skills.command-mMs4o12N.mjs → skills.command-C2NXqc5h.mjs} +4 -4
- package/dist/{skills.handler-JauTJV1C.mjs → skills.handler-BTUhxO37.mjs} +1 -1
- package/dist/{sync-keystroke-agent-skills-CY9h25_5.mjs → sync-keystroke-agent-skills-CBMQ4fh_.mjs} +8 -12
- package/dist/task-target-deploy-runner.d.mts +0 -0
- package/dist/task-target-deploy-runner.mjs +0 -0
- package/package.json +31 -32
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Keystroke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -25,7 +25,7 @@ function createAuthCommand() {
|
|
|
25
25
|
description: "Authenticate Keystroke CLI via device flow",
|
|
26
26
|
schema: AuthOptionsSchema,
|
|
27
27
|
optionsConfig: AUTH_OPTIONS_CONFIG,
|
|
28
|
-
loadHandler: async () => (await import("./auth.handler-
|
|
28
|
+
loadHandler: async () => (await import("./auth.handler-BFnFI2fQ.mjs")).handleAuth,
|
|
29
29
|
subcommands: [
|
|
30
30
|
createTypedCommand({
|
|
31
31
|
name: "clear",
|
|
@@ -23,7 +23,7 @@ const deviceAuthCallbackSuccessSchema = z.object({
|
|
|
23
23
|
organizationName: z.string().optional()
|
|
24
24
|
});
|
|
25
25
|
function createDeviceAuthState() {
|
|
26
|
-
return randomBytes(24).toString("
|
|
26
|
+
return randomBytes(24).toString("hex");
|
|
27
27
|
}
|
|
28
28
|
function buildDeviceAuthUrl(params) {
|
|
29
29
|
const authUrl = new URL(AUTH_URL_PATH, params.webUrl);
|
|
@@ -7,8 +7,7 @@ const InitOptionsSchema = z.object({
|
|
|
7
7
|
path: z.string().optional().describe("Directory to initialize (default: current directory)"),
|
|
8
8
|
name: z.string().optional().describe("Project name (skips prompt; default: directory basename)"),
|
|
9
9
|
description: z.string().optional().describe("Project description for the API (skips prompt when creating a new project)"),
|
|
10
|
-
scaffold: z.boolean().default(true).describe("Scaffold project files (package.json, vitest.config.ts, etc.)")
|
|
11
|
-
install: z.boolean().default(true).describe("Run package manager install after scaffolding (when scaffold is enabled)")
|
|
10
|
+
scaffold: z.boolean().default(true).describe("Scaffold project files (package.json, vitest.config.ts, etc.)")
|
|
12
11
|
});
|
|
13
12
|
const INIT_OPTIONS_CONFIG = {
|
|
14
13
|
path: {
|
|
@@ -26,10 +25,6 @@ const INIT_OPTIONS_CONFIG = {
|
|
|
26
25
|
scaffold: {
|
|
27
26
|
flag: "--no-scaffold",
|
|
28
27
|
description: "Skip scaffolding project files (package.json, vitest.config.ts, etc.)"
|
|
29
|
-
},
|
|
30
|
-
install: {
|
|
31
|
-
flag: "--no-install",
|
|
32
|
-
description: "Skip running package manager install after scaffolding"
|
|
33
28
|
}
|
|
34
29
|
};
|
|
35
30
|
function createInitCommand() {
|
|
@@ -38,7 +33,7 @@ function createInitCommand() {
|
|
|
38
33
|
description: "Initialize a Keystroke project (creates keystroke.config.ts)",
|
|
39
34
|
schema: InitOptionsSchema,
|
|
40
35
|
optionsConfig: INIT_OPTIONS_CONFIG,
|
|
41
|
-
loadHandler: async () => (await import("./init.handler-
|
|
36
|
+
loadHandler: async () => (await import("./init.handler-Cs5YXM5Z.mjs")).handleInit
|
|
42
37
|
});
|
|
43
38
|
}
|
|
44
39
|
//#endregion
|
|
@@ -4,36 +4,20 @@ import { C as CliExitError, t as ui } from "./keystroke.mjs";
|
|
|
4
4
|
import { d as trackProject } from "./dist-BF6r1hfv.mjs";
|
|
5
5
|
import { a as writeProjectConfig, i as readProjectConfig, r as getProjectConfigPath } from "./project-config-opj6DsPF.mjs";
|
|
6
6
|
import { i as requireClient } from "./context-D-YKFNxL.mjs";
|
|
7
|
-
import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-
|
|
7
|
+
import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-CBMQ4fh_.mjs";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
|
-
import {
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
10
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
11
11
|
import * as path$1 from "node:path";
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { cancel, isCancel, text } from "@clack/prompts";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Default local registry for consumer projects (Verdaccio default port).
|
|
19
|
-
* Override with `KEYSTROKE_LOCAL_NPM_REGISTRY` when publishing or documenting for authors.
|
|
20
|
-
*/
|
|
21
|
-
function getKeystrokeLocalNpmRegistryUrl() {
|
|
22
|
-
const raw = process.env.KEYSTROKE_LOCAL_NPM_REGISTRY?.trim();
|
|
23
|
-
if (!raw) return "http://localhost:4873/";
|
|
24
|
-
return `${raw.replace(/\/+$/, "")}/`;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* `.npmrc` line so installs resolve `@keystroke/*` from the local registry (Verdaccio).
|
|
28
|
-
*/
|
|
29
|
-
function createKeystrokeLocalRegistryNpmrcContent() {
|
|
30
|
-
return `@keystroke:registry=${getKeystrokeLocalNpmRegistryUrl()}\n`;
|
|
31
|
-
}
|
|
32
|
-
/** When the CLI cannot resolve `@keystrokehq/core` on disk (e.g. unusual installs). */
|
|
15
|
+
//#region src/lib/keystroke-scaffold-version-ranges.ts
|
|
16
|
+
/** When the CLI cannot resolve `@keystrokehq/core` on disk (e.g. bundled installs). */
|
|
33
17
|
const FALLBACK_WORKFLOW_CORE_VERSION_RANGE = "^0.0.1";
|
|
34
18
|
/**
|
|
35
19
|
* Semver range for scaffold `package.json` — uses the version of `@keystrokehq/core`
|
|
36
|
-
* installed next to this CLI
|
|
20
|
+
* installed next to this CLI when available.
|
|
37
21
|
*/
|
|
38
22
|
function workflowCoreScaffoldVersionRange() {
|
|
39
23
|
try {
|
|
@@ -43,19 +27,6 @@ function workflowCoreScaffoldVersionRange() {
|
|
|
43
27
|
} catch {}
|
|
44
28
|
return FALLBACK_WORKFLOW_CORE_VERSION_RANGE;
|
|
45
29
|
}
|
|
46
|
-
/** When the CLI cannot resolve `@keystroke/skills` on disk. */
|
|
47
|
-
const FALLBACK_SKILLS_VERSION_RANGE = "^0.0.1";
|
|
48
|
-
/**
|
|
49
|
-
* Semver range for scaffold `package.json` devDependency `@keystroke/skills` (published to local Verdaccio).
|
|
50
|
-
*/
|
|
51
|
-
function keystrokeSkillsScaffoldVersionRange() {
|
|
52
|
-
try {
|
|
53
|
-
const raw = readFileSync(createRequire(import.meta.url).resolve("@keystroke/skills/package.json"), "utf-8");
|
|
54
|
-
const version = JSON.parse(raw).version?.trim();
|
|
55
|
-
if (version) return `^${version}`;
|
|
56
|
-
} catch {}
|
|
57
|
-
return FALLBACK_SKILLS_VERSION_RANGE;
|
|
58
|
-
}
|
|
59
30
|
//#endregion
|
|
60
31
|
//#region src/commands/init/agents-md.ts
|
|
61
32
|
const AGENTS_FILENAME = "AGENTS.md";
|
|
@@ -76,7 +47,7 @@ function resolveCliPackageSkillsBlurbPath() {
|
|
|
76
47
|
function resolveBundledKeystrokeAgentsBlurbPath() {
|
|
77
48
|
const require = createRequire(import.meta.url);
|
|
78
49
|
try {
|
|
79
|
-
const skillsPackageJsonPath = require.resolve("@
|
|
50
|
+
const skillsPackageJsonPath = require.resolve("@keystrokehq/skills/package.json");
|
|
80
51
|
return path$1.join(path$1.dirname(skillsPackageJsonPath), AGENTS_BLURB_PACKAGE_PATH);
|
|
81
52
|
} catch {}
|
|
82
53
|
try {
|
|
@@ -237,9 +208,6 @@ describe('hello workflow', () => {
|
|
|
237
208
|
//#region src/commands/init/templates/package-json.ts
|
|
238
209
|
/**
|
|
239
210
|
* Template for generating a package.json for a new Keystroke project.
|
|
240
|
-
*
|
|
241
|
-
* `@keystrokehq/core` uses a semver range; installs resolve via `.npmrc` → local Verdaccio
|
|
242
|
-
* (see `pnpm publish:local` from the Keystroke monorepo).
|
|
243
211
|
*/
|
|
244
212
|
function createPackageJsonContent(projectName, options) {
|
|
245
213
|
return JSON.stringify({
|
|
@@ -256,7 +224,6 @@ function createPackageJsonContent(projectName, options) {
|
|
|
256
224
|
zod: "^4.3.6"
|
|
257
225
|
},
|
|
258
226
|
devDependencies: {
|
|
259
|
-
"@keystroke/skills": options.skillsVersionRange,
|
|
260
227
|
"@biomejs/biome": "2.4.13",
|
|
261
228
|
vitest: "^4.0.18",
|
|
262
229
|
typescript: "^5.9.3"
|
|
@@ -359,40 +326,22 @@ async function promptProjectDescription(options) {
|
|
|
359
326
|
const t = typeof answer === "string" ? answer.trim() : "";
|
|
360
327
|
return t.length > 0 ? t : void 0;
|
|
361
328
|
}
|
|
362
|
-
async function ensureScaffoldPackageJson(targetDir, projectName,
|
|
329
|
+
async function ensureScaffoldPackageJson(targetDir, projectName, workflowCoreRange) {
|
|
363
330
|
const pkgPath = path.join(targetDir, "package.json");
|
|
364
331
|
try {
|
|
365
332
|
const raw = await readFile(pkgPath, "utf-8");
|
|
366
333
|
const pkg = JSON.parse(raw);
|
|
367
334
|
pkg.dependencies = pkg.dependencies ?? {};
|
|
368
|
-
pkg.dependencies["@keystrokehq/core"] =
|
|
335
|
+
pkg.dependencies["@keystrokehq/core"] = workflowCoreRange;
|
|
369
336
|
pkg.dependencies.zod = pkg.dependencies.zod ?? "^4.3.6";
|
|
370
337
|
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
371
|
-
pkg.devDependencies["@keystroke/skills"] = ranges.skills;
|
|
372
338
|
pkg.devDependencies.vitest = pkg.devDependencies.vitest ?? "^4.0.18";
|
|
373
339
|
pkg.devDependencies.typescript = pkg.devDependencies.typescript ?? "^5.9.3";
|
|
374
340
|
if (!pkg.name) pkg.name = projectName;
|
|
375
341
|
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
|
|
376
342
|
return "updated";
|
|
377
343
|
} catch {
|
|
378
|
-
await writeFile(pkgPath, `${createPackageJsonContent(projectName, {
|
|
379
|
-
workflowCoreVersionRange: ranges.workflowCore,
|
|
380
|
-
skillsVersionRange: ranges.skills
|
|
381
|
-
})}\n`, "utf-8");
|
|
382
|
-
return "created";
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
/** Ensure `.npmrc` sends `@keystroke/*` to the local Verdaccio registry. */
|
|
386
|
-
async function ensureKeystrokeLocalRegistryNpmrc(targetDir) {
|
|
387
|
-
const npmrcPath = path.join(targetDir, ".npmrc");
|
|
388
|
-
const line = createKeystrokeLocalRegistryNpmrcContent().trimEnd();
|
|
389
|
-
try {
|
|
390
|
-
const existing = await readFile(npmrcPath, "utf-8");
|
|
391
|
-
if (existing.split(/\r?\n/).some((l) => l.trim().startsWith("@keystroke:registry="))) return "skipped";
|
|
392
|
-
await writeFile(npmrcPath, existing.trimEnd().length > 0 ? `${existing.trimEnd()}\n${line}\n` : `${line}\n`, "utf-8");
|
|
393
|
-
return "updated";
|
|
394
|
-
} catch {
|
|
395
|
-
await writeFile(npmrcPath, createKeystrokeLocalRegistryNpmrcContent(), "utf-8");
|
|
344
|
+
await writeFile(pkgPath, `${createPackageJsonContent(projectName, { workflowCoreVersionRange: workflowCoreRange })}\n`, "utf-8");
|
|
396
345
|
return "created";
|
|
397
346
|
}
|
|
398
347
|
}
|
|
@@ -447,7 +396,7 @@ async function handleInit(options, ctx) {
|
|
|
447
396
|
const agentsAction = await ensureAgentsMarkdown(targetDir, await loadKeystrokeAgentsBlurb());
|
|
448
397
|
if (agentsAction === "created") ui.success("Created AGENTS.md with Keystroke project guidance.");
|
|
449
398
|
else if (agentsAction === "updated") ui.success("Updated AGENTS.md with Keystroke project guidance.");
|
|
450
|
-
if (options.scaffold) await scaffoldProject(targetDir, projectName, workflowCoreScaffoldVersionRange()
|
|
399
|
+
if (options.scaffold) await scaffoldProject(targetDir, projectName, workflowCoreScaffoldVersionRange());
|
|
451
400
|
}
|
|
452
401
|
/** Write a file only if it does not already exist. Returns true if written. */
|
|
453
402
|
async function writeIfMissing(filePath, content) {
|
|
@@ -459,54 +408,15 @@ async function writeIfMissing(filePath, content) {
|
|
|
459
408
|
return true;
|
|
460
409
|
}
|
|
461
410
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Detect package manager from lockfiles. New projects (no lockfile) default to **pnpm** so `keystroke init`
|
|
464
|
-
* matches the Keystroke monorepo toolchain.
|
|
465
|
-
*/
|
|
466
|
-
function detectPackageManager(targetDir) {
|
|
467
|
-
try {
|
|
468
|
-
accessSync(path.join(targetDir, "pnpm-lock.yaml"));
|
|
469
|
-
return "pnpm";
|
|
470
|
-
} catch {}
|
|
471
|
-
try {
|
|
472
|
-
accessSync(path.join(targetDir, "yarn.lock"));
|
|
473
|
-
return "yarn";
|
|
474
|
-
} catch {}
|
|
475
|
-
try {
|
|
476
|
-
accessSync(path.join(targetDir, "package-lock.json"));
|
|
477
|
-
return "npm";
|
|
478
|
-
} catch {}
|
|
479
|
-
return "pnpm";
|
|
480
|
-
}
|
|
481
|
-
/** Run install in targetDir. Returns true if succeeded. */
|
|
482
|
-
function runInstall(targetDir) {
|
|
483
|
-
const pm = detectPackageManager(targetDir);
|
|
484
|
-
const [cmd, ...args] = pm === "pnpm" ? ["pnpm", "install"] : pm === "yarn" ? ["yarn", "install"] : ["npm", "install"];
|
|
485
|
-
return new Promise((resolve) => {
|
|
486
|
-
spawn(cmd, args, {
|
|
487
|
-
cwd: targetDir,
|
|
488
|
-
stdio: "inherit",
|
|
489
|
-
shell: true
|
|
490
|
-
}).on("close", (code) => resolve(code === 0));
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
411
|
async function trySyncAgentSkillsAfterScaffold(targetDir) {
|
|
494
412
|
const syncResult = await syncKeystrokeAgentSkills(targetDir);
|
|
495
413
|
if (syncResult.ok) ui.success(`Synced ${syncResult.copied.length} skill(s) to .cursor/skills and .claude/skills: ${syncResult.copied.join(", ")}`);
|
|
496
|
-
else if (syncResult.reason === "not_installed") ui.hint("After install completes, run `keystroke skills sync` to copy @
|
|
497
|
-
else ui.warn(`@
|
|
414
|
+
else if (syncResult.reason === "not_installed") ui.hint("After install completes, run `keystroke skills sync` to copy @keystrokehq/skills for Cursor / Claude Code.");
|
|
415
|
+
else ui.warn(`@keystrokehq/skills is installed at ${syncResult.packageRoot} but no skill directories with SKILL.md were found.`);
|
|
498
416
|
}
|
|
499
|
-
async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange
|
|
500
|
-
const pkgAction = await ensureScaffoldPackageJson(targetDir, projectName,
|
|
501
|
-
|
|
502
|
-
skills: skillsVersionRange
|
|
503
|
-
});
|
|
504
|
-
ui.success(pkgAction === "created" ? `Created package.json (@keystrokehq/core ${workflowCoreVersionRange}, @keystroke/skills ${skillsVersionRange})` : `Updated package.json (Keystroke deps → core ${workflowCoreVersionRange}, skills ${skillsVersionRange})`);
|
|
505
|
-
const registryUrl = getKeystrokeLocalNpmRegistryUrl();
|
|
506
|
-
const npmrcAction = await ensureKeystrokeLocalRegistryNpmrc(targetDir);
|
|
507
|
-
if (npmrcAction === "created") ui.success(`Created .npmrc (@keystroke → local registry ${registryUrl.trim()})`);
|
|
508
|
-
else if (npmrcAction === "updated") ui.success("Updated .npmrc with @keystroke registry line");
|
|
509
|
-
ui.hint("Before install: run Verdaccio (e.g. pnpm dlx verdaccio), then from the Keystroke repo: pnpm publish:local");
|
|
417
|
+
async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange) {
|
|
418
|
+
const pkgAction = await ensureScaffoldPackageJson(targetDir, projectName, workflowCoreVersionRange);
|
|
419
|
+
ui.success(pkgAction === "created" ? `Created package.json (@keystrokehq/core ${workflowCoreVersionRange})` : `Updated package.json (Keystroke deps -> core ${workflowCoreVersionRange})`);
|
|
510
420
|
const files = [
|
|
511
421
|
{
|
|
512
422
|
rel: "vitest.config.ts",
|
|
@@ -557,29 +467,8 @@ async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange,
|
|
|
557
467
|
}
|
|
558
468
|
if (created.length > 0) ui.success(`Scaffolded ${created.length} file(s): ${created.join(", ")}`);
|
|
559
469
|
else ui.hint("Scaffold files already exist — skipped (package.json was still updated).");
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
try {
|
|
563
|
-
await access(pkgJsonPath);
|
|
564
|
-
} catch {
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
ui.hint("Running install...");
|
|
568
|
-
const ok = await runInstall(targetDir);
|
|
569
|
-
const pm = detectPackageManager(targetDir);
|
|
570
|
-
const testCmd = pm === "pnpm" ? "pnpm test" : pm === "yarn" ? "yarn test" : "npm test";
|
|
571
|
-
if (ok) {
|
|
572
|
-
ui.success("Dependencies installed.");
|
|
573
|
-
await trySyncAgentSkillsAfterScaffold(targetDir);
|
|
574
|
-
ui.hint(`Run \`${testCmd}\` to run tests.`);
|
|
575
|
-
} else {
|
|
576
|
-
ui.warn("Install failed. Run your package manager install manually.");
|
|
577
|
-
await trySyncAgentSkillsAfterScaffold(targetDir);
|
|
578
|
-
}
|
|
579
|
-
} else {
|
|
580
|
-
ui.hint("Run `pnpm install`, then `pnpm test` to run tests (or use your lockfile’s package manager).");
|
|
581
|
-
await trySyncAgentSkillsAfterScaffold(targetDir);
|
|
582
|
-
}
|
|
470
|
+
ui.hint("Run `pnpm install` to install dependencies, then `pnpm test` to run tests (or use your lockfile's package manager).");
|
|
471
|
+
await trySyncAgentSkillsAfterScaffold(targetDir);
|
|
583
472
|
}
|
|
584
473
|
//#endregion
|
|
585
474
|
export { handleInit };
|
package/dist/keystroke.d.mts
CHANGED
|
File without changes
|
package/dist/keystroke.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import * as path$1 from "node:path";
|
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { log } from "@clack/prompts";
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "0.0.
|
|
12
|
+
var version = "0.0.7";
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/command-registry.ts
|
|
15
15
|
const ROOT_OPTIONS_WITH_VALUES = new Set([
|
|
@@ -33,7 +33,7 @@ const lazyCommandDefinitions = [
|
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
name: "auth",
|
|
36
|
-
loadCommand: async () => (await import("./auth-
|
|
36
|
+
loadCommand: async () => (await import("./auth-D2vYD0E8.mjs")).createAuthCommand()
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
name: "connect",
|
|
@@ -54,7 +54,7 @@ const lazyCommandDefinitions = [
|
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
name: "init",
|
|
57
|
-
loadCommand: async () => (await import("./init-
|
|
57
|
+
loadCommand: async () => (await import("./init-BXwx0QA4.mjs")).createInitCommand()
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: "integrations",
|
|
@@ -82,7 +82,7 @@ const lazyCommandDefinitions = [
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
name: "skills",
|
|
85
|
-
loadCommand: async () => (await import("./skills.command-
|
|
85
|
+
loadCommand: async () => (await import("./skills.command-C2NXqc5h.mjs")).createSkillsCommand()
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
name: "sync",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { C as CliExitError, t as ui } from "./keystroke.mjs";
|
|
4
4
|
import { i as writeJson, r as isJsonMode } from "./output-q4KljAhu.mjs";
|
|
5
|
-
import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-
|
|
5
|
+
import { t as syncKeystrokeAgentSkills } from "./sync-keystroke-agent-skills-CBMQ4fh_.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) {
|
|
@@ -27,8 +27,8 @@ async function handleSkillsSync(options, _ctx) {
|
|
|
27
27
|
ui.success(`Synced ${result.copied.length} skill(s) to .cursor/skills and .claude/skills: ${result.copied.join(", ")}`);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
if (result.reason === "not_installed") throw new CliExitError("Could not resolve @
|
|
31
|
-
ui.warn(`@
|
|
30
|
+
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 });
|
|
31
|
+
ui.warn(`@keystrokehq/skills is installed at ${result.packageRoot} but no skill directories with SKILL.md were found.`);
|
|
32
32
|
}
|
|
33
33
|
//#endregion
|
|
34
34
|
export { handleSkillsSync };
|
|
@@ -15,16 +15,16 @@ const SKILLS_OPTIONS_CONFIG = {
|
|
|
15
15
|
function createSkillsCommand() {
|
|
16
16
|
const cmd = createTypedCommand({
|
|
17
17
|
name: "skills",
|
|
18
|
-
description: "Sync Keystroke agent skills (SKILL.md) from @
|
|
18
|
+
description: "Sync Keystroke agent skills (SKILL.md) from @keystrokehq/skills",
|
|
19
19
|
schema: SkillsCommandOptionsSchema,
|
|
20
20
|
optionsConfig: SKILLS_OPTIONS_CONFIG,
|
|
21
|
-
loadHandler: async () => (await import("./skills.handler-
|
|
21
|
+
loadHandler: async () => (await import("./skills.handler-BTUhxO37.mjs")).handleSkillsParent,
|
|
22
22
|
subcommands: [createTypedCommand({
|
|
23
23
|
name: "sync",
|
|
24
|
-
description: "Copy installed @
|
|
24
|
+
description: "Copy installed @keystrokehq/skills into .cursor/skills and .claude/skills",
|
|
25
25
|
schema: SkillsCommandOptionsSchema,
|
|
26
26
|
optionsConfig: SKILLS_OPTIONS_CONFIG,
|
|
27
|
-
loadHandler: async () => (await import("./skills-sync.handler-
|
|
27
|
+
loadHandler: async () => (await import("./skills-sync.handler-CwwnzDiO.mjs")).handleSkillsSync
|
|
28
28
|
})]
|
|
29
29
|
});
|
|
30
30
|
cmd.enablePositionalOptions();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { t 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 @
|
|
6
|
+
ui.hint("Run `keystroke skills sync` to copy @keystrokehq/skills into .cursor/skills and .claude/skills.");
|
|
7
7
|
}
|
|
8
8
|
//#endregion
|
|
9
9
|
export { handleSkillsParent };
|
package/dist/{sync-keystroke-agent-skills-CY9h25_5.mjs → sync-keystroke-agent-skills-CBMQ4fh_.mjs}
RENAMED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import { access, cp, mkdir, readdir } from "node:fs/promises";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
//#region src/lib/sync-keystroke-agent-skills.ts
|
|
6
7
|
/**
|
|
7
|
-
* Resolve the
|
|
8
|
-
*
|
|
9
|
-
* Only checks `projectDir/node_modules/@keystroke/skills` (pnpm symlinks that path; npm/yarn lay out
|
|
10
|
-
* the same). We intentionally do not walk ancestor directories — that avoids resolving a
|
|
11
|
-
* unrelated workspace copy when TMPDIR or the project lives inside another repo.
|
|
8
|
+
* Resolve the `@keystrokehq/skills` package root from the CLI's own node_modules.
|
|
9
|
+
* Skills are distributed with the CLI release, so no npm install is needed.
|
|
12
10
|
*/
|
|
13
|
-
async function resolveKeystrokeSkillsPackageRoot(
|
|
14
|
-
const root = path.resolve(projectDir);
|
|
15
|
-
const marker = path.join(root, "node_modules", "@keystroke", "skills", "package.json");
|
|
11
|
+
async function resolveKeystrokeSkillsPackageRoot() {
|
|
16
12
|
try {
|
|
17
|
-
|
|
18
|
-
return path.dirname(
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
return path.dirname(require.resolve("@keystrokehq/skills/package.json"));
|
|
19
15
|
} catch {
|
|
20
16
|
return null;
|
|
21
17
|
}
|
|
@@ -34,11 +30,11 @@ async function listKeystrokeSkillDirectoryNames(skillsPackageRoot) {
|
|
|
34
30
|
return names.sort();
|
|
35
31
|
}
|
|
36
32
|
/**
|
|
37
|
-
* Copy each skill directory from
|
|
33
|
+
* Copy each skill directory from the resolved `@keystrokehq/skills` package into
|
|
38
34
|
* `.cursor/skills` and `.claude/skills` under `projectDir`.
|
|
39
35
|
*/
|
|
40
36
|
async function syncKeystrokeAgentSkills(projectDir) {
|
|
41
|
-
const packageRoot = await resolveKeystrokeSkillsPackageRoot(
|
|
37
|
+
const packageRoot = await resolveKeystrokeSkillsPackageRoot();
|
|
42
38
|
if (!packageRoot) return {
|
|
43
39
|
ok: false,
|
|
44
40
|
reason: "not_installed"
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keystrokehq/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Command-line interface for creating, managing, and deploying Keystroke automations.",
|
|
6
6
|
"type": "module",
|
|
@@ -22,46 +22,34 @@
|
|
|
22
22
|
"dist",
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"dev:cli": "pnpm run build && node bin/keystroke.mjs",
|
|
27
|
-
"typecheck": "tsgo --build",
|
|
28
|
-
"build": "tsdown",
|
|
29
|
-
"check:command-imports": "node scripts/check-command-imports.mjs",
|
|
30
|
-
"dev:install-pack": "pnpm run build && node scripts/install-dev-pack.mjs",
|
|
31
|
-
"smoke:pack": "pnpm run build && node scripts/smoke-pack.mjs",
|
|
32
|
-
"lint": "biome check --write .",
|
|
33
|
-
"test:unit": "vitest run --passWithNoTests --project unit",
|
|
34
|
-
"test:int": "vitest run --passWithNoTests --project int",
|
|
35
|
-
"prepublishOnly": "pnpm run build && pnpm run test:unit"
|
|
36
|
-
},
|
|
37
25
|
"dependencies": {
|
|
38
26
|
"@clack/prompts": "^1.2.0",
|
|
39
27
|
"cli-table3": "^0.6.5",
|
|
40
28
|
"commander": "^14.0.3",
|
|
41
|
-
"dayjs": "
|
|
42
|
-
"dotenv": "
|
|
29
|
+
"dayjs": "^1.11.20",
|
|
30
|
+
"dotenv": "^17.4.2",
|
|
43
31
|
"ky": "^1.14.3",
|
|
44
32
|
"oxc-parser": "^0.128.0",
|
|
45
33
|
"rolldown": "1.0.0-rc.17",
|
|
46
34
|
"tsx": "^4.21.0",
|
|
47
|
-
"zod": "
|
|
35
|
+
"zod": "^4.3.6",
|
|
36
|
+
"@keystrokehq/skills": "0.0.1"
|
|
48
37
|
},
|
|
49
38
|
"devDependencies": {
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"@keystroke/
|
|
54
|
-
"@keystroke/
|
|
55
|
-
"@keystroke/
|
|
56
|
-
"@keystroke/
|
|
57
|
-
"@keystroke/utils": "
|
|
58
|
-
"@keystroke/
|
|
59
|
-
"@
|
|
60
|
-
"@keystroke/workflow-
|
|
61
|
-
"@
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"vitest": "catalog:"
|
|
39
|
+
"tsdown": "0.21.10",
|
|
40
|
+
"typescript": "^5.9.3",
|
|
41
|
+
"vitest": "^4.1.5",
|
|
42
|
+
"@keystroke/env-utils": "0.0.0",
|
|
43
|
+
"@keystroke/local-memory": "0.0.0",
|
|
44
|
+
"@keystroke/project-config": "0.0.1",
|
|
45
|
+
"@keystroke/shared-types": "0.0.1",
|
|
46
|
+
"@keystroke/test-utils": "0.0.0",
|
|
47
|
+
"@keystroke/utils": "0.0.0",
|
|
48
|
+
"@keystroke/typescript-config": "0.0.0",
|
|
49
|
+
"@keystroke/workflow-builder": "0.0.2",
|
|
50
|
+
"@keystrokehq/core": "0.0.4",
|
|
51
|
+
"@keystroke/workflow-deploy": "0.0.1",
|
|
52
|
+
"@keystroke/workflow-sdk": "0.0.0"
|
|
65
53
|
},
|
|
66
54
|
"keywords": [
|
|
67
55
|
"automation",
|
|
@@ -82,5 +70,16 @@
|
|
|
82
70
|
"publishConfig": {
|
|
83
71
|
"access": "public",
|
|
84
72
|
"registry": "https://registry.npmjs.org/"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"dev:cli": "pnpm run build && node bin/keystroke.mjs",
|
|
76
|
+
"typecheck": "tsgo --build",
|
|
77
|
+
"build": "tsdown",
|
|
78
|
+
"check:command-imports": "node scripts/check-command-imports.mjs",
|
|
79
|
+
"dev:install-pack": "pnpm run build && node scripts/install-dev-pack.mjs",
|
|
80
|
+
"smoke:pack": "pnpm run build && node scripts/smoke-pack.mjs",
|
|
81
|
+
"lint": "biome check --write .",
|
|
82
|
+
"test:unit": "vitest run --passWithNoTests --project unit",
|
|
83
|
+
"test:int": "vitest run --passWithNoTests --project int"
|
|
85
84
|
}
|
|
86
|
-
}
|
|
85
|
+
}
|