@keystrokehq/cli 0.1.162 → 0.1.163
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 +1 -1
- package/dist/{dist-Cy2nsWsI.mjs → dist-BgPOKEEt.mjs} +7 -4
- package/dist/dist-BgPOKEEt.mjs.map +1 -0
- package/dist/dist-CE_RfXDS.mjs +4 -0
- package/dist/dist-Co-J5D_c.mjs +3 -0
- package/dist/{dist-Dg-PHK0j.mjs → dist-fy1jz-eq.mjs} +40 -2
- package/dist/dist-fy1jz-eq.mjs.map +1 -0
- package/dist/{dist-DeMzV-BR.mjs → dist-v54rjb2O.mjs} +4 -4
- package/dist/{dist-DeMzV-BR.mjs.map → dist-v54rjb2O.mjs.map} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{maybe-auto-update-J-Am1CbS.mjs → maybe-auto-update-oRHYV8-i.mjs} +2 -2
- package/dist/{maybe-auto-update-J-Am1CbS.mjs.map → maybe-auto-update-oRHYV8-i.mjs.map} +1 -1
- package/dist/{program-BWeEKhR_.mjs → program-CKQqD-RE.mjs} +146 -146
- package/dist/program-CKQqD-RE.mjs.map +1 -0
- package/dist/{run-package-manager-update-CuLe-Jux.mjs → run-package-manager-update-D_nLqg4e.mjs} +2 -2
- package/dist/{run-package-manager-update-CuLe-Jux.mjs.map → run-package-manager-update-D_nLqg4e.mjs.map} +1 -1
- package/dist/skills-bundle/_AGENTS.mcp.md +5 -5
- package/dist/skills-bundle/_AGENTS.md +9 -7
- package/package.json +1 -1
- package/dist/dist-B_Dy4mW_.mjs +0 -3
- package/dist/dist-Cy2nsWsI.mjs.map +0 -1
- package/dist/dist-DMlQ27mb.mjs +0 -4
- package/dist/dist-Dg-PHK0j.mjs.map +0 -1
- package/dist/program-BWeEKhR_.mjs.map +0 -1
package/dist/{run-package-manager-update-CuLe-Jux.mjs → run-package-manager-update-D_nLqg4e.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { _i as originFromPublicUrl, zi as LOCAL_PLATFORM_ORIGIN } from "./dist-
|
|
2
|
+
import { _i as originFromPublicUrl, zi as LOCAL_PLATFORM_ORIGIN } from "./dist-BgPOKEEt.mjs";
|
|
3
3
|
import Conf from "conf";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
@@ -702,4 +702,4 @@ function runPackageManagerUpdate(install, distTag) {
|
|
|
702
702
|
//#endregion
|
|
703
703
|
export { resolvePlatformUrlForWebUrl as A, createCliConfig as C, getWebUrl as D, getPlatformUrl as E, ExpectedCliError as M, isExpectedCliError as N, DEFAULT_PLATFORM_URL as O, resolveCliRoot as S, getCredentialStorage as T, isLocalSdkSpec as _, formatReleaseAgeBlockMessage as a, shouldUpdateCliVersion as b, detectManagerFromLockfile as c, installDependencies as d, installPlaygroundDependencies as f, ensureSdkCurrent as g, CLI_PACKAGE_NAME as h, readPnpmMinimumReleaseAgeMinutes as i, parseCredentialStorage as j, DEFAULT_WEB_URL as k, buildPlaygroundWorkspace as l, resolvePackageManager as m, ensureMinimumReleaseAgeExclude as n, isReleaseAgeBlock as o, resolveGithubPackagesToken as p, computeReleaseAgeRetryAfter as r, detectCliInstall as s, runPackageManagerUpdate as t, detectPackageManager as u, fetchLatestCliRelease as v, getCliConfigDir as w, readCliVersion as x, resolveCliDistTag as y };
|
|
704
704
|
|
|
705
|
-
//# sourceMappingURL=run-package-manager-update-
|
|
705
|
+
//# sourceMappingURL=run-package-manager-update-D_nLqg4e.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-package-manager-update-CuLe-Jux.mjs","names":["CLI_PACKAGE_NAME"],"sources":["../src/errors/expected-cli-error.ts","../src/auth/credential-storage.ts","../src/resolve-platform-url.ts","../src/config.ts","../src/project/resolve-cli-root.ts","../src/version.ts","../../../packages/shared/dist/cli-release.mjs","../src/update/ensure-sdk-current.ts","../src/init/package-manager.ts","../src/update/detect-cli-install.ts","../src/update/detect-release-age-block.ts","../src/update/read-pnpm-release-age-minutes.ts","../src/update/resolve-global-pnpm-root.ts","../src/update/build-update-command.ts","../src/update/ensure-release-age-exclude.ts","../src/update/run-package-manager-update.ts"],"sourcesContent":["/**\n * User/project failures that are expected CLI exits (lint, typecheck, validation, etc.).\n * These should not become Error Tracking issues.\n */\nexport class ExpectedCliError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"ExpectedCliError\";\n }\n}\n\nexport function isExpectedCliError(error: unknown): error is ExpectedCliError {\n return error instanceof ExpectedCliError;\n}\n","import { ExpectedCliError } from \"../errors/expected-cli-error\";\n\nexport const CREDENTIAL_STORAGE_VALUES = [\"keychain\", \"file\"] as const;\n\nexport type CredentialStorage = (typeof CREDENTIAL_STORAGE_VALUES)[number];\n\nexport function isCredentialStorage(value: unknown): value is CredentialStorage {\n return value === \"keychain\" || value === \"file\";\n}\n\nexport function parseCredentialStorage(value: string): CredentialStorage {\n if (!isCredentialStorage(value)) {\n throw new ExpectedCliError(`Invalid credential storage \"${value}\". Use keychain or file.`);\n }\n return value;\n}\n","import { LOCAL_PLATFORM_ORIGIN, originFromPublicUrl } from \"@keystrokehq/shared\";\n\nexport const DEFAULT_WEB_URL = \"https://keystroke.ai\";\nexport const DEFAULT_PLATFORM_URL = \"https://api.keystroke.ai\";\nexport const LOCAL_WEB_URL = \"http://localhost:3000\";\n\nexport type ResolvePlatformUrlOptions = {\n platformUrl?: string;\n /** Used when webUrl does not match a known deployment. */\n fallback?: string;\n};\n\nfunction webOriginFromUrl(webUrl: string): string {\n return originFromPublicUrl(webUrl, webUrl.replace(/\\/+$/, \"\"));\n}\n\n/** Known web origins with a fixed platform API — undefined for custom/staging URLs. */\nexport function knownPlatformUrlForWebUrl(webUrl: string): string | undefined {\n const webOrigin = webOriginFromUrl(webUrl);\n\n if (webOrigin === LOCAL_WEB_URL || webOrigin === \"http://127.0.0.1:3000\") {\n return LOCAL_PLATFORM_ORIGIN;\n }\n\n if (webOrigin === DEFAULT_WEB_URL) {\n return DEFAULT_PLATFORM_URL;\n }\n\n return undefined;\n}\n\nexport function resolvePlatformUrlForWebUrl(\n webUrl: string,\n options: ResolvePlatformUrlOptions = {},\n): string {\n const explicit = options.platformUrl?.trim();\n if (explicit) {\n return explicit.replace(/\\/+$/, \"\");\n }\n\n const known = knownPlatformUrlForWebUrl(webUrl);\n if (known) {\n return known;\n }\n\n const fallback = options.fallback?.trim() || DEFAULT_PLATFORM_URL;\n return fallback.replace(/\\/+$/, \"\");\n}\n","import Conf from \"conf\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { isCredentialStorage, type CredentialStorage } from \"./auth/credential-storage\";\nimport {\n DEFAULT_PLATFORM_URL,\n DEFAULT_WEB_URL,\n knownPlatformUrlForWebUrl,\n resolvePlatformUrlForWebUrl,\n} from \"./resolve-platform-url\";\n\nexport type CliConfig = {\n webUrl: string;\n platformUrl: string;\n /** Where session tokens are stored. Defaults to OS keychain when unset. */\n credentialStorage?: CredentialStorage;\n};\n\nexport function getCliConfigDir(cwd = join(homedir(), \".keystroke\")): string {\n return cwd;\n}\n\nexport function getConfigDir(config: Conf<CliConfig>): string {\n return dirname(config.path);\n}\n\nfunction syncPlatformUrlWithWebUrl(config: Conf<CliConfig>): void {\n const webUrl = config.get(\"webUrl\");\n const known = knownPlatformUrlForWebUrl(webUrl);\n if (!known) {\n return;\n }\n\n const stored = config.get(\"platformUrl\");\n if (stored !== known) {\n config.set(\"platformUrl\", known);\n }\n}\n\nexport function createCliConfig(cwd = getCliConfigDir()): Conf<CliConfig> {\n const config = new Conf<CliConfig>({\n projectName: \"keystroke\",\n cwd,\n schema: {\n webUrl: {\n type: \"string\",\n default: DEFAULT_WEB_URL,\n },\n platformUrl: {\n type: \"string\",\n default: DEFAULT_PLATFORM_URL,\n },\n credentialStorage: {\n type: \"string\",\n enum: [\"keychain\", \"file\"],\n },\n },\n });\n\n syncPlatformUrlWithWebUrl(config);\n return config;\n}\n\n/** Effective credential backend — keychain unless the user explicitly chose file. */\nexport function getCredentialStorage(config: Conf<CliConfig>): CredentialStorage {\n const stored = config.get(\"credentialStorage\");\n return isCredentialStorage(stored) ? stored : \"keychain\";\n}\n\nexport function getWebUrl(config: Conf<CliConfig>): string {\n return config.get(\"webUrl\");\n}\n\nexport function getPlatformUrl(config: Conf<CliConfig>): string {\n const apiKey = process.env.KEYSTROKE_API_KEY?.trim();\n const fromEnv = process.env.KEYSTROKE_PLATFORM_URL?.trim();\n if (apiKey && fromEnv) {\n return fromEnv.replace(/\\/+$/, \"\");\n }\n return resolvePlatformUrlForWebUrl(getWebUrl(config), {\n fallback: config.get(\"platformUrl\"),\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nfunction isCliPackage(dir: string): boolean {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n return false;\n }\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { name?: string };\n return pkg.name === \"@keystrokehq/cli\";\n}\n\nexport function resolveCliRoot(fromModuleUrl: string): string {\n let dir = dirname(fileURLToPath(fromModuleUrl));\n\n while (dir !== dirname(dir)) {\n if (isCliPackage(dir)) {\n return dir;\n }\n\n dir = dirname(dir);\n }\n\n throw new Error(\"Could not resolve keystroke CLI package root\");\n}\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { resolveCliRoot } from \"./project/resolve-cli-root\";\n\nexport function readCliVersion(): string {\n const packageJsonPath = join(resolveCliRoot(import.meta.url), \"package.json\");\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: string };\n return pkg.version ?? \"0.0.0\";\n}\n","//#region src/cli-release.ts\nconst STAGING_PLATFORM_HOST = \"staging-api.keystroke.ai\";\nconst CLI_PACKAGE_NAME = \"@keystrokehq/cli\";\nconst REGISTRY_URL = \"https://registry.npmjs.org/@keystrokehq%2Fcli\";\nconst REQUEST_TIMEOUT_MS = 3e3;\n/**\n* npm dist-tag for `@keystrokehq/cli` auto-update / explicit update.\n*\n* Priority: KEYSTROKE_CLI_DIST_TAG → KEYSTROKE_ENVIRONMENT=staging →\n* staging platform URL → latest.\n*/\nfunction resolveCliDistTag(env = process.env) {\n\tconst explicit = env.KEYSTROKE_CLI_DIST_TAG?.trim();\n\tif (explicit) return explicit;\n\tif (env.KEYSTROKE_ENVIRONMENT?.trim() === \"staging\") return \"staging\";\n\tfor (const key of [\"KEYSTROKE_PLATFORM_URL\", \"PUBLIC_PLATFORM_URL\"]) {\n\t\tconst raw = env[key]?.trim();\n\t\tif (!raw) continue;\n\t\ttry {\n\t\t\tif (new URL(raw).hostname === STAGING_PLATFORM_HOST) return \"staging\";\n\t\t} catch {}\n\t}\n\treturn \"latest\";\n}\nfunction cliPackageSpec(distTagOrVersion = resolveCliDistTag()) {\n\treturn `${CLI_PACKAGE_NAME}@${distTagOrVersion}`;\n}\nfunction parseVersion(version) {\n\tconst [major = 0, minor = 0, patch = 0] = (version.trim().replace(/^v/, \"\").split(\"-\")[0] ?? \"\").split(\".\").map((part) => {\n\t\tconst value = Number.parseInt(part, 10);\n\t\treturn Number.isFinite(value) ? value : 0;\n\t});\n\treturn [\n\t\tmajor,\n\t\tminor,\n\t\tpatch\n\t];\n}\n/** `0.0.0-staging.<timestamp>` → timestamp, else undefined. */\nfunction stagingSnapshotTimestamp(version) {\n\tconst match = version.trim().replace(/^v/, \"\").match(/^0\\.0\\.0-staging\\.(\\d+)$/);\n\tif (!match?.[1]) return;\n\tconst value = Number.parseInt(match[1], 10);\n\treturn Number.isFinite(value) ? value : void 0;\n}\nfunction isStagingSnapshotVersion(version) {\n\treturn stagingSnapshotTimestamp(version) !== void 0;\n}\nfunction isNewerVersion(latest, current) {\n\tconst latestStaging = stagingSnapshotTimestamp(latest);\n\tconst currentStaging = stagingSnapshotTimestamp(current);\n\tif (latestStaging !== void 0 && currentStaging !== void 0) return latestStaging > currentStaging;\n\tconst [latestMajor, latestMinor, latestPatch] = parseVersion(latest);\n\tconst [currentMajor, currentMinor, currentPatch] = parseVersion(current);\n\tif (latestMajor !== currentMajor) return latestMajor > currentMajor;\n\tif (latestMinor !== currentMinor) return latestMinor > currentMinor;\n\treturn latestPatch > currentPatch;\n}\n/**\n* Whether auto-update / `keystroke update` should install `registryVersion`.\n* Handles channel switches (prod ↔ staging) where semver alone would refuse.\n*/\nfunction shouldUpdateCliVersion(input) {\n\tconst { registryVersion, currentVersion, distTag } = input;\n\tif (registryVersion.trim() === currentVersion.trim()) return false;\n\tconst currentIsStaging = isStagingSnapshotVersion(currentVersion);\n\tconst registryIsStaging = isStagingSnapshotVersion(registryVersion);\n\tif (distTag === \"staging\") {\n\t\tif (!currentIsStaging) return true;\n\t\treturn isNewerVersion(registryVersion, currentVersion);\n\t}\n\tif (currentIsStaging && !registryIsStaging) return true;\n\treturn isNewerVersion(registryVersion, currentVersion);\n}\nasync function fetchLatestCliRelease(distTag = resolveCliDistTag(), options) {\n\tconst timeoutMs = options?.timeoutMs ?? REQUEST_TIMEOUT_MS;\n\tconst fetchImpl = options?.fetchImpl ?? fetch;\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), timeoutMs);\n\ttry {\n\t\tconst response = await fetchImpl(REGISTRY_URL, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: { Accept: \"application/json\" }\n\t\t});\n\t\tif (!response.ok) return;\n\t\tconst payload = await response.json();\n\t\tconst version = payload[\"dist-tags\"]?.[distTag]?.trim();\n\t\tif (!version) return;\n\t\treturn {\n\t\t\tversion,\n\t\t\tpublishedAt: payload.time?.[version],\n\t\t\tdistTag\n\t\t};\n\t} catch {\n\t\treturn;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\nasync function fetchLatestCliVersion(distTag = resolveCliDistTag(), options) {\n\treturn (await fetchLatestCliRelease(distTag, options))?.version;\n}\n//#endregion\nexport { CLI_PACKAGE_NAME, cliPackageSpec, fetchLatestCliRelease, fetchLatestCliVersion, isNewerVersion, isStagingSnapshotVersion, resolveCliDistTag, shouldUpdateCliVersion };\n\n//# sourceMappingURL=cli-release.mjs.map","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { ExpectedCliError } from \"../errors/expected-cli-error\";\nimport { isNewerVersion } from \"./compare-version\";\n\nexport const SDK_PACKAGE_NAME = \"@keystrokehq/keystroke\";\nexport const CLI_PACKAGE_NAME = \"@keystrokehq/cli\";\n\nconst KEYSTROKE_SCOPE = \"@keystrokehq/\";\nconst REGISTRY_TIMEOUT_MS = 3_000;\n\ntype ManagedPackage = {\n name: string;\n};\n\ntype OutdatedPackage = {\n name: string;\n installed?: string;\n latest?: string;\n};\n\nfunction shouldSkip(): boolean {\n return Boolean(\n process.env.KEYSTROKE_SKIP_UPDATE || process.env.CI === \"true\" || process.env.CI === \"1\",\n );\n}\n\nfunction readPackageJson(root: string):\n | {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n }\n | undefined {\n const path = join(root, \"package.json\");\n if (!existsSync(path)) {\n return undefined;\n }\n\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n } catch {\n return undefined;\n }\n}\n\n/** Local/workspace specs are left alone; everything else (ranges and exact pins) must stay current. */\nexport function isLocalSdkSpec(spec: string | undefined): boolean {\n if (!spec) {\n return true;\n }\n\n const trimmed = spec.trim();\n return (\n trimmed.startsWith(\"workspace:\") || trimmed.startsWith(\"link:\") || trimmed.startsWith(\"file:\")\n );\n}\n\nfunction listManagedKeystrokePackages(root: string): ManagedPackage[] {\n const pkg = readPackageJson(root);\n if (!pkg) {\n return [];\n }\n\n const packages: ManagedPackage[] = [];\n\n for (const [name, spec] of Object.entries({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n })) {\n // CLI is global + self-updating; never gate project deps on a local copy.\n if (name === CLI_PACKAGE_NAME) {\n continue;\n }\n if (name.startsWith(KEYSTROKE_SCOPE) && !isLocalSdkSpec(spec)) {\n packages.push({ name });\n }\n }\n\n return packages;\n}\n\nfunction readInstalledVersion(root: string, packageName: string): string | undefined {\n const path = join(root, \"node_modules\", ...packageName.split(\"/\"), \"package.json\");\n if (!existsSync(path)) {\n return undefined;\n }\n\n try {\n const pkg = JSON.parse(readFileSync(path, \"utf8\")) as { version?: string };\n const version = pkg.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function fetchLatestPackageVersion(packageName: string): Promise<string | undefined> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REGISTRY_TIMEOUT_MS);\n\n try {\n const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`, {\n signal: controller.signal,\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n return undefined;\n }\n\n const payload = (await response.json()) as {\n \"dist-tags\"?: { latest?: string };\n };\n return payload[\"dist-tags\"]?.latest?.trim() || undefined;\n } catch {\n return undefined;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction formatOutdatedLine(pkg: OutdatedPackage): string {\n if (pkg.installed && pkg.latest) {\n return `- ${pkg.name} (${pkg.installed} → ${pkg.latest})`;\n }\n if (pkg.latest) {\n return `- ${pkg.name} (not installed → ${pkg.latest})`;\n }\n return `- ${pkg.name}`;\n}\n\nasync function packagesNeedingUpdate(\n root: string,\n packages: ManagedPackage[],\n): Promise<OutdatedPackage[]> {\n const checks = await Promise.all(\n packages.map(async (pkg): Promise<OutdatedPackage | undefined> => {\n const installed = readInstalledVersion(root, pkg.name);\n const latest = await fetchLatestPackageVersion(pkg.name);\n\n // Unknown registry: only fail when the package isn't present locally.\n if (!latest) {\n return installed ? undefined : { name: pkg.name, installed };\n }\n\n if (!installed || isNewerVersion(latest, installed)) {\n return { name: pkg.name, installed, latest };\n }\n\n return undefined;\n }),\n );\n\n return checks.flatMap((pkg) => (pkg ? [pkg] : []));\n}\n\n/**\n * Require @keystrokehq/* project dependencies to be on latest before build/deploy.\n * Skips `@keystrokehq/cli` (global + self-updating). Throws instead of auto-installing.\n */\nexport async function ensureSdkCurrent(root: string): Promise<void> {\n if (shouldSkip()) {\n return;\n }\n\n const packages = listManagedKeystrokePackages(root);\n if (packages.length === 0) {\n return;\n }\n\n const outdated = await packagesNeedingUpdate(root, packages);\n if (outdated.length === 0) {\n return;\n }\n\n const lines = outdated.map(formatOutdatedLine).join(\"\\n\");\n throw new ExpectedCliError(\n `@keystrokehq packages are behind npm latest:\\n${lines}\\n\\n` +\n `Run \\`keystroke update\\`, then retry.`,\n );\n}\n","import { spawnSync } from \"node:child_process\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nconst MANAGERS: PackageManager[] = [\"pnpm\", \"npm\", \"yarn\", \"bun\"];\n\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent ?? \"\";\n\n for (const manager of MANAGERS) {\n if (userAgent.startsWith(manager)) {\n return manager;\n }\n }\n\n if (process.env.PNPM_HOME) {\n return \"pnpm\";\n }\n\n return \"npm\";\n}\n\nexport function resolvePackageManager(explicit?: string): PackageManager {\n if (!explicit) {\n return detectPackageManager();\n }\n\n const normalized = explicit.trim().toLowerCase();\n if (!MANAGERS.includes(normalized as PackageManager)) {\n throw new Error(`Unsupported package manager \"${explicit}\". Use npm, pnpm, yarn, or bun.`);\n }\n\n return normalized as PackageManager;\n}\n\n/** Resolve GitHub Packages auth for @keystrokehq/* when NODE_AUTH_TOKEN is unset. */\nexport function resolveGithubPackagesToken(): string | undefined {\n if (process.env.NODE_AUTH_TOKEN) {\n return process.env.NODE_AUTH_TOKEN;\n }\n\n for (const key of [\"GITHUB_TOKEN\", \"GH_TOKEN\"] as const) {\n const value = process.env[key];\n if (value) {\n return value;\n }\n }\n\n const gh = spawnSync(\"gh\", [\"auth\", \"token\"], { encoding: \"utf8\" });\n if (gh.status === 0) {\n const token = gh.stdout.trim();\n if (token) {\n return token;\n }\n }\n\n return undefined;\n}\n\nexport function installDependencies(cwd: string, manager: PackageManager): void {\n const token = resolveGithubPackagesToken();\n const env = token ? { ...process.env, NODE_AUTH_TOKEN: token } : process.env;\n\n const result = spawnSync(manager, [\"install\"], {\n cwd,\n stdio: \"inherit\",\n env,\n });\n\n if (result.status !== 0) {\n throw new Error(`${manager} install failed`);\n }\n}\n\nexport function installPlaygroundDependencies(cwd: string): void {\n const result = spawnSync(\"pnpm\", [\"install\", \"--ignore-workspace\"], {\n cwd,\n stdio: \"inherit\",\n env: process.env,\n });\n\n if (result.status !== 0) {\n throw new Error(\"pnpm install failed\");\n }\n}\n\n/**\n * Build every workspace package so the playground's `link:` deps resolve to\n * compiled `dist/`. Without this, local imports fail with\n * `ERR_MODULE_NOT_FOUND` against whichever package was never built. Turbo\n * caches, so this is only slow on the first run.\n */\nexport function buildPlaygroundWorkspace(monorepoRoot: string): void {\n // Build with a clean Node env: the `keystroke-dev` wrapper sets\n // NODE_OPTIONS=--conditions=development, which would make tsdown/turbo resolve\n // their own deps to src/ and fail. Dropping NODE_OPTIONS builds to dist/ normally.\n const { NODE_OPTIONS: _drop, ...buildEnv } = process.env;\n const result = spawnSync(\"pnpm\", [\"run\", \"build\"], {\n cwd: monorepoRoot,\n stdio: \"inherit\",\n env: buildEnv,\n });\n\n if (result.status !== 0) {\n throw new Error(\"workspace build failed (pnpm run build)\");\n }\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\n\nimport { detectPackageManager, type PackageManager } from \"../init/package-manager\";\n\nexport type CliInstallKind = \"global\" | \"local\";\n\nexport type CliInstallInfo = {\n kind: CliInstallKind;\n packageManager: PackageManager;\n packageRoot: string;\n projectRoot?: string;\n /**\n * When the CLI was installed with `npm install -g --prefix <dir>` (Modal /\n * session images use `/root/.keystroke`), updates must pass the same prefix\n * so npm does not fight a `/usr/local/bin/keystroke` symlink.\n */\n npmPrefix?: string;\n};\n\nfunction realpathSafe(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return path;\n }\n}\n\n/**\n * Resolve an npm `--prefix` root from a global package path.\n * Layout: `<prefix>/lib/node_modules/@keystrokehq/cli`.\n */\nexport function resolveNpmInstallPrefix(packageRoot: string): string | undefined {\n const normalized = packageRoot.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const match = normalized.match(/^(.*)\\/lib\\/node_modules\\/@keystrokehq\\/cli$/);\n const prefix = match?.[1]?.trim();\n return prefix && prefix.length > 0 ? prefix : undefined;\n}\n\nexport function detectManagerFromLockfile(dir: string): PackageManager | undefined {\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) {\n return \"pnpm\";\n }\n\n if (existsSync(join(dir, \"bun.lockb\")) || existsSync(join(dir, \"bun.lock\"))) {\n return \"bun\";\n }\n\n if (existsSync(join(dir, \"yarn.lock\"))) {\n return \"yarn\";\n }\n\n if (existsSync(join(dir, \"package-lock.json\"))) {\n return \"npm\";\n }\n\n return undefined;\n}\n\nfunction findLocalProjectRoot(packageRoot: string): string | undefined {\n const normalizedRoot = realpathSafe(packageRoot);\n let dir = dirname(packageRoot);\n\n while (dir !== dirname(dir)) {\n const installedCliPath = join(dir, \"node_modules\", \"@keystrokehq\", \"cli\");\n if (\n existsSync(join(dir, \"package.json\")) &&\n realpathSafe(installedCliPath) === normalizedRoot\n ) {\n return dir;\n }\n\n dir = dirname(dir);\n }\n\n return undefined;\n}\n\nfunction globalRootForManager(manager: PackageManager): string | undefined {\n const commands: Record<PackageManager, { command: string; args: string[] }> = {\n pnpm: { command: \"pnpm\", args: [\"root\", \"-g\"] },\n npm: { command: \"npm\", args: [\"root\", \"-g\"] },\n yarn: { command: \"yarn\", args: [\"global\", \"dir\"] },\n bun: { command: \"bun\", args: [\"pm\", \"bin\"] },\n };\n\n const { command, args } = commands[manager];\n const result = spawnSync(command, args, { encoding: \"utf8\" });\n\n if (result.status !== 0) {\n return undefined;\n }\n\n const root = result.stdout.trim();\n return root ? realpathSafe(root) : undefined;\n}\n\nfunction detectGlobalManager(packageRoot: string): PackageManager {\n const normalizedRoot = realpathSafe(packageRoot);\n\n if (normalizedRoot.includes(`${join(\"\", \".pnpm\")}`)) {\n return \"pnpm\";\n }\n\n for (const manager of [\"pnpm\", \"npm\", \"yarn\", \"bun\"] as const) {\n const globalRoot = globalRootForManager(manager);\n if (globalRoot && normalizedRoot.startsWith(globalRoot)) {\n return manager;\n }\n }\n\n if (process.env.PNPM_HOME) {\n return \"pnpm\";\n }\n\n return detectPackageManager();\n}\n\nexport function detectCliInstall(packageRoot: string): CliInstallInfo | undefined {\n const normalizedRoot = realpathSafe(packageRoot);\n const projectRoot = findLocalProjectRoot(normalizedRoot);\n\n if (projectRoot) {\n const packageManager = detectManagerFromLockfile(projectRoot) ?? detectPackageManager();\n\n return {\n kind: \"local\",\n packageManager,\n packageRoot: normalizedRoot,\n projectRoot,\n };\n }\n\n const npmPrefix = resolveNpmInstallPrefix(normalizedRoot);\n if (npmPrefix) {\n return {\n kind: \"global\",\n packageManager: \"npm\",\n packageRoot: normalizedRoot,\n npmPrefix,\n };\n }\n\n return {\n kind: \"global\",\n packageManager: detectGlobalManager(normalizedRoot),\n packageRoot: normalizedRoot,\n };\n}\n","const RELEASE_AGE_PATTERNS = [\n /minimumReleaseAge/i,\n /minimum-release-age/i,\n /ERR_PNPM_NO_MATURE_MATCHING_VERSION/,\n /ERR_PNPM_MINIMUM_RELEASE_AGE/,\n /does not meet the minimumReleaseAge constraint/,\n];\n\nexport function isReleaseAgeBlock(output: string): boolean {\n return RELEASE_AGE_PATTERNS.some((pattern) => pattern.test(output));\n}\n\nexport function formatReleaseAgeBlockMessage(options: {\n currentVersion: string;\n availableVersion: string;\n retryAfter?: Date;\n}): string {\n const retry =\n options.retryAfter !== undefined ? ` Retry after ${options.retryAfter.toLocaleString()}.` : \"\";\n\n return (\n `@keystrokehq/cli ${options.availableVersion} is available but blocked by your ` +\n `minimum-release-age setting. You're on ${options.currentVersion}.${retry} ` +\n `Run \\`keystroke update\\` again — it bypasses minimum-release-age for @keystrokehq packages and retries.`\n );\n}\n","import { spawnSync } from \"node:child_process\";\n\nexport function readPnpmMinimumReleaseAgeMinutes(): number | undefined {\n const result = spawnSync(\"pnpm\", [\"config\", \"get\", \"minimum-release-age\"], {\n encoding: \"utf8\",\n });\n\n if (result.status !== 0) {\n return undefined;\n }\n\n const value = result.stdout.trim();\n if (!value || value === \"undefined\" || value === \"0\") {\n return undefined;\n }\n\n const minutes = Number.parseInt(value, 10);\n return Number.isFinite(minutes) && minutes > 0 ? minutes : undefined;\n}\n\nexport function computeReleaseAgeRetryAfter(\n publishedAt: string | undefined,\n minimumReleaseAgeMinutes: number | undefined,\n): Date | undefined {\n if (!publishedAt || !minimumReleaseAgeMinutes) {\n return undefined;\n }\n\n const publishedMs = Date.parse(publishedAt);\n if (!Number.isFinite(publishedMs)) {\n return undefined;\n }\n\n return new Date(publishedMs + minimumReleaseAgeMinutes * 60_000);\n}\n","/** pnpm global installs live in `<pnpm-home>/global/<major>/`. */\nexport function resolveGlobalPnpmRoot(packageRoot: string): string | undefined {\n const normalized = packageRoot.replace(/\\\\/g, \"/\");\n const match = normalized.match(/^(.*\\/global\\/\\d+)\\//);\n return match?.[1];\n}\n","import type { CliInstallInfo } from \"./detect-cli-install\";\nimport { cliPackageSpec, resolveCliDistTag } from \"./resolve-cli-dist-tag\";\nimport { resolveGlobalPnpmRoot } from \"./resolve-global-pnpm-root\";\n\nexport function buildUpdateCommand(\n install: CliInstallInfo,\n distTag: string = resolveCliDistTag(),\n): {\n command: string;\n args: string[];\n cwd?: string;\n} {\n const { kind, packageManager } = install;\n const packageName = cliPackageSpec(distTag);\n\n if (kind === \"global\") {\n switch (packageManager) {\n case \"pnpm\":\n return {\n command: \"pnpm\",\n args: [\"add\", \"-g\", packageName],\n cwd: resolveGlobalPnpmRoot(install.packageRoot),\n };\n case \"yarn\":\n return { command: \"yarn\", args: [\"global\", \"add\", packageName] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", \"-g\", packageName] };\n case \"npm\":\n default:\n if (install.npmPrefix) {\n return {\n command: \"npm\",\n args: [\"install\", \"-g\", \"--prefix\", install.npmPrefix, packageName],\n };\n }\n return { command: \"npm\", args: [\"install\", \"-g\", packageName] };\n }\n }\n\n const cwd = install.projectRoot;\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", \"-D\", packageName], cwd };\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", \"-D\", packageName], cwd };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", \"-D\", packageName], cwd };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"install\", \"-D\", packageName], cwd };\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst EXCLUDE_PREFIX = \"minimum-release-age-exclude[]=\";\n\nfunction npmrcPath(root: string): string {\n return join(root, \".npmrc\");\n}\n\n/** Package names already listed as `minimum-release-age-exclude[]=` in an .npmrc body. */\nexport function parseMinimumReleaseAgeExcludes(contents: string): string[] {\n const found: string[] = [];\n for (const rawLine of contents.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (!line.startsWith(EXCLUDE_PREFIX)) {\n continue;\n }\n const value = line.slice(EXCLUDE_PREFIX.length).trim();\n if (value) {\n found.push(value);\n }\n }\n return found;\n}\n\n/**\n * Ensure each package is listed in the project `.npmrc` as\n * `minimum-release-age-exclude[]=<name>` so `pnpm add pkg@latest` is not held\n * back by minimum-release-age. Creates `.npmrc` when missing.\n *\n * Returns the packages that were newly added (empty when already present).\n */\nexport function ensureMinimumReleaseAgeExclude(root: string, packageNames: string[]): string[] {\n const unique = [...new Set(packageNames.map((name) => name.trim()).filter(Boolean))].sort();\n if (unique.length === 0) {\n return [];\n }\n\n const path = npmrcPath(root);\n const existing = existsSync(path) ? readFileSync(path, \"utf8\") : \"\";\n const already = new Set(parseMinimumReleaseAgeExcludes(existing));\n const added = unique.filter((name) => !already.has(name));\n if (added.length === 0) {\n return [];\n }\n\n const trimmed = existing.replace(/\\s+$/, \"\");\n const next = [\n ...(trimmed.length > 0 ? [trimmed] : []),\n ...added.map((name) => `${EXCLUDE_PREFIX}${name}`),\n \"\",\n ].join(\"\\n\");\n writeFileSync(path, next, \"utf8\");\n return added;\n}\n","import { spawnSync } from \"node:child_process\";\n\nimport { buildUpdateCommand } from \"./build-update-command\";\nimport type { CliInstallInfo } from \"./detect-cli-install\";\nimport { isReleaseAgeBlock } from \"./detect-release-age-block\";\nimport { ensureMinimumReleaseAgeExclude } from \"./ensure-release-age-exclude\";\nimport { CLI_PACKAGE_NAME } from \"./ensure-sdk-current\";\n\nexport function updateSpawnEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n const pnpmHome = env.PNPM_HOME;\n\n if (!pnpmHome) {\n return env;\n }\n\n const pathKey = process.platform === \"win32\" ? \"Path\" : \"PATH\";\n const path = env[pathKey] ?? \"\";\n const segments = path.split(process.platform === \"win32\" ? \";\" : \":\");\n const binDir = `${pnpmHome}/bin`;\n const prefix = [binDir, pnpmHome].filter((dir) => !segments.includes(dir));\n\n if (prefix.length > 0) {\n env[pathKey] = [...prefix, path].filter(Boolean).join(process.platform === \"win32\" ? \";\" : \":\");\n }\n\n return env;\n}\n\nexport type PackageManagerRunResult = {\n ok: boolean;\n output: string;\n};\n\nfunction runPackageManager(command: string, args: string[], cwd?: string): PackageManagerRunResult {\n const result = spawnSync(command, args, {\n cwd,\n encoding: \"utf8\",\n env: updateSpawnEnv(),\n });\n\n const output = `${result.stdout ?? \"\"}${result.stderr ?? \"\"}`;\n\n return {\n ok: result.status === 0,\n output,\n };\n}\n\nfunction migratePnpmGlobal(cwd: string): boolean {\n const result = spawnSync(\"pnpm\", [\"install\"], {\n cwd,\n encoding: \"utf8\",\n env: {\n ...updateSpawnEnv(),\n CI: \"true\",\n },\n });\n\n return result.status === 0;\n}\n\n/** Bypass minimum-release-age for this one CLI install without editing user config. */\nfunction withCliReleaseAgeExclude(args: string[]): string[] {\n return [...args, `--config.minimum-release-age-exclude[]=${CLI_PACKAGE_NAME}`];\n}\n\nexport function runPackageManagerUpdate(\n install: CliInstallInfo,\n distTag?: string,\n): PackageManagerRunResult {\n const { command, args, cwd } = buildUpdateCommand(install, distTag);\n const firstAttempt = runPackageManager(command, args, cwd);\n\n if (firstAttempt.ok) {\n return firstAttempt;\n }\n\n if (install.kind === \"global\" && install.packageManager === \"pnpm\" && cwd) {\n if (migratePnpmGlobal(cwd)) {\n const migrated = runPackageManager(command, args, cwd);\n if (migrated.ok) {\n return migrated;\n }\n }\n }\n\n if (install.packageManager === \"pnpm\" && isReleaseAgeBlock(firstAttempt.output)) {\n if (install.kind === \"local\" && install.projectRoot) {\n const added = ensureMinimumReleaseAgeExclude(install.projectRoot, [CLI_PACKAGE_NAME]);\n if (added.length > 0) {\n process.stderr.write(\n `Added ${CLI_PACKAGE_NAME} to .npmrc minimum-release-age-exclude; retrying CLI update...\\n`,\n );\n }\n return runPackageManager(command, args, cwd);\n }\n\n process.stderr.write(\n `Retrying CLI update with temporary minimum-release-age-exclude for ${CLI_PACKAGE_NAME}...\\n`,\n );\n return runPackageManager(command, withCliReleaseAgeExclude(args), cwd);\n }\n\n return firstAttempt;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-package-manager-update-D_nLqg4e.mjs","names":["CLI_PACKAGE_NAME"],"sources":["../src/errors/expected-cli-error.ts","../src/auth/credential-storage.ts","../src/resolve-platform-url.ts","../src/config.ts","../src/project/resolve-cli-root.ts","../src/version.ts","../../../packages/shared/dist/cli-release.mjs","../src/update/ensure-sdk-current.ts","../src/init/package-manager.ts","../src/update/detect-cli-install.ts","../src/update/detect-release-age-block.ts","../src/update/read-pnpm-release-age-minutes.ts","../src/update/resolve-global-pnpm-root.ts","../src/update/build-update-command.ts","../src/update/ensure-release-age-exclude.ts","../src/update/run-package-manager-update.ts"],"sourcesContent":["/**\n * User/project failures that are expected CLI exits (lint, typecheck, validation, etc.).\n * These should not become Error Tracking issues.\n */\nexport class ExpectedCliError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"ExpectedCliError\";\n }\n}\n\nexport function isExpectedCliError(error: unknown): error is ExpectedCliError {\n return error instanceof ExpectedCliError;\n}\n","import { ExpectedCliError } from \"../errors/expected-cli-error\";\n\nexport const CREDENTIAL_STORAGE_VALUES = [\"keychain\", \"file\"] as const;\n\nexport type CredentialStorage = (typeof CREDENTIAL_STORAGE_VALUES)[number];\n\nexport function isCredentialStorage(value: unknown): value is CredentialStorage {\n return value === \"keychain\" || value === \"file\";\n}\n\nexport function parseCredentialStorage(value: string): CredentialStorage {\n if (!isCredentialStorage(value)) {\n throw new ExpectedCliError(`Invalid credential storage \"${value}\". Use keychain or file.`);\n }\n return value;\n}\n","import { LOCAL_PLATFORM_ORIGIN, originFromPublicUrl } from \"@keystrokehq/shared\";\n\nexport const DEFAULT_WEB_URL = \"https://keystroke.ai\";\nexport const DEFAULT_PLATFORM_URL = \"https://api.keystroke.ai\";\nexport const LOCAL_WEB_URL = \"http://localhost:3000\";\n\nexport type ResolvePlatformUrlOptions = {\n platformUrl?: string;\n /** Used when webUrl does not match a known deployment. */\n fallback?: string;\n};\n\nfunction webOriginFromUrl(webUrl: string): string {\n return originFromPublicUrl(webUrl, webUrl.replace(/\\/+$/, \"\"));\n}\n\n/** Known web origins with a fixed platform API — undefined for custom/staging URLs. */\nexport function knownPlatformUrlForWebUrl(webUrl: string): string | undefined {\n const webOrigin = webOriginFromUrl(webUrl);\n\n if (webOrigin === LOCAL_WEB_URL || webOrigin === \"http://127.0.0.1:3000\") {\n return LOCAL_PLATFORM_ORIGIN;\n }\n\n if (webOrigin === DEFAULT_WEB_URL) {\n return DEFAULT_PLATFORM_URL;\n }\n\n return undefined;\n}\n\nexport function resolvePlatformUrlForWebUrl(\n webUrl: string,\n options: ResolvePlatformUrlOptions = {},\n): string {\n const explicit = options.platformUrl?.trim();\n if (explicit) {\n return explicit.replace(/\\/+$/, \"\");\n }\n\n const known = knownPlatformUrlForWebUrl(webUrl);\n if (known) {\n return known;\n }\n\n const fallback = options.fallback?.trim() || DEFAULT_PLATFORM_URL;\n return fallback.replace(/\\/+$/, \"\");\n}\n","import Conf from \"conf\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { isCredentialStorage, type CredentialStorage } from \"./auth/credential-storage\";\nimport {\n DEFAULT_PLATFORM_URL,\n DEFAULT_WEB_URL,\n knownPlatformUrlForWebUrl,\n resolvePlatformUrlForWebUrl,\n} from \"./resolve-platform-url\";\n\nexport type CliConfig = {\n webUrl: string;\n platformUrl: string;\n /** Where session tokens are stored. Defaults to OS keychain when unset. */\n credentialStorage?: CredentialStorage;\n};\n\nexport function getCliConfigDir(cwd = join(homedir(), \".keystroke\")): string {\n return cwd;\n}\n\nexport function getConfigDir(config: Conf<CliConfig>): string {\n return dirname(config.path);\n}\n\nfunction syncPlatformUrlWithWebUrl(config: Conf<CliConfig>): void {\n const webUrl = config.get(\"webUrl\");\n const known = knownPlatformUrlForWebUrl(webUrl);\n if (!known) {\n return;\n }\n\n const stored = config.get(\"platformUrl\");\n if (stored !== known) {\n config.set(\"platformUrl\", known);\n }\n}\n\nexport function createCliConfig(cwd = getCliConfigDir()): Conf<CliConfig> {\n const config = new Conf<CliConfig>({\n projectName: \"keystroke\",\n cwd,\n schema: {\n webUrl: {\n type: \"string\",\n default: DEFAULT_WEB_URL,\n },\n platformUrl: {\n type: \"string\",\n default: DEFAULT_PLATFORM_URL,\n },\n credentialStorage: {\n type: \"string\",\n enum: [\"keychain\", \"file\"],\n },\n },\n });\n\n syncPlatformUrlWithWebUrl(config);\n return config;\n}\n\n/** Effective credential backend — keychain unless the user explicitly chose file. */\nexport function getCredentialStorage(config: Conf<CliConfig>): CredentialStorage {\n const stored = config.get(\"credentialStorage\");\n return isCredentialStorage(stored) ? stored : \"keychain\";\n}\n\nexport function getWebUrl(config: Conf<CliConfig>): string {\n return config.get(\"webUrl\");\n}\n\nexport function getPlatformUrl(config: Conf<CliConfig>): string {\n const apiKey = process.env.KEYSTROKE_API_KEY?.trim();\n const fromEnv = process.env.KEYSTROKE_PLATFORM_URL?.trim();\n if (apiKey && fromEnv) {\n return fromEnv.replace(/\\/+$/, \"\");\n }\n return resolvePlatformUrlForWebUrl(getWebUrl(config), {\n fallback: config.get(\"platformUrl\"),\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nfunction isCliPackage(dir: string): boolean {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n return false;\n }\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { name?: string };\n return pkg.name === \"@keystrokehq/cli\";\n}\n\nexport function resolveCliRoot(fromModuleUrl: string): string {\n let dir = dirname(fileURLToPath(fromModuleUrl));\n\n while (dir !== dirname(dir)) {\n if (isCliPackage(dir)) {\n return dir;\n }\n\n dir = dirname(dir);\n }\n\n throw new Error(\"Could not resolve keystroke CLI package root\");\n}\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { resolveCliRoot } from \"./project/resolve-cli-root\";\n\nexport function readCliVersion(): string {\n const packageJsonPath = join(resolveCliRoot(import.meta.url), \"package.json\");\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: string };\n return pkg.version ?? \"0.0.0\";\n}\n","//#region src/cli-release.ts\nconst STAGING_PLATFORM_HOST = \"staging-api.keystroke.ai\";\nconst CLI_PACKAGE_NAME = \"@keystrokehq/cli\";\nconst REGISTRY_URL = \"https://registry.npmjs.org/@keystrokehq%2Fcli\";\nconst REQUEST_TIMEOUT_MS = 3e3;\n/**\n* npm dist-tag for `@keystrokehq/cli` auto-update / explicit update.\n*\n* Priority: KEYSTROKE_CLI_DIST_TAG → KEYSTROKE_ENVIRONMENT=staging →\n* staging platform URL → latest.\n*/\nfunction resolveCliDistTag(env = process.env) {\n\tconst explicit = env.KEYSTROKE_CLI_DIST_TAG?.trim();\n\tif (explicit) return explicit;\n\tif (env.KEYSTROKE_ENVIRONMENT?.trim() === \"staging\") return \"staging\";\n\tfor (const key of [\"KEYSTROKE_PLATFORM_URL\", \"PUBLIC_PLATFORM_URL\"]) {\n\t\tconst raw = env[key]?.trim();\n\t\tif (!raw) continue;\n\t\ttry {\n\t\t\tif (new URL(raw).hostname === STAGING_PLATFORM_HOST) return \"staging\";\n\t\t} catch {}\n\t}\n\treturn \"latest\";\n}\nfunction cliPackageSpec(distTagOrVersion = resolveCliDistTag()) {\n\treturn `${CLI_PACKAGE_NAME}@${distTagOrVersion}`;\n}\nfunction parseVersion(version) {\n\tconst [major = 0, minor = 0, patch = 0] = (version.trim().replace(/^v/, \"\").split(\"-\")[0] ?? \"\").split(\".\").map((part) => {\n\t\tconst value = Number.parseInt(part, 10);\n\t\treturn Number.isFinite(value) ? value : 0;\n\t});\n\treturn [\n\t\tmajor,\n\t\tminor,\n\t\tpatch\n\t];\n}\n/** `0.0.0-staging.<timestamp>` → timestamp, else undefined. */\nfunction stagingSnapshotTimestamp(version) {\n\tconst match = version.trim().replace(/^v/, \"\").match(/^0\\.0\\.0-staging\\.(\\d+)$/);\n\tif (!match?.[1]) return;\n\tconst value = Number.parseInt(match[1], 10);\n\treturn Number.isFinite(value) ? value : void 0;\n}\nfunction isStagingSnapshotVersion(version) {\n\treturn stagingSnapshotTimestamp(version) !== void 0;\n}\nfunction isNewerVersion(latest, current) {\n\tconst latestStaging = stagingSnapshotTimestamp(latest);\n\tconst currentStaging = stagingSnapshotTimestamp(current);\n\tif (latestStaging !== void 0 && currentStaging !== void 0) return latestStaging > currentStaging;\n\tconst [latestMajor, latestMinor, latestPatch] = parseVersion(latest);\n\tconst [currentMajor, currentMinor, currentPatch] = parseVersion(current);\n\tif (latestMajor !== currentMajor) return latestMajor > currentMajor;\n\tif (latestMinor !== currentMinor) return latestMinor > currentMinor;\n\treturn latestPatch > currentPatch;\n}\n/**\n* Whether auto-update / `keystroke update` should install `registryVersion`.\n* Handles channel switches (prod ↔ staging) where semver alone would refuse.\n*/\nfunction shouldUpdateCliVersion(input) {\n\tconst { registryVersion, currentVersion, distTag } = input;\n\tif (registryVersion.trim() === currentVersion.trim()) return false;\n\tconst currentIsStaging = isStagingSnapshotVersion(currentVersion);\n\tconst registryIsStaging = isStagingSnapshotVersion(registryVersion);\n\tif (distTag === \"staging\") {\n\t\tif (!currentIsStaging) return true;\n\t\treturn isNewerVersion(registryVersion, currentVersion);\n\t}\n\tif (currentIsStaging && !registryIsStaging) return true;\n\treturn isNewerVersion(registryVersion, currentVersion);\n}\nasync function fetchLatestCliRelease(distTag = resolveCliDistTag(), options) {\n\tconst timeoutMs = options?.timeoutMs ?? REQUEST_TIMEOUT_MS;\n\tconst fetchImpl = options?.fetchImpl ?? fetch;\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), timeoutMs);\n\ttry {\n\t\tconst response = await fetchImpl(REGISTRY_URL, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: { Accept: \"application/json\" }\n\t\t});\n\t\tif (!response.ok) return;\n\t\tconst payload = await response.json();\n\t\tconst version = payload[\"dist-tags\"]?.[distTag]?.trim();\n\t\tif (!version) return;\n\t\treturn {\n\t\t\tversion,\n\t\t\tpublishedAt: payload.time?.[version],\n\t\t\tdistTag\n\t\t};\n\t} catch {\n\t\treturn;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\nasync function fetchLatestCliVersion(distTag = resolveCliDistTag(), options) {\n\treturn (await fetchLatestCliRelease(distTag, options))?.version;\n}\n//#endregion\nexport { CLI_PACKAGE_NAME, cliPackageSpec, fetchLatestCliRelease, fetchLatestCliVersion, isNewerVersion, isStagingSnapshotVersion, resolveCliDistTag, shouldUpdateCliVersion };\n\n//# sourceMappingURL=cli-release.mjs.map","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { ExpectedCliError } from \"../errors/expected-cli-error\";\nimport { isNewerVersion } from \"./compare-version\";\n\nexport const SDK_PACKAGE_NAME = \"@keystrokehq/keystroke\";\nexport const CLI_PACKAGE_NAME = \"@keystrokehq/cli\";\n\nconst KEYSTROKE_SCOPE = \"@keystrokehq/\";\nconst REGISTRY_TIMEOUT_MS = 3_000;\n\ntype ManagedPackage = {\n name: string;\n};\n\ntype OutdatedPackage = {\n name: string;\n installed?: string;\n latest?: string;\n};\n\nfunction shouldSkip(): boolean {\n return Boolean(\n process.env.KEYSTROKE_SKIP_UPDATE || process.env.CI === \"true\" || process.env.CI === \"1\",\n );\n}\n\nfunction readPackageJson(root: string):\n | {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n }\n | undefined {\n const path = join(root, \"package.json\");\n if (!existsSync(path)) {\n return undefined;\n }\n\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n } catch {\n return undefined;\n }\n}\n\n/** Local/workspace specs are left alone; everything else (ranges and exact pins) must stay current. */\nexport function isLocalSdkSpec(spec: string | undefined): boolean {\n if (!spec) {\n return true;\n }\n\n const trimmed = spec.trim();\n return (\n trimmed.startsWith(\"workspace:\") || trimmed.startsWith(\"link:\") || trimmed.startsWith(\"file:\")\n );\n}\n\nfunction listManagedKeystrokePackages(root: string): ManagedPackage[] {\n const pkg = readPackageJson(root);\n if (!pkg) {\n return [];\n }\n\n const packages: ManagedPackage[] = [];\n\n for (const [name, spec] of Object.entries({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n })) {\n // CLI is global + self-updating; never gate project deps on a local copy.\n if (name === CLI_PACKAGE_NAME) {\n continue;\n }\n if (name.startsWith(KEYSTROKE_SCOPE) && !isLocalSdkSpec(spec)) {\n packages.push({ name });\n }\n }\n\n return packages;\n}\n\nfunction readInstalledVersion(root: string, packageName: string): string | undefined {\n const path = join(root, \"node_modules\", ...packageName.split(\"/\"), \"package.json\");\n if (!existsSync(path)) {\n return undefined;\n }\n\n try {\n const pkg = JSON.parse(readFileSync(path, \"utf8\")) as { version?: string };\n const version = pkg.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function fetchLatestPackageVersion(packageName: string): Promise<string | undefined> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REGISTRY_TIMEOUT_MS);\n\n try {\n const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`, {\n signal: controller.signal,\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n return undefined;\n }\n\n const payload = (await response.json()) as {\n \"dist-tags\"?: { latest?: string };\n };\n return payload[\"dist-tags\"]?.latest?.trim() || undefined;\n } catch {\n return undefined;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction formatOutdatedLine(pkg: OutdatedPackage): string {\n if (pkg.installed && pkg.latest) {\n return `- ${pkg.name} (${pkg.installed} → ${pkg.latest})`;\n }\n if (pkg.latest) {\n return `- ${pkg.name} (not installed → ${pkg.latest})`;\n }\n return `- ${pkg.name}`;\n}\n\nasync function packagesNeedingUpdate(\n root: string,\n packages: ManagedPackage[],\n): Promise<OutdatedPackage[]> {\n const checks = await Promise.all(\n packages.map(async (pkg): Promise<OutdatedPackage | undefined> => {\n const installed = readInstalledVersion(root, pkg.name);\n const latest = await fetchLatestPackageVersion(pkg.name);\n\n // Unknown registry: only fail when the package isn't present locally.\n if (!latest) {\n return installed ? undefined : { name: pkg.name, installed };\n }\n\n if (!installed || isNewerVersion(latest, installed)) {\n return { name: pkg.name, installed, latest };\n }\n\n return undefined;\n }),\n );\n\n return checks.flatMap((pkg) => (pkg ? [pkg] : []));\n}\n\n/**\n * Require @keystrokehq/* project dependencies to be on latest before build/deploy.\n * Skips `@keystrokehq/cli` (global + self-updating). Throws instead of auto-installing.\n */\nexport async function ensureSdkCurrent(root: string): Promise<void> {\n if (shouldSkip()) {\n return;\n }\n\n const packages = listManagedKeystrokePackages(root);\n if (packages.length === 0) {\n return;\n }\n\n const outdated = await packagesNeedingUpdate(root, packages);\n if (outdated.length === 0) {\n return;\n }\n\n const lines = outdated.map(formatOutdatedLine).join(\"\\n\");\n throw new ExpectedCliError(\n `@keystrokehq packages are behind npm latest:\\n${lines}\\n\\n` +\n `Run \\`keystroke update\\`, then retry.`,\n );\n}\n","import { spawnSync } from \"node:child_process\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nconst MANAGERS: PackageManager[] = [\"pnpm\", \"npm\", \"yarn\", \"bun\"];\n\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent ?? \"\";\n\n for (const manager of MANAGERS) {\n if (userAgent.startsWith(manager)) {\n return manager;\n }\n }\n\n if (process.env.PNPM_HOME) {\n return \"pnpm\";\n }\n\n return \"npm\";\n}\n\nexport function resolvePackageManager(explicit?: string): PackageManager {\n if (!explicit) {\n return detectPackageManager();\n }\n\n const normalized = explicit.trim().toLowerCase();\n if (!MANAGERS.includes(normalized as PackageManager)) {\n throw new Error(`Unsupported package manager \"${explicit}\". Use npm, pnpm, yarn, or bun.`);\n }\n\n return normalized as PackageManager;\n}\n\n/** Resolve GitHub Packages auth for @keystrokehq/* when NODE_AUTH_TOKEN is unset. */\nexport function resolveGithubPackagesToken(): string | undefined {\n if (process.env.NODE_AUTH_TOKEN) {\n return process.env.NODE_AUTH_TOKEN;\n }\n\n for (const key of [\"GITHUB_TOKEN\", \"GH_TOKEN\"] as const) {\n const value = process.env[key];\n if (value) {\n return value;\n }\n }\n\n const gh = spawnSync(\"gh\", [\"auth\", \"token\"], { encoding: \"utf8\" });\n if (gh.status === 0) {\n const token = gh.stdout.trim();\n if (token) {\n return token;\n }\n }\n\n return undefined;\n}\n\nexport function installDependencies(cwd: string, manager: PackageManager): void {\n const token = resolveGithubPackagesToken();\n const env = token ? { ...process.env, NODE_AUTH_TOKEN: token } : process.env;\n\n const result = spawnSync(manager, [\"install\"], {\n cwd,\n stdio: \"inherit\",\n env,\n });\n\n if (result.status !== 0) {\n throw new Error(`${manager} install failed`);\n }\n}\n\nexport function installPlaygroundDependencies(cwd: string): void {\n const result = spawnSync(\"pnpm\", [\"install\", \"--ignore-workspace\"], {\n cwd,\n stdio: \"inherit\",\n env: process.env,\n });\n\n if (result.status !== 0) {\n throw new Error(\"pnpm install failed\");\n }\n}\n\n/**\n * Build every workspace package so the playground's `link:` deps resolve to\n * compiled `dist/`. Without this, local imports fail with\n * `ERR_MODULE_NOT_FOUND` against whichever package was never built. Turbo\n * caches, so this is only slow on the first run.\n */\nexport function buildPlaygroundWorkspace(monorepoRoot: string): void {\n // Build with a clean Node env: the `keystroke-dev` wrapper sets\n // NODE_OPTIONS=--conditions=development, which would make tsdown/turbo resolve\n // their own deps to src/ and fail. Dropping NODE_OPTIONS builds to dist/ normally.\n const { NODE_OPTIONS: _drop, ...buildEnv } = process.env;\n const result = spawnSync(\"pnpm\", [\"run\", \"build\"], {\n cwd: monorepoRoot,\n stdio: \"inherit\",\n env: buildEnv,\n });\n\n if (result.status !== 0) {\n throw new Error(\"workspace build failed (pnpm run build)\");\n }\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\n\nimport { detectPackageManager, type PackageManager } from \"../init/package-manager\";\n\nexport type CliInstallKind = \"global\" | \"local\";\n\nexport type CliInstallInfo = {\n kind: CliInstallKind;\n packageManager: PackageManager;\n packageRoot: string;\n projectRoot?: string;\n /**\n * When the CLI was installed with `npm install -g --prefix <dir>` (Modal /\n * session images use `/root/.keystroke`), updates must pass the same prefix\n * so npm does not fight a `/usr/local/bin/keystroke` symlink.\n */\n npmPrefix?: string;\n};\n\nfunction realpathSafe(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return path;\n }\n}\n\n/**\n * Resolve an npm `--prefix` root from a global package path.\n * Layout: `<prefix>/lib/node_modules/@keystrokehq/cli`.\n */\nexport function resolveNpmInstallPrefix(packageRoot: string): string | undefined {\n const normalized = packageRoot.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const match = normalized.match(/^(.*)\\/lib\\/node_modules\\/@keystrokehq\\/cli$/);\n const prefix = match?.[1]?.trim();\n return prefix && prefix.length > 0 ? prefix : undefined;\n}\n\nexport function detectManagerFromLockfile(dir: string): PackageManager | undefined {\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) {\n return \"pnpm\";\n }\n\n if (existsSync(join(dir, \"bun.lockb\")) || existsSync(join(dir, \"bun.lock\"))) {\n return \"bun\";\n }\n\n if (existsSync(join(dir, \"yarn.lock\"))) {\n return \"yarn\";\n }\n\n if (existsSync(join(dir, \"package-lock.json\"))) {\n return \"npm\";\n }\n\n return undefined;\n}\n\nfunction findLocalProjectRoot(packageRoot: string): string | undefined {\n const normalizedRoot = realpathSafe(packageRoot);\n let dir = dirname(packageRoot);\n\n while (dir !== dirname(dir)) {\n const installedCliPath = join(dir, \"node_modules\", \"@keystrokehq\", \"cli\");\n if (\n existsSync(join(dir, \"package.json\")) &&\n realpathSafe(installedCliPath) === normalizedRoot\n ) {\n return dir;\n }\n\n dir = dirname(dir);\n }\n\n return undefined;\n}\n\nfunction globalRootForManager(manager: PackageManager): string | undefined {\n const commands: Record<PackageManager, { command: string; args: string[] }> = {\n pnpm: { command: \"pnpm\", args: [\"root\", \"-g\"] },\n npm: { command: \"npm\", args: [\"root\", \"-g\"] },\n yarn: { command: \"yarn\", args: [\"global\", \"dir\"] },\n bun: { command: \"bun\", args: [\"pm\", \"bin\"] },\n };\n\n const { command, args } = commands[manager];\n const result = spawnSync(command, args, { encoding: \"utf8\" });\n\n if (result.status !== 0) {\n return undefined;\n }\n\n const root = result.stdout.trim();\n return root ? realpathSafe(root) : undefined;\n}\n\nfunction detectGlobalManager(packageRoot: string): PackageManager {\n const normalizedRoot = realpathSafe(packageRoot);\n\n if (normalizedRoot.includes(`${join(\"\", \".pnpm\")}`)) {\n return \"pnpm\";\n }\n\n for (const manager of [\"pnpm\", \"npm\", \"yarn\", \"bun\"] as const) {\n const globalRoot = globalRootForManager(manager);\n if (globalRoot && normalizedRoot.startsWith(globalRoot)) {\n return manager;\n }\n }\n\n if (process.env.PNPM_HOME) {\n return \"pnpm\";\n }\n\n return detectPackageManager();\n}\n\nexport function detectCliInstall(packageRoot: string): CliInstallInfo | undefined {\n const normalizedRoot = realpathSafe(packageRoot);\n const projectRoot = findLocalProjectRoot(normalizedRoot);\n\n if (projectRoot) {\n const packageManager = detectManagerFromLockfile(projectRoot) ?? detectPackageManager();\n\n return {\n kind: \"local\",\n packageManager,\n packageRoot: normalizedRoot,\n projectRoot,\n };\n }\n\n const npmPrefix = resolveNpmInstallPrefix(normalizedRoot);\n if (npmPrefix) {\n return {\n kind: \"global\",\n packageManager: \"npm\",\n packageRoot: normalizedRoot,\n npmPrefix,\n };\n }\n\n return {\n kind: \"global\",\n packageManager: detectGlobalManager(normalizedRoot),\n packageRoot: normalizedRoot,\n };\n}\n","const RELEASE_AGE_PATTERNS = [\n /minimumReleaseAge/i,\n /minimum-release-age/i,\n /ERR_PNPM_NO_MATURE_MATCHING_VERSION/,\n /ERR_PNPM_MINIMUM_RELEASE_AGE/,\n /does not meet the minimumReleaseAge constraint/,\n];\n\nexport function isReleaseAgeBlock(output: string): boolean {\n return RELEASE_AGE_PATTERNS.some((pattern) => pattern.test(output));\n}\n\nexport function formatReleaseAgeBlockMessage(options: {\n currentVersion: string;\n availableVersion: string;\n retryAfter?: Date;\n}): string {\n const retry =\n options.retryAfter !== undefined ? ` Retry after ${options.retryAfter.toLocaleString()}.` : \"\";\n\n return (\n `@keystrokehq/cli ${options.availableVersion} is available but blocked by your ` +\n `minimum-release-age setting. You're on ${options.currentVersion}.${retry} ` +\n `Run \\`keystroke update\\` again — it bypasses minimum-release-age for @keystrokehq packages and retries.`\n );\n}\n","import { spawnSync } from \"node:child_process\";\n\nexport function readPnpmMinimumReleaseAgeMinutes(): number | undefined {\n const result = spawnSync(\"pnpm\", [\"config\", \"get\", \"minimum-release-age\"], {\n encoding: \"utf8\",\n });\n\n if (result.status !== 0) {\n return undefined;\n }\n\n const value = result.stdout.trim();\n if (!value || value === \"undefined\" || value === \"0\") {\n return undefined;\n }\n\n const minutes = Number.parseInt(value, 10);\n return Number.isFinite(minutes) && minutes > 0 ? minutes : undefined;\n}\n\nexport function computeReleaseAgeRetryAfter(\n publishedAt: string | undefined,\n minimumReleaseAgeMinutes: number | undefined,\n): Date | undefined {\n if (!publishedAt || !minimumReleaseAgeMinutes) {\n return undefined;\n }\n\n const publishedMs = Date.parse(publishedAt);\n if (!Number.isFinite(publishedMs)) {\n return undefined;\n }\n\n return new Date(publishedMs + minimumReleaseAgeMinutes * 60_000);\n}\n","/** pnpm global installs live in `<pnpm-home>/global/<major>/`. */\nexport function resolveGlobalPnpmRoot(packageRoot: string): string | undefined {\n const normalized = packageRoot.replace(/\\\\/g, \"/\");\n const match = normalized.match(/^(.*\\/global\\/\\d+)\\//);\n return match?.[1];\n}\n","import type { CliInstallInfo } from \"./detect-cli-install\";\nimport { cliPackageSpec, resolveCliDistTag } from \"./resolve-cli-dist-tag\";\nimport { resolveGlobalPnpmRoot } from \"./resolve-global-pnpm-root\";\n\nexport function buildUpdateCommand(\n install: CliInstallInfo,\n distTag: string = resolveCliDistTag(),\n): {\n command: string;\n args: string[];\n cwd?: string;\n} {\n const { kind, packageManager } = install;\n const packageName = cliPackageSpec(distTag);\n\n if (kind === \"global\") {\n switch (packageManager) {\n case \"pnpm\":\n return {\n command: \"pnpm\",\n args: [\"add\", \"-g\", packageName],\n cwd: resolveGlobalPnpmRoot(install.packageRoot),\n };\n case \"yarn\":\n return { command: \"yarn\", args: [\"global\", \"add\", packageName] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", \"-g\", packageName] };\n case \"npm\":\n default:\n if (install.npmPrefix) {\n return {\n command: \"npm\",\n args: [\"install\", \"-g\", \"--prefix\", install.npmPrefix, packageName],\n };\n }\n return { command: \"npm\", args: [\"install\", \"-g\", packageName] };\n }\n }\n\n const cwd = install.projectRoot;\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", \"-D\", packageName], cwd };\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", \"-D\", packageName], cwd };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", \"-D\", packageName], cwd };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"install\", \"-D\", packageName], cwd };\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst EXCLUDE_PREFIX = \"minimum-release-age-exclude[]=\";\n\nfunction npmrcPath(root: string): string {\n return join(root, \".npmrc\");\n}\n\n/** Package names already listed as `minimum-release-age-exclude[]=` in an .npmrc body. */\nexport function parseMinimumReleaseAgeExcludes(contents: string): string[] {\n const found: string[] = [];\n for (const rawLine of contents.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (!line.startsWith(EXCLUDE_PREFIX)) {\n continue;\n }\n const value = line.slice(EXCLUDE_PREFIX.length).trim();\n if (value) {\n found.push(value);\n }\n }\n return found;\n}\n\n/**\n * Ensure each package is listed in the project `.npmrc` as\n * `minimum-release-age-exclude[]=<name>` so `pnpm add pkg@latest` is not held\n * back by minimum-release-age. Creates `.npmrc` when missing.\n *\n * Returns the packages that were newly added (empty when already present).\n */\nexport function ensureMinimumReleaseAgeExclude(root: string, packageNames: string[]): string[] {\n const unique = [...new Set(packageNames.map((name) => name.trim()).filter(Boolean))].sort();\n if (unique.length === 0) {\n return [];\n }\n\n const path = npmrcPath(root);\n const existing = existsSync(path) ? readFileSync(path, \"utf8\") : \"\";\n const already = new Set(parseMinimumReleaseAgeExcludes(existing));\n const added = unique.filter((name) => !already.has(name));\n if (added.length === 0) {\n return [];\n }\n\n const trimmed = existing.replace(/\\s+$/, \"\");\n const next = [\n ...(trimmed.length > 0 ? [trimmed] : []),\n ...added.map((name) => `${EXCLUDE_PREFIX}${name}`),\n \"\",\n ].join(\"\\n\");\n writeFileSync(path, next, \"utf8\");\n return added;\n}\n","import { spawnSync } from \"node:child_process\";\n\nimport { buildUpdateCommand } from \"./build-update-command\";\nimport type { CliInstallInfo } from \"./detect-cli-install\";\nimport { isReleaseAgeBlock } from \"./detect-release-age-block\";\nimport { ensureMinimumReleaseAgeExclude } from \"./ensure-release-age-exclude\";\nimport { CLI_PACKAGE_NAME } from \"./ensure-sdk-current\";\n\nexport function updateSpawnEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n const pnpmHome = env.PNPM_HOME;\n\n if (!pnpmHome) {\n return env;\n }\n\n const pathKey = process.platform === \"win32\" ? \"Path\" : \"PATH\";\n const path = env[pathKey] ?? \"\";\n const segments = path.split(process.platform === \"win32\" ? \";\" : \":\");\n const binDir = `${pnpmHome}/bin`;\n const prefix = [binDir, pnpmHome].filter((dir) => !segments.includes(dir));\n\n if (prefix.length > 0) {\n env[pathKey] = [...prefix, path].filter(Boolean).join(process.platform === \"win32\" ? \";\" : \":\");\n }\n\n return env;\n}\n\nexport type PackageManagerRunResult = {\n ok: boolean;\n output: string;\n};\n\nfunction runPackageManager(command: string, args: string[], cwd?: string): PackageManagerRunResult {\n const result = spawnSync(command, args, {\n cwd,\n encoding: \"utf8\",\n env: updateSpawnEnv(),\n });\n\n const output = `${result.stdout ?? \"\"}${result.stderr ?? \"\"}`;\n\n return {\n ok: result.status === 0,\n output,\n };\n}\n\nfunction migratePnpmGlobal(cwd: string): boolean {\n const result = spawnSync(\"pnpm\", [\"install\"], {\n cwd,\n encoding: \"utf8\",\n env: {\n ...updateSpawnEnv(),\n CI: \"true\",\n },\n });\n\n return result.status === 0;\n}\n\n/** Bypass minimum-release-age for this one CLI install without editing user config. */\nfunction withCliReleaseAgeExclude(args: string[]): string[] {\n return [...args, `--config.minimum-release-age-exclude[]=${CLI_PACKAGE_NAME}`];\n}\n\nexport function runPackageManagerUpdate(\n install: CliInstallInfo,\n distTag?: string,\n): PackageManagerRunResult {\n const { command, args, cwd } = buildUpdateCommand(install, distTag);\n const firstAttempt = runPackageManager(command, args, cwd);\n\n if (firstAttempt.ok) {\n return firstAttempt;\n }\n\n if (install.kind === \"global\" && install.packageManager === \"pnpm\" && cwd) {\n if (migratePnpmGlobal(cwd)) {\n const migrated = runPackageManager(command, args, cwd);\n if (migrated.ok) {\n return migrated;\n }\n }\n }\n\n if (install.packageManager === \"pnpm\" && isReleaseAgeBlock(firstAttempt.output)) {\n if (install.kind === \"local\" && install.projectRoot) {\n const added = ensureMinimumReleaseAgeExclude(install.projectRoot, [CLI_PACKAGE_NAME]);\n if (added.length > 0) {\n process.stderr.write(\n `Added ${CLI_PACKAGE_NAME} to .npmrc minimum-release-age-exclude; retrying CLI update...\\n`,\n );\n }\n return runPackageManager(command, args, cwd);\n }\n\n process.stderr.write(\n `Retrying CLI update with temporary minimum-release-age-exclude for ${CLI_PACKAGE_NAME}...\\n`,\n );\n return runPackageManager(command, withCliReleaseAgeExclude(args), cwd);\n }\n\n return firstAttempt;\n}\n"],"mappings":"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"}
|
|
@@ -75,7 +75,7 @@ Workflows also render as an interactive **canvas** in the platform. Keep durable
|
|
|
75
75
|
- **Search the catalog, then research the system** — check `keystroke apps search` thoroughly before assuming an integration is missing. For anything custom or unfamiliar, web-fetch/search the real docs — `llms.txt`, OpenAPI/GraphQL specs, API reference — before mirroring endpoints or payloads. Never guess.
|
|
76
76
|
- **Run before you claim you are finished** — deploy with `keystroke deploy` via `exec_command`, run it in the cloud, and read the real output before activating live triggers or claiming you are finished. Chat with agents and run workflows to confirm they behave correctly.
|
|
77
77
|
- **Cover obvious edge cases** and write simple tests as needed (null field, empty array, a step that throws).
|
|
78
|
-
- **Verify integration prerequisites** — before composing a **catalog** action into a workflow, run it once with `keystroke apps execute` (via `exec_command`) to confirm the IDs and fields exist in the connected account.
|
|
78
|
+
- **Verify integration prerequisites** — before composing a **catalog** action or **custom MCP** tool into a workflow/agent, run it once with `keystroke apps execute` (via `exec_command`) to confirm the IDs and fields exist in the connected account. Other custom org apps (`{org}/{name}` without `source:"mcp"`) cannot use `apps execute` for project `defineApp(...).action(...)` code — smoke-test with deploy + `keystroke workflows run` on a thin workflow.
|
|
79
79
|
- **Connect integrations in the web app** — use the `connect_app` tool to get a link for the user (a browser cannot open in this workspace). Keystroke projects don't use `.env`.
|
|
80
80
|
- **Filtered deploys** — determine if you should do a full vs filtered deploy, or use WIP ignore directives (`search_docs "filtered deploy"`).
|
|
81
81
|
- **Dependencies** — use the project's existing package manager (`package.json` `packageManager` field or lockfile); default to npm only on a freshly created project with no lockfile. Deploy uploads only the built `dist/` artifact — a lockfile is not part of what ships to the platform.
|
|
@@ -119,13 +119,13 @@ To discover apps/integrations and their actions, query the live catalog with the
|
|
|
119
119
|
keystroke apps search "{query}" # find an app and its slug in the full catalog — start here
|
|
120
120
|
keystroke apps list # apps registered/connectable in your org
|
|
121
121
|
keystroke apps get <slug> # catalog toolkit OR custom org template (see kind)
|
|
122
|
-
keystroke apps actions list <app> --search <q> # catalog toolkit
|
|
122
|
+
keystroke apps actions list <app> --search <q> # catalog: toolkit; MCP: live remote tools (not TS yet); other custom: guidance
|
|
123
123
|
keystroke apps actions get <app> <tool> # schema + how to run/import one catalog action
|
|
124
|
-
keystroke apps execute <app> <tool> --input '{...}' #
|
|
124
|
+
keystroke apps execute <app> <tool> --input '{...}' # catalog toolkit action OR custom MCP remote tool
|
|
125
125
|
keystroke credentials list # what's already connected — check before asking the user to connect
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Custom org apps (`{org}/{name}`) do not have catalog toolkit actions
|
|
128
|
+
Custom org apps (`{org}/{name}`) do not have catalog toolkit actions. Custom MCP: after connect, `apps actions list` returns the live remote `tools/list` (`kind:mcp`) — smoke-test with `apps execute <org>/<name> <tool>` (no `--version`), then wrap what you need in `app.action(...)`. Other non-MCP custom apps: use `apps get` / `apps sync` / `defineApp(...).action(...)`, and smoke-test with a thin workflow via `keystroke workflows run <slug> --input '{...}' --wait` after deploy.
|
|
129
129
|
|
|
130
130
|
**Gateway / channel binding:** use the `setup_agent_slack` tool (kind `keystroke` or `custom`), then follow its `nextCommands` via `exec_command` and share any OAuth/wizard URLs with the user. Keystroke path: OAuth for the Keystroke Slack App (catalog slug `slackbot`) if needed, then `keystroke channels setup <slug> [--channel <name>]`. Custom @handle: `keystroke channels setup <slug> --custom --print-url` and share the wizard link — user finishes in the browser. Do not use a Personal Slack Account (catalog slug `slack`, user token) for External Channels. Full detail: `search_docs "external channels"` → `/learn/agents/external-channels`.
|
|
131
131
|
|
|
@@ -139,7 +139,7 @@ If a **credentialed** integration isn't supported, build a proper custom app —
|
|
|
139
139
|
2. Author with `defineApp` in `src/apps/` + `app.action(...)`.
|
|
140
140
|
3. Have the user connect (`connect_app` link), then deploy.
|
|
141
141
|
|
|
142
|
-
For MCP: `search_docs "custom apps MCP"` first, then connect,
|
|
142
|
+
For MCP: `search_docs "custom apps MCP"` first, then connect, `keystroke apps actions list <org>/<name>` to inspect **remote** tools, `keystroke apps execute <org>/<name> <tool> --input '{...}'` to smoke-test, `keystroke apps sync <org>/<name>`, author `app.action(...)` wrappers, and put the app in `tools: [app]` (all registered actions) or pick actions. Do not use `defineMcp`. Credential-free project actions stay as plain `defineAction`. `search_docs "custom integration"`.
|
|
143
143
|
|
|
144
144
|
## Report friction and feedback to the Keystroke team
|
|
145
145
|
|
|
@@ -89,7 +89,7 @@ pnpm test # same — package.json scripts call the CLI
|
|
|
89
89
|
Build, ship, then run and inspect what's live. Deploy often.
|
|
90
90
|
|
|
91
91
|
1. **Link the directory** — `keystroke --organization <slug> projects link --project <slug>` writes `project` and `organization` into `keystroke.config.ts` (or pass the flags on every command). Commands that need auth tell you how to log in.
|
|
92
|
-
2. **Verify prerequisites** — for **catalog** integrations, run each
|
|
92
|
+
2. **Verify prerequisites** — for **catalog** integrations and **custom MCP** apps, run each tool once for real with `keystroke apps execute` before wiring it in. Other custom org apps (`{org}/{name}` without `source:"mcp"`) smoke-test via a thin workflow (see [Integrations & credentials](#integrations--credentials)).
|
|
93
93
|
3. **Edit** primitives under `src/`. Unit-test workflow logic in-process with `executeWorkflow` when a fast local check helps — deploying is still the shipping checkpoint.
|
|
94
94
|
4. **Deploy** — `keystroke deploy` (full) or `keystroke deploy --filter agents/support` (one module).
|
|
95
95
|
5. **Run** — `keystroke workflows run <slug> --input '{...}' --wait` / `keystroke agents prompt <slug> --message "..." --wait`. Prefer `--wait` over `sleep`-and-recheck loops and choose its duration with `--timeout <seconds>`. A timeout means it is still running, not that it failed; continue with `keystroke workflows runs get <slug> <runId> --wait` or `keystroke agents sessions get <slug> <sessionId> --wait`.
|
|
@@ -259,21 +259,23 @@ run: async ({ state, setState }) => {
|
|
|
259
259
|
|
|
260
260
|
Keystroke has 1,000+ built-in integrations, and it's easy to build a custom one for any HTTP API or MCP server (including private/internal). **Research first, then build:** search the catalog thoroughly before assuming an app is missing; for anything custom or unfamiliar, web-fetch/search the system's real docs — `llms.txt`, OpenAPI/GraphQL specs, API reference — before writing code. Never guess endpoints or payloads.
|
|
261
261
|
|
|
262
|
-
Discover apps and actions with the CLI — the docs integration index is **not** reliable for discovery. One `<app> <tool>` shape flows through discovery → inspect → run for **catalog** apps; `apps actions get` / `apps actions list` print the next step after their output.
|
|
262
|
+
Discover apps and actions with the CLI — the docs integration index is **not** reliable for discovery. One `<app> <tool>` shape flows through discovery → inspect → run for **catalog** apps; `apps actions get` / `apps actions list` print the next step after their output. **`apps actions list` is not one behavior:** catalog apps return ready toolkit actions; custom MCP apps (`source:"mcp"`) return the live remote `tools/list` after connect (`kind:"mcp"`) — those tools may **not** exist as TypeScript `app.action(...)` yet; other custom org apps return `kind:"custom"` guidance (actions live in project code). Always `keystroke docs search` Keystroke docs first for custom/MCP patterns.
|
|
263
263
|
|
|
264
264
|
Think about testing as you build. Local tests don't link cloud credentials or the Keystroke client, so unit-test pure logic locally.
|
|
265
265
|
|
|
266
266
|
**Catalog apps** — check needed apps/credentials and run each action once for real with `keystroke apps execute` (no deploy, no server) before wiring it into a workflow or agent — confirm the IDs, custom fields, and labels you're about to hard-code exist in the *connected* account. Schema inspection and dry-run flags prove nothing about the mutating path.
|
|
267
267
|
|
|
268
|
-
**Custom
|
|
268
|
+
**Custom MCP apps** (`source:"mcp"`) — after connect, `keystroke apps actions list <org>/<name>` lists **remote** MCP tools (not authored TypeScript yet). Smoke-test a remote tool with the same command: `keystroke apps execute <org>/<name> <tool> --input '{...}'` (no `--version`; tool names keep vendor case). Then wrap what you need in `app.action(...)` and attach the app or actions.
|
|
269
|
+
|
|
270
|
+
**Other custom org apps** (`{org}/{name}` from `apps create` / `apps sync`) — `apps execute` cannot run `defineApp(...).action(...)` project code. Smoke-test by deploying a thin workflow that calls the action, then `keystroke workflows run <workflow-slug> --input '{...}' --wait`.
|
|
269
271
|
|
|
270
272
|
```bash
|
|
271
273
|
keystroke apps list # all registered apps
|
|
272
274
|
keystroke apps search "{query}" # find an app + slug in the full catalog
|
|
273
275
|
keystroke apps get <slug> # catalog toolkit OR custom credential template (kind)
|
|
274
|
-
keystroke apps actions list <app> --search <q> # catalog toolkit
|
|
276
|
+
keystroke apps actions list <app> --search <q> # catalog: toolkit actions; MCP: live remote tools (not TS yet); other custom: guidance
|
|
275
277
|
keystroke apps actions get <app> <tool> # schema + how to run/import one catalog action
|
|
276
|
-
keystroke apps execute <app> <tool> --input '{...}' #
|
|
278
|
+
keystroke apps execute <app> <tool> --input '{...}' # catalog toolkit action OR custom MCP remote tool
|
|
277
279
|
keystroke credentials list # what's already connected
|
|
278
280
|
keystroke connect <slug> # connect an app credential (opens the web connect flow; --print-url prints it instead)
|
|
279
281
|
keystroke credentials create <key> --set apiKey=@env:MY_KEY # static API key
|
|
@@ -335,7 +337,7 @@ Missing a built-in **credentialed** integration? After researching the system's
|
|
|
335
337
|
2. **Code authoring** — always `defineApp` in `src/apps/` + `app.action(...)`. Do **not** invent `src/credentials/foo.ts` + a lone `defineAction` for a new API.
|
|
336
338
|
3. **Connect** — `keystroke connect <slug>` (or `credentials create` when you already have the secret), then deploy.
|
|
337
339
|
|
|
338
|
-
For MCP apps: `keystroke docs search "custom apps MCP"` first, then `connect`,
|
|
340
|
+
For MCP apps: `keystroke docs search "custom apps MCP"` first, then `connect`, `keystroke apps actions list <org>/<name>` to inspect **remote** tools (unlike catalog list — wrappers may not exist yet), `keystroke apps sync <org>/<name>`, author `app.action(...)` wrappers, and put the app in `tools: [app]` (all registered actions) or pick individual actions. Do not use `defineMcp`. Plain `defineAction` (no credentials) does not need an app. See `/learn/credentials/custom-integrations`.
|
|
339
341
|
|
|
340
342
|
## Skills & files
|
|
341
343
|
|
|
@@ -388,7 +390,7 @@ Invoke/inspect commands print JSON to stdout (exit 0 on success, 1 on failure)
|
|
|
388
390
|
- [ ] Deployed the change and read the real run output/trace — not just "it should work".
|
|
389
391
|
- [ ] Prompted agents / ran workflows with realistic input and verified behavior.
|
|
390
392
|
- [ ] Researched real APIs before mirroring them in custom integration actions — no guessed endpoints or payloads.
|
|
391
|
-
- [ ] Catalog: executed each mutating
|
|
393
|
+
- [ ] Catalog / custom MCP: executed each mutating tool once via `keystroke apps execute` before composing it — a passing dry-run flag doesn't count. Other custom org apps: smoke-tested via deploy + `workflows run` on a thin workflow that calls `defineApp(...).action(...)`.
|
|
392
394
|
- [ ] Covered obvious edge cases (null field, empty array, a step that throws) with a simple test where warranted.
|
|
393
395
|
- [ ] Checked `keystroke credentials list` before connecting; connected any new apps with `keystroke connect`.
|
|
394
396
|
- [ ] Tested manually before deploying attached cron/polling triggers, or used `triggers disable` to pause until ready.
|
package/package.json
CHANGED
package/dist/dist-B_Dy4mW_.mjs
DELETED