@keystrokehq/cli 0.1.102 → 0.1.103
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/dist/index.mjs +86 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -5014,6 +5014,21 @@ function readLinkedProjectConfig(fromDir = process.cwd()) {
|
|
|
5014
5014
|
return parseLinkedProjectConfig(readFileSync(join(root, KEYSTROKE_CONFIG$1), "utf8"));
|
|
5015
5015
|
}
|
|
5016
5016
|
//#endregion
|
|
5017
|
+
//#region src/errors/expected-cli-error.ts
|
|
5018
|
+
/**
|
|
5019
|
+
* User/project failures that are expected CLI exits (lint, typecheck, validation, etc.).
|
|
5020
|
+
* These should not become Error Tracking issues.
|
|
5021
|
+
*/
|
|
5022
|
+
var ExpectedCliError = class extends Error {
|
|
5023
|
+
constructor(message) {
|
|
5024
|
+
super(message);
|
|
5025
|
+
this.name = "ExpectedCliError";
|
|
5026
|
+
}
|
|
5027
|
+
};
|
|
5028
|
+
function isExpectedCliError(error) {
|
|
5029
|
+
return error instanceof ExpectedCliError;
|
|
5030
|
+
}
|
|
5031
|
+
//#endregion
|
|
5017
5032
|
//#region src/target-hints.ts
|
|
5018
5033
|
function missingOrganizationRefMessage() {
|
|
5019
5034
|
return "No organization selected. Pass `--organization <slug>` or set `organization` in keystroke.config.ts (via `keystroke projects link --project <slug>`).";
|
|
@@ -5022,10 +5037,10 @@ function missingProjectRefMessage() {
|
|
|
5022
5037
|
return "No project selected. Pass `--project <slug>` or set `project` in keystroke.config.ts (via `keystroke projects link --project <slug>`).";
|
|
5023
5038
|
}
|
|
5024
5039
|
function missingOrganizationRefError() {
|
|
5025
|
-
return new
|
|
5040
|
+
return new ExpectedCliError(missingOrganizationRefMessage());
|
|
5026
5041
|
}
|
|
5027
5042
|
function missingProjectRefError() {
|
|
5028
|
-
return new
|
|
5043
|
+
return new ExpectedCliError(missingProjectRefMessage());
|
|
5029
5044
|
}
|
|
5030
5045
|
//#endregion
|
|
5031
5046
|
//#region src/resolve-organization-target.ts
|
|
@@ -5052,7 +5067,7 @@ async function resolveActiveOrganization(config, fromDir = process.cwd()) {
|
|
|
5052
5067
|
//#region src/project/resolve-project-root.ts
|
|
5053
5068
|
function resolveProjectRoot(fromDir = process.cwd()) {
|
|
5054
5069
|
const root = resolveKeystrokeConfigRoot(fromDir);
|
|
5055
|
-
if (!root) throw new
|
|
5070
|
+
if (!root) throw new ExpectedCliError("Could not find keystroke project root (expected keystroke.config.ts)");
|
|
5056
5071
|
return root;
|
|
5057
5072
|
}
|
|
5058
5073
|
//#endregion
|
|
@@ -5198,14 +5213,14 @@ function getTelemetryContext() {
|
|
|
5198
5213
|
*/
|
|
5199
5214
|
function isExpectedError(error) {
|
|
5200
5215
|
if (!error || typeof error !== "object") return false;
|
|
5201
|
-
const status = readStatus(error);
|
|
5202
|
-
if (status !== void 0 && status >= 400 && status < 500) return true;
|
|
5216
|
+
const status = readStatus$1(error);
|
|
5217
|
+
if (status !== void 0 && (status === 0 || status >= 400 && status < 500)) return true;
|
|
5203
5218
|
if ("name" in error && typeof error.name === "string") {
|
|
5204
5219
|
if (error.name === "AbortError" || error.name === "CanceledError" || error.name === "CancelledError" || error.name === "RunTimeoutError") return true;
|
|
5205
5220
|
}
|
|
5206
5221
|
return false;
|
|
5207
5222
|
}
|
|
5208
|
-
function readStatus(error) {
|
|
5223
|
+
function readStatus$1(error) {
|
|
5209
5224
|
if ("status" in error && typeof error.status === "number") return error.status;
|
|
5210
5225
|
if ("statusCode" in error && typeof error.statusCode === "number") return error.statusCode;
|
|
5211
5226
|
}
|
|
@@ -5339,6 +5354,39 @@ function sanitizeProperties(properties) {
|
|
|
5339
5354
|
return Object.fromEntries(Object.entries(properties).filter((entry) => entry[1] !== void 0));
|
|
5340
5355
|
}
|
|
5341
5356
|
//#endregion
|
|
5357
|
+
//#region src/errors/should-report-cli-exception.ts
|
|
5358
|
+
function readStatus(error) {
|
|
5359
|
+
if (!error || typeof error !== "object") return;
|
|
5360
|
+
if ("status" in error && typeof error.status === "number") return error.status;
|
|
5361
|
+
if ("statusCode" in error && typeof error.statusCode === "number") return error.statusCode;
|
|
5362
|
+
}
|
|
5363
|
+
function isAuthCommand(context) {
|
|
5364
|
+
const operation = context.operation ?? "";
|
|
5365
|
+
const command = context.command ?? "";
|
|
5366
|
+
return operation.startsWith("cli.auth") || command.startsWith("auth");
|
|
5367
|
+
}
|
|
5368
|
+
function isDeployCommand(context) {
|
|
5369
|
+
const operation = context.operation ?? "";
|
|
5370
|
+
const command = context.command ?? "";
|
|
5371
|
+
return operation === "cli.deploy" || command === "deploy";
|
|
5372
|
+
}
|
|
5373
|
+
/**
|
|
5374
|
+
* CLI Error Tracking allowlist — report only:
|
|
5375
|
+
* - HTTP 5xx responses
|
|
5376
|
+
* - unexpected failures on auth / deploy paths
|
|
5377
|
+
*
|
|
5378
|
+
* Validation, lint/typecheck, bad flags, and local unreachable servers stay quiet.
|
|
5379
|
+
*/
|
|
5380
|
+
function shouldReportCliException(error, context) {
|
|
5381
|
+
if (isExpectedCliError(error)) return false;
|
|
5382
|
+
const status = readStatus(error);
|
|
5383
|
+
if (status !== void 0) {
|
|
5384
|
+
if (status === 0 || status >= 400 && status < 500) return false;
|
|
5385
|
+
if (status >= 500) return true;
|
|
5386
|
+
}
|
|
5387
|
+
return isAuthCommand(context) || isDeployCommand(context);
|
|
5388
|
+
}
|
|
5389
|
+
//#endregion
|
|
5342
5390
|
//#region src/telemetry/identity.ts
|
|
5343
5391
|
function getCliTelemetryActorId() {
|
|
5344
5392
|
return getOrCreateAnonymousDistinctId();
|
|
@@ -5409,7 +5457,7 @@ async function shutdownCliTelemetry() {
|
|
|
5409
5457
|
enabled = false;
|
|
5410
5458
|
}
|
|
5411
5459
|
async function reportCliException(error, context) {
|
|
5412
|
-
if (!enabled) return;
|
|
5460
|
+
if (!enabled || isExpectedCliError(error) || !shouldReportCliException(error, context)) return;
|
|
5413
5461
|
await captureException({
|
|
5414
5462
|
error,
|
|
5415
5463
|
analyticsId: getCliTelemetryActorId(),
|
|
@@ -5604,7 +5652,7 @@ function parseJsonOption(value, flag) {
|
|
|
5604
5652
|
try {
|
|
5605
5653
|
return JSON.parse(value);
|
|
5606
5654
|
} catch {
|
|
5607
|
-
throw new
|
|
5655
|
+
throw new ExpectedCliError(`Invalid ${flag} JSON`);
|
|
5608
5656
|
}
|
|
5609
5657
|
}
|
|
5610
5658
|
//#endregion
|
|
@@ -7116,8 +7164,7 @@ async function ensureSdkCurrent(root) {
|
|
|
7116
7164
|
if (packages.length === 0) return;
|
|
7117
7165
|
const outdated = await packagesNeedingUpdate(root, packages);
|
|
7118
7166
|
if (outdated.length === 0) return;
|
|
7119
|
-
|
|
7120
|
-
throw new Error(`Outdated @keystrokehq packages:\n${lines}\n\nPlease run \`keystroke update\` before continuing.`);
|
|
7167
|
+
throw new ExpectedCliError(`Outdated @keystrokehq packages:\n${outdated.map(formatOutdatedLine).join("\n")}\n\nPlease run \`keystroke update\` before continuing.`);
|
|
7121
7168
|
}
|
|
7122
7169
|
//#endregion
|
|
7123
7170
|
//#region src/commands/build.ts
|
|
@@ -7288,8 +7335,8 @@ async function buildDeployArchive(client, root, projectId, filter) {
|
|
|
7288
7335
|
async function runDeploy(options) {
|
|
7289
7336
|
const root = resolveProjectRoot(options.dir);
|
|
7290
7337
|
await ensureSdkCurrent(root);
|
|
7291
|
-
if (await runLint(root) !== 0) throw new
|
|
7292
|
-
if (await runTypecheck(root) !== 0) throw new
|
|
7338
|
+
if (await runLint(root) !== 0) throw new ExpectedCliError("lint failed");
|
|
7339
|
+
if (await runTypecheck(root) !== 0) throw new ExpectedCliError("typecheck failed");
|
|
7293
7340
|
const config = createCliConfig();
|
|
7294
7341
|
await resolveActiveOrganization(config, root);
|
|
7295
7342
|
const client = createCliPlatformClient(config);
|
|
@@ -7711,8 +7758,8 @@ function projectNameValidationError(name) {
|
|
|
7711
7758
|
}
|
|
7712
7759
|
function assertProjectName(name) {
|
|
7713
7760
|
const trimmed = name.trim();
|
|
7714
|
-
if (!trimmed) throw new
|
|
7715
|
-
if (!KEBAB_CASE.test(trimmed)) throw new
|
|
7761
|
+
if (!trimmed) throw new ExpectedCliError("Project name is required");
|
|
7762
|
+
if (!KEBAB_CASE.test(trimmed)) throw new ExpectedCliError(projectNameValidationError(trimmed));
|
|
7716
7763
|
return trimmed;
|
|
7717
7764
|
}
|
|
7718
7765
|
function projectNameFromDirectory(directory) {
|
|
@@ -7861,21 +7908,33 @@ function resolveSkillsBundleDir(fromModuleUrl = import.meta.url) {
|
|
|
7861
7908
|
}
|
|
7862
7909
|
//#endregion
|
|
7863
7910
|
//#region src/skills/scaffold-agents-guide.ts
|
|
7864
|
-
|
|
7911
|
+
function isSymlinkUnsupported(error) {
|
|
7912
|
+
if (!error || typeof error !== "object" || !("code" in error)) return false;
|
|
7913
|
+
const code = error.code;
|
|
7914
|
+
return code === "EPERM" || code === "EACCES" || code === "ENOTSUP";
|
|
7915
|
+
}
|
|
7916
|
+
/** Prefer a symlink; on Windows without symlink privileges, write a regular file copy. */
|
|
7917
|
+
async function ensureClaudeMdLink(guidePath, linkPath, createLink = symlink) {
|
|
7865
7918
|
await mkdir(dirname(linkPath), { recursive: true });
|
|
7866
7919
|
await rm(linkPath, {
|
|
7867
7920
|
recursive: true,
|
|
7868
7921
|
force: true
|
|
7869
7922
|
});
|
|
7870
|
-
|
|
7923
|
+
const target = relative(dirname(linkPath), guidePath);
|
|
7924
|
+
try {
|
|
7925
|
+
await createLink(target, linkPath, "file");
|
|
7926
|
+
} catch (error) {
|
|
7927
|
+
if (!isSymlinkUnsupported(error)) throw error;
|
|
7928
|
+
await writeFile(linkPath, await readFile(guidePath, "utf8"));
|
|
7929
|
+
}
|
|
7871
7930
|
}
|
|
7872
|
-
/** Writes AGENTS.md from the CLI bundle and recreates the CLAUDE.md symlink. */
|
|
7931
|
+
/** Writes AGENTS.md from the CLI bundle and recreates the CLAUDE.md symlink (or copy). */
|
|
7873
7932
|
async function scaffoldAgentsGuide(projectRoot, fromModuleUrl = import.meta.url) {
|
|
7874
7933
|
const bundleDir = resolveSkillsBundleDir(fromModuleUrl);
|
|
7875
7934
|
const guidePath = agentsMdPath(projectRoot);
|
|
7876
7935
|
if ((await lstat(guidePath).catch(() => null))?.isSymbolicLink()) await rm(guidePath, { force: true });
|
|
7877
7936
|
await writeFile(guidePath, stampAgentsGuideVersion(await readFile(join(bundleDir, "_AGENTS.md"), "utf8")));
|
|
7878
|
-
await
|
|
7937
|
+
await ensureClaudeMdLink(guidePath, join(projectRoot, "CLAUDE.md"));
|
|
7879
7938
|
}
|
|
7880
7939
|
//#endregion
|
|
7881
7940
|
//#region src/project/write-project-config.ts
|
|
@@ -7994,8 +8053,8 @@ async function runInit(options) {
|
|
|
7994
8053
|
const playgroundRoot = resolvePlaygroundRoot(targetDir);
|
|
7995
8054
|
if (!await directoryIsEmpty(targetDir)) {
|
|
7996
8055
|
if (interactive) {
|
|
7997
|
-
if (!await confirmTargetDir(targetDir)) throw new
|
|
7998
|
-
} else if (!options.yes) throw new
|
|
8056
|
+
if (!await confirmTargetDir(targetDir)) throw new ExpectedCliError("Init cancelled");
|
|
8057
|
+
} else if (!options.yes) throw new ExpectedCliError(`Directory "${targetDir}" is not empty. Pass --yes to merge or choose an empty directory.`);
|
|
7999
8058
|
}
|
|
8000
8059
|
await copyTemplate(resolveTemplateDir(options.template ?? "hello-world"), targetDir, { projectName });
|
|
8001
8060
|
await scaffoldEmptySrcDirs(targetDir);
|
|
@@ -9366,8 +9425,13 @@ async function syncAgentsGuide(command) {
|
|
|
9366
9425
|
if (existsSync(legacySkillsDir) && lstatSync(legacySkillsDir).isSymbolicLink()) return;
|
|
9367
9426
|
const currentVersion = readCliVersion();
|
|
9368
9427
|
if (await readBundleVersion(projectRoot) === currentVersion) return;
|
|
9369
|
-
|
|
9370
|
-
|
|
9428
|
+
try {
|
|
9429
|
+
await scaffoldAgentsGuide(projectRoot);
|
|
9430
|
+
process.stderr.write(`Synced AGENTS.md to ${currentVersion}\n`);
|
|
9431
|
+
} catch (error) {
|
|
9432
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
9433
|
+
process.stderr.write(`Failed to sync AGENTS.md (${detail}); continuing.\n`);
|
|
9434
|
+
}
|
|
9371
9435
|
}
|
|
9372
9436
|
//#endregion
|
|
9373
9437
|
//#region src/program.ts
|