@keystrokehq/cli 0.0.30 → 0.0.32
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/README.md +36 -2
- package/dist/{credentials-LmhgE-Co.mjs → credentials-CsncZ52a.mjs} +1 -1
- package/dist/{init-DX08T87c.mjs → init-BOCDwqKR.mjs} +6 -1
- package/dist/{init.handler-CzlmkNXi.mjs → init.handler-B3T4J6u_.mjs} +55 -12
- package/dist/{integrations-MEExmqcg.mjs → integrations-m7_tb3GV.mjs} +4 -4
- package/dist/keystroke.mjs +7 -7
- package/dist/{list.handler-BKfGLkFu.mjs → list.handler-DbYUk6ko.mjs} +2 -2
- package/dist/{operations-wXS1s3du.mjs → operations-CF2nUiBs.mjs} +4 -4
- package/dist/package-manager-CvY4IW7X.mjs +137 -0
- package/dist/{render-operation-Bc7Wu1sP.mjs → render-operation-DWbMwhfc.mjs} +1 -1
- package/dist/{search-BEfy2fG9.mjs → search-CA0J5NOY.mjs} +1 -1
- package/dist/{search.handler-V7ObLGjN.mjs → search.handler-BVDsYZlJ.mjs} +2 -2
- package/dist/{show.handler-Wmv0tkxx.mjs → show.handler-CwwnCmbp.mjs} +2 -2
- package/dist/{show.handler-C_VDYU91.mjs → show.handler-nkK6Erbb.mjs} +1 -1
- package/dist/{skills-sync.handler-BAATdT6N.mjs → skills-sync.handler-yRmi3OgP.mjs} +1 -1
- package/dist/{skills.command-0-E8mcYE.mjs → skills.command-COYd3k4Z.mjs} +1 -1
- package/package.json +5 -5
- package/dist/package-manager-DT1EhOkS.mjs +0 -61
- /package/dist/{list.handler-Jk_vK66s.mjs → list.handler-CMRQKH4b.mjs} +0 -0
- /package/dist/{register.handler-CePNU3sP.mjs → register.handler-CKMZ2WmD.mjs} +0 -0
- /package/dist/{skill-installer-D6j9IA3Z.mjs → skill-installer-DG8kTaQR.mjs} +0 -0
package/README.md
CHANGED
|
@@ -89,8 +89,10 @@ keystroke --api-key sk_... --server-url https://api.example.com workflows list
|
|
|
89
89
|
| `keystroke test` | Test agent-callable tools. |
|
|
90
90
|
| `keystroke connect` | Connect official integrations through OAuth. |
|
|
91
91
|
| `keystroke listen` | Create a temporary URL and print the first captured request body. |
|
|
92
|
-
| `keystroke
|
|
93
|
-
| `keystroke
|
|
92
|
+
| `keystroke search` | Ranked discovery across operations, integrations, or credential definitions. |
|
|
93
|
+
| `keystroke operations` | List and show operations (catalog metadata, including JSON schemas). |
|
|
94
|
+
| `keystroke integrations` | List integrations; `integrations show` returns one integration and its operations. |
|
|
95
|
+
| `keystroke credentials` | Per-org credential sets, requirements, and upload. Use `credentials definitions` for catalog auth shapes. |
|
|
94
96
|
| `keystroke org` | View and switch organization context. |
|
|
95
97
|
| `keystroke projects` | List or clear locally tracked projects. |
|
|
96
98
|
| `keystroke runs inspect` | Inspect workflow and agent runs. |
|
|
@@ -174,6 +176,37 @@ The relevant configuration sources are:
|
|
|
174
176
|
|
|
175
177
|
Use `--debug` on any command to show diagnostic output.
|
|
176
178
|
|
|
179
|
+
## Catalog discovery
|
|
180
|
+
|
|
181
|
+
Discovery commands call the server catalog API via `@keystroke/workflow-sdk`. They require the same auth as deploy: API key plus organization context.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
export KEYSTROKE_API_KEY=sk_...
|
|
185
|
+
export KEYSTROKE_ORG_ID=<your-org-uuid>
|
|
186
|
+
export SERVER_URL=http://localhost:3001 # local API (port 3001, not the web app on 3000)
|
|
187
|
+
|
|
188
|
+
keystroke search "put object"
|
|
189
|
+
keystroke search "slack" --type integrations
|
|
190
|
+
keystroke search "oauth" --type credentials --integration keystroke:slack
|
|
191
|
+
|
|
192
|
+
keystroke operations list --integration aws-s3
|
|
193
|
+
keystroke operations show aws-s3.put-object
|
|
194
|
+
keystroke operations show aws-s3.put-object --schema --json
|
|
195
|
+
|
|
196
|
+
keystroke integrations list
|
|
197
|
+
keystroke integrations show keystroke:slack # bare `slack` also works today
|
|
198
|
+
|
|
199
|
+
keystroke credentials definitions list --role connection
|
|
200
|
+
keystroke credentials definitions show keystroke:aws-s3
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Flags shared across discovery commands:
|
|
204
|
+
|
|
205
|
+
- `--json` — machine-readable output (field names match shared-types schemas).
|
|
206
|
+
- `--full` on `search`, `operations list`, and `credentials definitions list` — pass `include=full` for schemas and extended fields in one round-trip.
|
|
207
|
+
|
|
208
|
+
`keystroke credentials list` lists **your organization's credential sets**, not catalog definitions.
|
|
209
|
+
|
|
177
210
|
## Integrations And Credentials
|
|
178
211
|
|
|
179
212
|
Connect an OAuth integration:
|
|
@@ -188,6 +221,7 @@ Inspect integration and credential state:
|
|
|
188
221
|
|
|
189
222
|
```bash
|
|
190
223
|
keystroke integrations list
|
|
224
|
+
keystroke credentials definitions list --role connection
|
|
191
225
|
keystroke credentials requirements --path .
|
|
192
226
|
keystroke credentials list
|
|
193
227
|
```
|
|
@@ -279,7 +279,7 @@ function createCredentialsDefinitionsCommand() {
|
|
|
279
279
|
optionsConfig: DEFINITION_SHOW_OPTIONS_CONFIG,
|
|
280
280
|
argument: {
|
|
281
281
|
name: "id",
|
|
282
|
-
description: "Credential definition id, e.g.
|
|
282
|
+
description: "Credential definition id, e.g. keystroke:aws-s3",
|
|
283
283
|
key: "id"
|
|
284
284
|
},
|
|
285
285
|
loadHandler: async () => (await import("./show.handler-CsidInW8.mjs")).handleCredentialDefinitionShow
|
|
@@ -9,6 +9,7 @@ const InitOptionsSchema = z.object({
|
|
|
9
9
|
name: z.string().optional().describe("Project name (skips prompt; default: directory basename)"),
|
|
10
10
|
description: z.string().optional().describe("Project description for the API (skips prompt when creating a new project)"),
|
|
11
11
|
scaffold: z.boolean().default(true).describe("Scaffold project files (package.json, vitest.config.ts, etc.)"),
|
|
12
|
+
install: z.boolean().default(true).describe("Install scaffold dependencies after writing project files"),
|
|
12
13
|
agent: z.array(z.string()).optional().describe("Agent target to install Keystroke skills for. Repeat for multiple agents; '*' selects all."),
|
|
13
14
|
method: z.enum(SKILL_INSTALL_METHODS).optional().describe("Skill install method for agent-specific targets")
|
|
14
15
|
});
|
|
@@ -29,6 +30,10 @@ const INIT_OPTIONS_CONFIG = {
|
|
|
29
30
|
flag: "--no-scaffold",
|
|
30
31
|
description: "Skip scaffolding project files (package.json, vitest.config.ts, etc.)"
|
|
31
32
|
},
|
|
33
|
+
install: {
|
|
34
|
+
flag: "--no-install",
|
|
35
|
+
description: "Skip installing scaffold dependencies after writing project files"
|
|
36
|
+
},
|
|
32
37
|
agent: {
|
|
33
38
|
flag: "--agent <agent>",
|
|
34
39
|
description: "Install Keystroke skills for an agent target. Repeat for multiple agents; '*' selects all.",
|
|
@@ -45,7 +50,7 @@ function createInitCommand() {
|
|
|
45
50
|
description: "Initialize a Keystroke project (creates keystroke.config.ts)",
|
|
46
51
|
schema: InitOptionsSchema,
|
|
47
52
|
optionsConfig: INIT_OPTIONS_CONFIG,
|
|
48
|
-
loadHandler: async () => (await import("./init.handler-
|
|
53
|
+
loadHandler: async () => (await import("./init.handler-B3T4J6u_.mjs")).handleInit
|
|
49
54
|
});
|
|
50
55
|
}
|
|
51
56
|
//#endregion
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { D as CliExitError, a as ui, i as fetchLatestNpmPackageVersion } from "./keystroke.mjs";
|
|
3
|
+
import { D as CliExitError, a as ui, i as fetchLatestNpmPackageVersion, j as throwReportedCliExit } from "./keystroke.mjs";
|
|
4
4
|
import { i as projects } from "./dist-Dw7gCE7y.mjs";
|
|
5
5
|
import { a as writeProjectConfig, i as readProjectConfig, r as getProjectConfigPath } from "./project-config-DudGRFPO.mjs";
|
|
6
6
|
import { i as requireClient } from "./context-sgKhRc5v.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { a as runProjectInstall, i as resolvePackageManagerResolution, t as buildProjectInstallCommand } from "./package-manager-CvY4IW7X.mjs";
|
|
8
|
+
import { i as UnknownSkillAgentError, n as resolveSkillInstallChoices, r as installKeystrokeAgentSkills, t as summarizeSkillInstall } from "./skill-installer-DG8kTaQR.mjs";
|
|
8
9
|
import { createRequire } from "node:module";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -14,6 +15,7 @@ import { cancel, isCancel, text } from "@clack/prompts";
|
|
|
14
15
|
const WORKFLOW_CORE_PACKAGE_NAME = "@keystrokehq/core";
|
|
15
16
|
const CONFIG_PACKAGE_NAME = "@keystrokehq/config";
|
|
16
17
|
const RUNTIME_PACKAGE_NAME = "@keystrokehq/runtime";
|
|
18
|
+
const TESTING_PACKAGE_NAME = "@keystrokehq/testing";
|
|
17
19
|
const FALLBACK_SCAFFOLD_VERSION_RANGE = "latest";
|
|
18
20
|
const DEFAULT_TIMEOUT_MS = 750;
|
|
19
21
|
/**
|
|
@@ -41,6 +43,13 @@ async function runtimeScaffoldVersionRange(options = {}) {
|
|
|
41
43
|
readLocalVersion: options.readLocalRuntimeVersion ?? readLocalRuntimeVersion
|
|
42
44
|
});
|
|
43
45
|
}
|
|
46
|
+
async function testingScaffoldVersionRange(options = {}) {
|
|
47
|
+
return packageScaffoldVersionRange({
|
|
48
|
+
packageName: TESTING_PACKAGE_NAME,
|
|
49
|
+
timeoutMs: options.timeoutMs,
|
|
50
|
+
readLocalVersion: options.readLocalTestingVersion ?? readLocalTestingVersion
|
|
51
|
+
});
|
|
52
|
+
}
|
|
44
53
|
async function packageScaffoldVersionRange(options) {
|
|
45
54
|
const latestVersion = await fetchLatestNpmPackageVersion({
|
|
46
55
|
packageName: options.packageName,
|
|
@@ -75,6 +84,14 @@ function readLocalRuntimeVersion() {
|
|
|
75
84
|
} catch {}
|
|
76
85
|
return null;
|
|
77
86
|
}
|
|
87
|
+
function readLocalTestingVersion() {
|
|
88
|
+
try {
|
|
89
|
+
const raw = readFileSync(createRequire(import.meta.url).resolve(`${TESTING_PACKAGE_NAME}/package.json`), "utf-8");
|
|
90
|
+
const version = JSON.parse(raw).version?.trim();
|
|
91
|
+
if (version) return version;
|
|
92
|
+
} catch {}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
78
95
|
//#endregion
|
|
79
96
|
//#region src/commands/init/templates/biome-config.ts
|
|
80
97
|
/**
|
|
@@ -206,6 +223,8 @@ describe('hello workflow', () => {
|
|
|
206
223
|
}
|
|
207
224
|
//#endregion
|
|
208
225
|
//#region src/commands/init/templates/package-json.ts
|
|
226
|
+
/** Matches the Keystroke monorepo; Corepack uses this for `pnpm install`. */
|
|
227
|
+
const SCAFFOLD_PNPM_PACKAGE_MANAGER = "pnpm@11.1.1";
|
|
209
228
|
/**
|
|
210
229
|
* Template for generating a package.json for a new Keystroke project.
|
|
211
230
|
*/
|
|
@@ -214,6 +233,7 @@ function createPackageJsonContent(projectName, options) {
|
|
|
214
233
|
name: projectName,
|
|
215
234
|
private: true,
|
|
216
235
|
type: "module",
|
|
236
|
+
...options.packageManagerField ? { packageManager: options.packageManagerField } : {},
|
|
217
237
|
scripts: {
|
|
218
238
|
test: "vitest run",
|
|
219
239
|
typecheck: "tsc --noEmit",
|
|
@@ -227,7 +247,7 @@ function createPackageJsonContent(projectName, options) {
|
|
|
227
247
|
devDependencies: {
|
|
228
248
|
"@biomejs/biome": "2.4.13",
|
|
229
249
|
"@keystrokehq/runtime": options.runtimeVersionRange,
|
|
230
|
-
"@keystrokehq/testing": options.
|
|
250
|
+
"@keystrokehq/testing": options.testingVersionRange,
|
|
231
251
|
vitest: "^4.0.18",
|
|
232
252
|
typescript: "^5.9.3"
|
|
233
253
|
}
|
|
@@ -329,7 +349,7 @@ async function promptProjectDescription(options) {
|
|
|
329
349
|
const t = typeof answer === "string" ? answer.trim() : "";
|
|
330
350
|
return t.length > 0 ? t : void 0;
|
|
331
351
|
}
|
|
332
|
-
async function ensureScaffoldPackageJson(targetDir, projectName, workflowCoreRange, configRange, runtimeRange) {
|
|
352
|
+
async function ensureScaffoldPackageJson(targetDir, projectName, workflowCoreRange, configRange, runtimeRange, testingRange, packageManagerField) {
|
|
333
353
|
const pkgPath = path.join(targetDir, "package.json");
|
|
334
354
|
try {
|
|
335
355
|
const raw = await readFile(pkgPath, "utf-8");
|
|
@@ -340,7 +360,7 @@ async function ensureScaffoldPackageJson(targetDir, projectName, workflowCoreRan
|
|
|
340
360
|
pkg.dependencies.zod = pkg.dependencies.zod ?? "^4.3.6";
|
|
341
361
|
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
342
362
|
pkg.devDependencies["@keystrokehq/runtime"] = runtimeRange;
|
|
343
|
-
pkg.devDependencies["@keystrokehq/testing"] =
|
|
363
|
+
pkg.devDependencies["@keystrokehq/testing"] = testingRange;
|
|
344
364
|
pkg.devDependencies.vitest = pkg.devDependencies.vitest ?? "^4.0.18";
|
|
345
365
|
pkg.devDependencies.typescript = pkg.devDependencies.typescript ?? "^5.9.3";
|
|
346
366
|
if (!pkg.name) pkg.name = projectName;
|
|
@@ -349,7 +369,9 @@ async function ensureScaffoldPackageJson(targetDir, projectName, workflowCoreRan
|
|
|
349
369
|
} catch {
|
|
350
370
|
await writeFile(pkgPath, `${createPackageJsonContent(projectName, {
|
|
351
371
|
configVersionRange: configRange,
|
|
372
|
+
packageManagerField,
|
|
352
373
|
runtimeVersionRange: runtimeRange,
|
|
374
|
+
testingVersionRange: testingRange,
|
|
353
375
|
workflowCoreVersionRange: workflowCoreRange
|
|
354
376
|
})}\n`, "utf-8");
|
|
355
377
|
return "created";
|
|
@@ -427,12 +449,13 @@ async function handleInit(options, ctx) {
|
|
|
427
449
|
await projects.track(targetDir, { name: projectName });
|
|
428
450
|
await installAgentSkillsForInit(targetDir, options);
|
|
429
451
|
if (options.scaffold) {
|
|
430
|
-
const [workflowCoreVersionRange, configVersionRange, runtimeVersionRange] = await Promise.all([
|
|
452
|
+
const [workflowCoreVersionRange, configVersionRange, runtimeVersionRange, testingVersionRange] = await Promise.all([
|
|
431
453
|
workflowCoreScaffoldVersionRange(),
|
|
432
454
|
configScaffoldVersionRange(),
|
|
433
|
-
runtimeScaffoldVersionRange()
|
|
455
|
+
runtimeScaffoldVersionRange(),
|
|
456
|
+
testingScaffoldVersionRange()
|
|
434
457
|
]);
|
|
435
|
-
await scaffoldProject(targetDir, projectName, workflowCoreVersionRange, configVersionRange, runtimeVersionRange);
|
|
458
|
+
await scaffoldProject(targetDir, projectName, workflowCoreVersionRange, configVersionRange, runtimeVersionRange, testingVersionRange, options.install !== false);
|
|
436
459
|
}
|
|
437
460
|
}
|
|
438
461
|
/** Write a file only if it does not already exist. Returns true if written. */
|
|
@@ -445,9 +468,11 @@ async function writeIfMissing(filePath, content) {
|
|
|
445
468
|
return true;
|
|
446
469
|
}
|
|
447
470
|
}
|
|
448
|
-
async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange, configVersionRange, runtimeVersionRange) {
|
|
449
|
-
const
|
|
450
|
-
|
|
471
|
+
async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange, configVersionRange, runtimeVersionRange, testingVersionRange, shouldInstall) {
|
|
472
|
+
const packageManagerResolution = await resolvePackageManagerResolution({ cwd: targetDir });
|
|
473
|
+
const { packageManager } = packageManagerResolution;
|
|
474
|
+
const pkgAction = await ensureScaffoldPackageJson(targetDir, projectName, workflowCoreVersionRange, configVersionRange, runtimeVersionRange, testingVersionRange, packageManager === "pnpm" && packageManagerResolution.source === "preferred" ? SCAFFOLD_PNPM_PACKAGE_MANAGER : void 0);
|
|
475
|
+
ui.success(pkgAction === "created" ? `Created package.json (@keystrokehq/core ${workflowCoreVersionRange}, @keystrokehq/config ${configVersionRange}, @keystrokehq/runtime ${runtimeVersionRange}, @keystrokehq/testing ${testingVersionRange})` : `Updated package.json (Keystroke deps -> core ${workflowCoreVersionRange}, config ${configVersionRange}, runtime ${runtimeVersionRange}, testing ${testingVersionRange})`);
|
|
451
476
|
const files = [
|
|
452
477
|
{
|
|
453
478
|
rel: "vitest.config.ts",
|
|
@@ -498,7 +523,25 @@ async function scaffoldProject(targetDir, projectName, workflowCoreVersionRange,
|
|
|
498
523
|
}
|
|
499
524
|
if (created.length > 0) ui.success(`Scaffolded ${created.length} file(s): ${created.join(", ")}`);
|
|
500
525
|
else ui.hint("Scaffold files already exist — skipped (package.json was still updated).");
|
|
501
|
-
|
|
526
|
+
if (shouldInstall) await installScaffoldDependencies(targetDir, packageManager);
|
|
527
|
+
else {
|
|
528
|
+
const installCommand = buildProjectInstallCommand(packageManager);
|
|
529
|
+
const renderedCommand = [installCommand.command, ...installCommand.args].join(" ");
|
|
530
|
+
ui.hint(`Skipped dependency install. Run \`${renderedCommand}\` when ready.`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
async function installScaffoldDependencies(targetDir, packageManager) {
|
|
534
|
+
const installCommand = buildProjectInstallCommand(packageManager);
|
|
535
|
+
const renderedCommand = [installCommand.command, ...installCommand.args].join(" ");
|
|
536
|
+
ui.header(`Installing dependencies with ${packageManager}...`);
|
|
537
|
+
ui.hint(renderedCommand);
|
|
538
|
+
const exitCode = await runProjectInstall({
|
|
539
|
+
cwd: targetDir,
|
|
540
|
+
packageManager
|
|
541
|
+
});
|
|
542
|
+
if (exitCode !== 0) throwReportedCliExit(`Dependency install failed with exit code ${exitCode}.`);
|
|
543
|
+
ui.success("Dependencies installed.");
|
|
544
|
+
ui.hint(`Run \`${packageManager} test\` to run the scaffolded workflow tests.`);
|
|
502
545
|
}
|
|
503
546
|
//#endregion
|
|
504
547
|
export { handleInit };
|
|
@@ -158,14 +158,14 @@ function createIntegrationsCommand() {
|
|
|
158
158
|
description: "List Keystroke integrations available to your organization",
|
|
159
159
|
schema: IntegrationsListOptionsSchema,
|
|
160
160
|
optionsConfig: INTEGRATIONS_LIST_OPTIONS_CONFIG,
|
|
161
|
-
loadHandler: async () => (await import("./list.handler-
|
|
161
|
+
loadHandler: async () => (await import("./list.handler-CMRQKH4b.mjs")).handleIntegrationsList,
|
|
162
162
|
subcommands: [
|
|
163
163
|
createTypedCommand({
|
|
164
164
|
name: "list",
|
|
165
165
|
description: "List Keystroke integrations available to your organization",
|
|
166
166
|
schema: IntegrationsListOptionsSchema,
|
|
167
167
|
optionsConfig: INTEGRATIONS_LIST_OPTIONS_CONFIG,
|
|
168
|
-
loadHandler: async () => (await import("./list.handler-
|
|
168
|
+
loadHandler: async () => (await import("./list.handler-CMRQKH4b.mjs")).handleIntegrationsList
|
|
169
169
|
}),
|
|
170
170
|
createTypedCommand({
|
|
171
171
|
name: "show",
|
|
@@ -177,7 +177,7 @@ function createIntegrationsCommand() {
|
|
|
177
177
|
description: "Integration id, e.g. aws-s3",
|
|
178
178
|
key: "id"
|
|
179
179
|
},
|
|
180
|
-
loadHandler: async () => (await import("./show.handler-
|
|
180
|
+
loadHandler: async () => (await import("./show.handler-nkK6Erbb.mjs")).handleIntegrationShow
|
|
181
181
|
}),
|
|
182
182
|
createTypedCommand({
|
|
183
183
|
name: "register",
|
|
@@ -185,7 +185,7 @@ function createIntegrationsCommand() {
|
|
|
185
185
|
schema: IntegrationsRegisterOptionsSchema,
|
|
186
186
|
optionsConfig: INTEGRATIONS_REGISTER_OPTIONS_CONFIG,
|
|
187
187
|
handler: async (opts, ctx) => {
|
|
188
|
-
const { handleIntegrationsRegister } = await import("./register.handler-
|
|
188
|
+
const { handleIntegrationsRegister } = await import("./register.handler-CKMZ2WmD.mjs");
|
|
189
189
|
await handleIntegrationsRegister({
|
|
190
190
|
integrationId: opts.integrationId,
|
|
191
191
|
clientAppCredentialSetId: opts.clientApp,
|
package/dist/keystroke.mjs
CHANGED
|
@@ -521,7 +521,7 @@ const logger = {
|
|
|
521
521
|
};
|
|
522
522
|
//#endregion
|
|
523
523
|
//#region package.json
|
|
524
|
-
var version = "0.0.
|
|
524
|
+
var version = "0.0.32";
|
|
525
525
|
//#endregion
|
|
526
526
|
//#region src/command-registry.ts
|
|
527
527
|
const ROOT_OPTIONS_WITH_VALUES$1 = new Set([
|
|
@@ -553,7 +553,7 @@ const lazyCommandDefinitions = [
|
|
|
553
553
|
},
|
|
554
554
|
{
|
|
555
555
|
name: "credentials",
|
|
556
|
-
loadCommand: async () => (await import("./credentials-
|
|
556
|
+
loadCommand: async () => (await import("./credentials-CsncZ52a.mjs")).createCredentialsCommand(),
|
|
557
557
|
copyInheritedSettings: true
|
|
558
558
|
},
|
|
559
559
|
{
|
|
@@ -566,11 +566,11 @@ const lazyCommandDefinitions = [
|
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
568
|
name: "init",
|
|
569
|
-
loadCommand: async () => (await import("./init-
|
|
569
|
+
loadCommand: async () => (await import("./init-BOCDwqKR.mjs")).createInitCommand()
|
|
570
570
|
},
|
|
571
571
|
{
|
|
572
572
|
name: "integrations",
|
|
573
|
-
loadCommand: async () => (await import("./integrations-
|
|
573
|
+
loadCommand: async () => (await import("./integrations-m7_tb3GV.mjs")).createIntegrationsCommand()
|
|
574
574
|
},
|
|
575
575
|
{
|
|
576
576
|
name: "invites",
|
|
@@ -586,7 +586,7 @@ const lazyCommandDefinitions = [
|
|
|
586
586
|
},
|
|
587
587
|
{
|
|
588
588
|
name: "operations",
|
|
589
|
-
loadCommand: async () => (await import("./operations-
|
|
589
|
+
loadCommand: async () => (await import("./operations-CF2nUiBs.mjs")).createOperationsCommand()
|
|
590
590
|
},
|
|
591
591
|
{
|
|
592
592
|
name: "projects",
|
|
@@ -598,11 +598,11 @@ const lazyCommandDefinitions = [
|
|
|
598
598
|
},
|
|
599
599
|
{
|
|
600
600
|
name: "search",
|
|
601
|
-
loadCommand: async () => (await import("./search-
|
|
601
|
+
loadCommand: async () => (await import("./search-CA0J5NOY.mjs")).createSearchCommand()
|
|
602
602
|
},
|
|
603
603
|
{
|
|
604
604
|
name: "skills",
|
|
605
|
-
loadCommand: async () => (await import("./skills.command-
|
|
605
|
+
loadCommand: async () => (await import("./skills.command-COYd3k4Z.mjs")).createSkillsCommand()
|
|
606
606
|
},
|
|
607
607
|
{
|
|
608
608
|
name: "sync",
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { a as ui } from "./keystroke.mjs";
|
|
4
4
|
import { i as writeJson } from "./output-BWcVRt-T.mjs";
|
|
5
5
|
import { i as requireClient } from "./context-sgKhRc5v.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import { t as renderOperation } from "./render-operation-
|
|
6
|
+
import { n as detectPackageManager } from "./package-manager-CvY4IW7X.mjs";
|
|
7
|
+
import { t as renderOperation } from "./render-operation-DWbMwhfc.mjs";
|
|
8
8
|
//#region src/commands/operations/list.handler.ts
|
|
9
9
|
async function handleOperationsList(options, ctx) {
|
|
10
10
|
const result = await requireClient(ctx).operations.list({
|
|
@@ -56,13 +56,13 @@ function createOperationsCommand() {
|
|
|
56
56
|
description: "Browse and inspect operations across all integrations",
|
|
57
57
|
schema: OperationsListOptionsSchema,
|
|
58
58
|
optionsConfig: OPERATIONS_LIST_OPTIONS_CONFIG,
|
|
59
|
-
loadHandler: async () => (await import("./list.handler-
|
|
59
|
+
loadHandler: async () => (await import("./list.handler-DbYUk6ko.mjs")).handleOperationsList,
|
|
60
60
|
subcommands: [createTypedCommand({
|
|
61
61
|
name: "list",
|
|
62
62
|
description: "List operations, optionally scoped to one integration",
|
|
63
63
|
schema: OperationsListOptionsSchema,
|
|
64
64
|
optionsConfig: OPERATIONS_LIST_OPTIONS_CONFIG,
|
|
65
|
-
loadHandler: async () => (await import("./list.handler-
|
|
65
|
+
loadHandler: async () => (await import("./list.handler-DbYUk6ko.mjs")).handleOperationsList
|
|
66
66
|
}), createTypedCommand({
|
|
67
67
|
name: "show",
|
|
68
68
|
description: "Show full details for one operation, including input/output schemas",
|
|
@@ -70,10 +70,10 @@ function createOperationsCommand() {
|
|
|
70
70
|
optionsConfig: OPERATION_SHOW_OPTIONS_CONFIG,
|
|
71
71
|
argument: {
|
|
72
72
|
name: "id",
|
|
73
|
-
description: "Operation id, e.g. aws-s3.
|
|
73
|
+
description: "Operation id, e.g. aws-s3.put-object",
|
|
74
74
|
key: "id"
|
|
75
75
|
},
|
|
76
|
-
loadHandler: async () => (await import("./show.handler-
|
|
76
|
+
loadHandler: async () => (await import("./show.handler-CwwnCmbp.mjs")).handleOperationShow
|
|
77
77
|
})]
|
|
78
78
|
});
|
|
79
79
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { y as toErrorMessage } from "./keystroke.mjs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
//#region src/lib/package-manager.ts
|
|
8
|
+
const PackageManagerValues = [
|
|
9
|
+
"npm",
|
|
10
|
+
"pnpm",
|
|
11
|
+
"yarn",
|
|
12
|
+
"bun"
|
|
13
|
+
];
|
|
14
|
+
function parsePackageManagerField(value) {
|
|
15
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
16
|
+
const name = value.split("@")[0]?.trim();
|
|
17
|
+
if (name && PackageManagerValues.includes(name)) return name;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function detectFromLockfiles(directory) {
|
|
21
|
+
if (existsSync(join(directory, "bun.lockb")) || existsSync(join(directory, "bun.lock"))) return "bun";
|
|
22
|
+
if (existsSync(join(directory, "pnpm-lock.yaml"))) return "pnpm";
|
|
23
|
+
if (existsSync(join(directory, "yarn.lock"))) return "yarn";
|
|
24
|
+
if (existsSync(join(directory, "package-lock.json")) || existsSync(join(directory, "npm-shrinkwrap.json"))) return "npm";
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function readPackageManagerField(directory) {
|
|
28
|
+
const packageJsonPath = join(directory, "package.json");
|
|
29
|
+
if (!existsSync(packageJsonPath)) return null;
|
|
30
|
+
try {
|
|
31
|
+
return parsePackageManagerField(JSON.parse(readFileSync(packageJsonPath, "utf8")).packageManager);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function walkProjectDirectories(startDir) {
|
|
37
|
+
const directories = [];
|
|
38
|
+
let directory = startDir;
|
|
39
|
+
while (true) {
|
|
40
|
+
directories.push(directory);
|
|
41
|
+
const parent = dirname(directory);
|
|
42
|
+
if (parent === directory) break;
|
|
43
|
+
directory = parent;
|
|
44
|
+
}
|
|
45
|
+
return directories;
|
|
46
|
+
}
|
|
47
|
+
function hasPackageManagerSignal(cwd) {
|
|
48
|
+
for (const directory of walkProjectDirectories(cwd)) {
|
|
49
|
+
if (detectFromLockfiles(directory)) return true;
|
|
50
|
+
if (readPackageManagerField(directory)) return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Infers the package manager for the current working directory by walking up
|
|
56
|
+
* from `cwd` and preferring lockfiles (monorepo roots) over nested package.json
|
|
57
|
+
* files without lockfiles.
|
|
58
|
+
*/
|
|
59
|
+
function detectPackageManager(options = {}) {
|
|
60
|
+
let packageManagerFromField = null;
|
|
61
|
+
for (const directory of walkProjectDirectories(options.cwd ?? process.cwd())) {
|
|
62
|
+
const fromLockfiles = detectFromLockfiles(directory);
|
|
63
|
+
if (fromLockfiles) return fromLockfiles;
|
|
64
|
+
const fromField = readPackageManagerField(directory);
|
|
65
|
+
if (fromField && !packageManagerFromField) packageManagerFromField = fromField;
|
|
66
|
+
}
|
|
67
|
+
return packageManagerFromField ?? "npm";
|
|
68
|
+
}
|
|
69
|
+
async function resolvePackageManagerResolution(options = {}) {
|
|
70
|
+
const cwd = options.cwd ?? process.cwd();
|
|
71
|
+
if (hasPackageManagerSignal(cwd)) return {
|
|
72
|
+
packageManager: detectPackageManager({ cwd }),
|
|
73
|
+
source: "project"
|
|
74
|
+
};
|
|
75
|
+
if (await (options.isPackageManagerAvailable ?? isPackageManagerOnPath)("pnpm")) return {
|
|
76
|
+
packageManager: "pnpm",
|
|
77
|
+
source: "preferred"
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
packageManager: "npm",
|
|
81
|
+
source: "fallback"
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function formatPackageInstallCommand(packageName, options = {}) {
|
|
85
|
+
const packageManager = options.packageManager ?? detectPackageManager({ cwd: options.cwd });
|
|
86
|
+
if (packageManager === "npm") return `npm install ${packageName}`;
|
|
87
|
+
if (packageManager === "pnpm") return `pnpm add ${packageName}`;
|
|
88
|
+
if (packageManager === "yarn") return `yarn add ${packageName}`;
|
|
89
|
+
return `bun add ${packageName}`;
|
|
90
|
+
}
|
|
91
|
+
function buildProjectInstallCommand(packageManager) {
|
|
92
|
+
if (packageManager === "pnpm") return {
|
|
93
|
+
command: "pnpm",
|
|
94
|
+
args: ["install"]
|
|
95
|
+
};
|
|
96
|
+
if (packageManager === "yarn") return {
|
|
97
|
+
command: "yarn",
|
|
98
|
+
args: ["install"]
|
|
99
|
+
};
|
|
100
|
+
if (packageManager === "bun") return {
|
|
101
|
+
command: "bun",
|
|
102
|
+
args: ["install"]
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
command: "npm",
|
|
106
|
+
args: ["install"]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function isPackageManagerOnPath(packageManager) {
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
const child = spawn(packageManager, ["--version"], {
|
|
112
|
+
stdio: "ignore",
|
|
113
|
+
shell: process.platform === "win32"
|
|
114
|
+
});
|
|
115
|
+
child.on("error", () => resolve(false));
|
|
116
|
+
child.on("close", (code) => resolve(code === 0));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async function runProjectInstall(options) {
|
|
120
|
+
const installCommand = buildProjectInstallCommand(options.packageManager);
|
|
121
|
+
return (options.runCommand ?? runPackageManagerCommand)(installCommand, { cwd: options.cwd });
|
|
122
|
+
}
|
|
123
|
+
function runPackageManagerCommand({ command, args }, options) {
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const child = spawn(command, args, {
|
|
126
|
+
cwd: options.cwd,
|
|
127
|
+
stdio: "inherit",
|
|
128
|
+
shell: process.platform === "win32"
|
|
129
|
+
});
|
|
130
|
+
child.on("error", (error) => {
|
|
131
|
+
reject(new Error(`Failed to start ${command}: ${toErrorMessage(error)}`, { cause: error }));
|
|
132
|
+
});
|
|
133
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
export { runProjectInstall as a, resolvePackageManagerResolution as i, detectPackageManager as n, formatPackageInstallCommand as r, buildProjectInstallCommand as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { a as ui } from "./keystroke.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { r as formatPackageInstallCommand } from "./package-manager-CvY4IW7X.mjs";
|
|
5
5
|
//#region src/lib/render-operation.ts
|
|
6
6
|
function isFull(op) {
|
|
7
7
|
return "inputSchemaJson" in op;
|
|
@@ -46,7 +46,7 @@ function createSearchCommand() {
|
|
|
46
46
|
description: "Search query (matches name and related fields per --type)",
|
|
47
47
|
key: "query"
|
|
48
48
|
},
|
|
49
|
-
loadHandler: async () => (await import("./search.handler-
|
|
49
|
+
loadHandler: async () => (await import("./search.handler-BVDsYZlJ.mjs")).handleSearch
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
//#endregion
|
|
@@ -4,8 +4,8 @@ import { a as ui } from "./keystroke.mjs";
|
|
|
4
4
|
import { i as writeJson } from "./output-BWcVRt-T.mjs";
|
|
5
5
|
import { i as requireClient } from "./context-sgKhRc5v.mjs";
|
|
6
6
|
import { t as renderCredential } from "./render-credential-Bn15FEUC.mjs";
|
|
7
|
-
import { n as
|
|
8
|
-
import { t as renderOperation } from "./render-operation-
|
|
7
|
+
import { n as detectPackageManager, r as formatPackageInstallCommand } from "./package-manager-CvY4IW7X.mjs";
|
|
8
|
+
import { t as renderOperation } from "./render-operation-DWbMwhfc.mjs";
|
|
9
9
|
//#region src/lib/render-integration.ts
|
|
10
10
|
function renderIntegration(i, { full = false, packageManager } = {}) {
|
|
11
11
|
ui.br();
|
|
@@ -4,8 +4,8 @@ import { a as ui } from "./keystroke.mjs";
|
|
|
4
4
|
import { i as writeJson } from "./output-BWcVRt-T.mjs";
|
|
5
5
|
import { i as requireClient } from "./context-sgKhRc5v.mjs";
|
|
6
6
|
import { i as renderJsonSchema } from "./schema-display-FvI8QjOQ.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import { t as renderOperation } from "./render-operation-
|
|
7
|
+
import { n as detectPackageManager } from "./package-manager-CvY4IW7X.mjs";
|
|
8
|
+
import { t as renderOperation } from "./render-operation-DWbMwhfc.mjs";
|
|
9
9
|
//#region src/commands/operations/show.handler.ts
|
|
10
10
|
async function handleOperationShow(options, ctx) {
|
|
11
11
|
const { operation } = await requireClient(ctx).operations.get(options.id);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { a as ui } from "./keystroke.mjs";
|
|
4
4
|
import { i as writeJson } from "./output-BWcVRt-T.mjs";
|
|
5
5
|
import { i as requireClient } from "./context-sgKhRc5v.mjs";
|
|
6
|
-
import { n as
|
|
6
|
+
import { n as detectPackageManager, r as formatPackageInstallCommand } from "./package-manager-CvY4IW7X.mjs";
|
|
7
7
|
//#region src/commands/integrations/show.handler.ts
|
|
8
8
|
async function handleIntegrationShow(options, ctx) {
|
|
9
9
|
const client = requireClient(ctx);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { D as CliExitError, a as ui } from "./keystroke.mjs";
|
|
4
4
|
import { i as writeJson, r as isJsonMode } from "./output-BWcVRt-T.mjs";
|
|
5
|
-
import { i as UnknownSkillAgentError, n as resolveSkillInstallChoices, r as installKeystrokeAgentSkills, t as summarizeSkillInstall } from "./skill-installer-
|
|
5
|
+
import { i as UnknownSkillAgentError, n as resolveSkillInstallChoices, r as installKeystrokeAgentSkills, t as summarizeSkillInstall } from "./skill-installer-DG8kTaQR.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) {
|
|
@@ -38,7 +38,7 @@ function createSkillsCommand() {
|
|
|
38
38
|
description: "Install bundled Keystroke skills into selected agent skill directories",
|
|
39
39
|
schema: SkillsCommandOptionsSchema,
|
|
40
40
|
optionsConfig: SKILLS_OPTIONS_CONFIG,
|
|
41
|
-
loadHandler: async () => (await import("./skills-sync.handler-
|
|
41
|
+
loadHandler: async () => (await import("./skills-sync.handler-yRmi3OgP.mjs")).handleSkillsSync
|
|
42
42
|
})]
|
|
43
43
|
});
|
|
44
44
|
cmd.enablePositionalOptions();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keystrokehq/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Command-line interface for creating, managing, and deploying Keystroke automations.",
|
|
6
6
|
"type": "module",
|
|
@@ -32,19 +32,19 @@
|
|
|
32
32
|
"rolldown": "1.0.0",
|
|
33
33
|
"tsx": "^4.21.0",
|
|
34
34
|
"zod": "4.4.3",
|
|
35
|
-
"@keystrokehq/skills": "0.0.
|
|
35
|
+
"@keystrokehq/skills": "0.0.9"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"tsdown": "0.21.10",
|
|
39
39
|
"typescript": "^5.9.3",
|
|
40
40
|
"vitest": "^4.1.5",
|
|
41
|
+
"@keystroke/env-utils": "0.0.0",
|
|
41
42
|
"@keystroke/local-memory": "0.0.2",
|
|
42
|
-
"@keystrokehq/config": "0.0.2",
|
|
43
43
|
"@keystroke/shared-types": "0.0.11",
|
|
44
|
+
"@keystrokehq/config": "0.0.2",
|
|
44
45
|
"@keystroke/typescript-config": "0.0.0",
|
|
45
|
-
"@keystroke/env-utils": "0.0.0",
|
|
46
|
-
"@keystroke/utils": "0.0.0",
|
|
47
46
|
"@keystroke/test-utils": "0.0.6",
|
|
47
|
+
"@keystroke/utils": "0.0.0",
|
|
48
48
|
"@keystroke/workflow-builder": "0.0.15",
|
|
49
49
|
"@keystrokehq/core": "0.0.10",
|
|
50
50
|
"@keystrokehq/runtime": "0.0.7",
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
-
//#region src/lib/package-manager.ts
|
|
6
|
-
const PackageManagerValues = [
|
|
7
|
-
"npm",
|
|
8
|
-
"pnpm",
|
|
9
|
-
"yarn",
|
|
10
|
-
"bun"
|
|
11
|
-
];
|
|
12
|
-
function parsePackageManagerField(value) {
|
|
13
|
-
if (typeof value !== "string" || value.length === 0) return null;
|
|
14
|
-
const name = value.split("@")[0]?.trim();
|
|
15
|
-
if (name && PackageManagerValues.includes(name)) return name;
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
function detectFromLockfiles(directory) {
|
|
19
|
-
if (existsSync(join(directory, "bun.lockb")) || existsSync(join(directory, "bun.lock"))) return "bun";
|
|
20
|
-
if (existsSync(join(directory, "pnpm-lock.yaml"))) return "pnpm";
|
|
21
|
-
if (existsSync(join(directory, "yarn.lock"))) return "yarn";
|
|
22
|
-
if (existsSync(join(directory, "package-lock.json")) || existsSync(join(directory, "npm-shrinkwrap.json"))) return "npm";
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
function readPackageManagerField(directory) {
|
|
26
|
-
const packageJsonPath = join(directory, "package.json");
|
|
27
|
-
if (!existsSync(packageJsonPath)) return null;
|
|
28
|
-
try {
|
|
29
|
-
return parsePackageManagerField(JSON.parse(readFileSync(packageJsonPath, "utf8")).packageManager);
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Infers the package manager for the current working directory by walking up
|
|
36
|
-
* from `cwd` and preferring lockfiles (monorepo roots) over nested package.json
|
|
37
|
-
* files without lockfiles.
|
|
38
|
-
*/
|
|
39
|
-
function detectPackageManager(options = {}) {
|
|
40
|
-
let directory = options.cwd ?? process.cwd();
|
|
41
|
-
let packageManagerFromField = null;
|
|
42
|
-
while (true) {
|
|
43
|
-
const fromLockfiles = detectFromLockfiles(directory);
|
|
44
|
-
if (fromLockfiles) return fromLockfiles;
|
|
45
|
-
const fromField = readPackageManagerField(directory);
|
|
46
|
-
if (fromField && !packageManagerFromField) packageManagerFromField = fromField;
|
|
47
|
-
const parent = dirname(directory);
|
|
48
|
-
if (parent === directory) break;
|
|
49
|
-
directory = parent;
|
|
50
|
-
}
|
|
51
|
-
return packageManagerFromField ?? "npm";
|
|
52
|
-
}
|
|
53
|
-
function formatPackageInstallCommand(packageName, options = {}) {
|
|
54
|
-
const packageManager = options.packageManager ?? detectPackageManager({ cwd: options.cwd });
|
|
55
|
-
if (packageManager === "npm") return `npm install ${packageName}`;
|
|
56
|
-
if (packageManager === "pnpm") return `pnpm add ${packageName}`;
|
|
57
|
-
if (packageManager === "yarn") return `yarn add ${packageName}`;
|
|
58
|
-
return `bun add ${packageName}`;
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
export { formatPackageInstallCommand as n, detectPackageManager as t };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|