@keystrokehq/cli 1.0.2 → 1.0.8
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 +3 -3
- package/dist/{dist-DEwhZoDf.mjs → dist-BXi7cRDx.mjs} +6 -8
- package/dist/dist-BXi7cRDx.mjs.map +1 -0
- package/dist/{dist-DtUH9rOc.mjs → dist-CaXYCefX.mjs} +6 -8
- package/dist/dist-CaXYCefX.mjs.map +1 -0
- package/dist/{dist-_46DIPBj.mjs → dist-DR0-KRom.mjs} +9 -2
- package/dist/{dist-_46DIPBj.mjs.map → dist-DR0-KRom.mjs.map} +1 -1
- package/dist/dist-MYk9JAIo.mjs +3 -0
- package/dist/index.mjs +11 -10
- package/dist/index.mjs.map +1 -1
- package/dist/{maybe-auto-update-DGBkB562.mjs → maybe-auto-update-DxAS-9S7.mjs} +2 -2
- package/dist/{maybe-auto-update-DGBkB562.mjs.map → maybe-auto-update-DxAS-9S7.mjs.map} +1 -1
- package/dist/skills-bundle/_AGENTS.md +5 -5
- package/dist/skills-bundle/skills/keystroke-actions/SKILL.md +39 -7
- package/dist/skills-bundle/skills/keystroke-actions/references/catalog-and-imports.md +25 -19
- package/dist/skills-bundle/skills/keystroke-agents/SKILL.md +3 -3
- package/dist/skills-bundle/skills/keystroke-apps/SKILL.md +133 -0
- package/dist/skills-bundle/skills/keystroke-apps/references/cli-and-catalog.md +66 -0
- package/dist/skills-bundle/skills/keystroke-cli/SKILL.md +2 -2
- package/dist/skills-bundle/skills/keystroke-cli/references/api-targets.md +2 -2
- package/dist/skills-bundle/skills/keystroke-deploy/SKILL.md +2 -2
- package/dist/skills-bundle/skills/keystroke-gateways/SKILL.md +2 -2
- package/dist/skills-bundle/skills/keystroke-gateways/references/slack-setup.md +1 -1
- package/dist/skills-bundle/skills/keystroke-skills/SKILL.md +1 -1
- package/dist/skills-bundle/skills/keystroke-workflows/SKILL.md +1 -1
- package/dist/skills-bundle/skills/keystroke-workflows/references/authoring.md +2 -2
- package/dist/{version-CKAYz1xm.mjs → version-TtPeAEMz.mjs} +4 -4
- package/dist/version-TtPeAEMz.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/dist-BrhJhyvP.mjs +0 -3
- package/dist/dist-DEwhZoDf.mjs.map +0 -1
- package/dist/dist-DtUH9rOc.mjs.map +0 -1
- package/dist/skills-bundle/skills/keystroke-credentials/SKILL.md +0 -108
- package/dist/skills-bundle/skills/keystroke-credentials/references/cli-and-oauth.md +0 -51
- package/dist/version-CKAYz1xm.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dist-DtUH9rOc.mjs","names":["toPosix"],"sources":["../../../packages/build/dist/walk-project-eZ95LOUW.mjs","../../../packages/tsdown-config/deps.js","../../../packages/tsdown-config/index.js","../../../packages/build/dist/index.mjs"],"sourcesContent":["import { readFileSync, readdirSync, realpathSync, statSync } from \"node:fs\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { entryIdFromFile, readKeystrokeIgnoreDirective, shouldSkipKeystrokeModuleFile } from \"@keystrokehq/manifest/discovery\";\nimport { fileURLToPath } from \"node:url\";\n//#region src/ignore-guard-plugin.ts\nfunction toPosix$1(path) {\n\treturn path.split(sep).join(\"/\");\n}\nfunction projectRelativePath(root, filePath) {\n\treturn toPosix$1(relative(root, normalizeBuildFilePath(filePath)));\n}\n/** Normalize paths so /var and /private/var compare equal on macOS. */\nfunction normalizeBuildFilePath(filePath) {\n\tconst absolute = resolve(filePath);\n\ttry {\n\t\treturn realpathSync.native(absolute);\n\t} catch {\n\t\treturn absolute;\n\t}\n}\nfunction normalizeModuleId(id, root) {\n\tif (id.startsWith(\"\\0\")) return null;\n\tconst normalized = normalizeBuildFilePath(id.startsWith(\"file://\") ? fileURLToPath(id) : id);\n\tif (!normalized.startsWith(normalizeBuildFilePath(root))) return null;\n\treturn normalized;\n}\nfunction formatImportGuardError(root, ignoredPath, importer) {\n\tconst ignored = projectRelativePath(root, ignoredPath);\n\tif (importer) return `Cannot import \"${ignored}\" (@keystroke ignore) from \"${projectRelativePath(root, importer)}\". Remove the directive or stop importing it from a shipped module.`;\n\treturn `Cannot import \"${ignored}\" (@keystroke ignore). Remove the directive or stop importing it from a shipped module.`;\n}\n/** Throw when a built module imports a `@keystroke ignore` source file. */\nfunction keystrokeIgnoreGuardPlugin(options) {\n\tconst root = normalizeBuildFilePath(options.root);\n\tconst ignoredFiles = new Set(options.ignoredFiles.map((filePath) => normalizeBuildFilePath(filePath)));\n\tfunction assertNotIgnored(filePath, importer) {\n\t\tconst normalized = normalizeBuildFilePath(filePath);\n\t\tif (!ignoredFiles.has(normalized)) return;\n\t\tthrow new Error(formatImportGuardError(root, normalized, importer));\n\t}\n\treturn {\n\t\tname: \"keystroke-ignore-guard\",\n\t\tasync resolveId(source, importer, resolveOptions) {\n\t\t\tif (resolveOptions?.isEntry || !importer) return null;\n\t\t\tconst resolved = await this.resolve(source, importer, {\n\t\t\t\t...resolveOptions,\n\t\t\t\tskipSelf: true\n\t\t\t});\n\t\t\tif (!resolved) return null;\n\t\t\tassertNotIgnored(typeof resolved === \"string\" ? resolved : resolved.id, importer);\n\t\t\treturn null;\n\t\t},\n\t\tload(id) {\n\t\t\tconst normalized = normalizeModuleId(id, root);\n\t\t\tif (!normalized) return null;\n\t\t\tassertNotIgnored(normalized);\n\t\t\treturn null;\n\t\t}\n\t};\n}\n//#endregion\n//#region src/walk-project.ts\nconst IGNORED_DIRS = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".git\",\n\t\".turbo\",\n\t\"build\",\n\t\"coverage\",\n\t\".keystroke\",\n\t\".cache\",\n\t\"tmp\"\n]);\nconst IGNORED_ENV_FILE = /\\.env/;\nconst IGNORED_LOG_FILE = /\\.log$/;\nfunction isIgnoredFile(name) {\n\treturn IGNORED_ENV_FILE.test(name) || IGNORED_LOG_FILE.test(name);\n}\nfunction toPosix(path) {\n\treturn path.split(sep).join(\"/\");\n}\nfunction isProbablyBinary(buffer) {\n\tconst sampleLength = Math.min(buffer.length, 8e3);\n\tfor (let index = 0; index < sampleLength; index += 1) if (buffer[index] === 0) return true;\n\treturn false;\n}\nfunction classifyBuildEntry(root, srcRoot, filePath) {\n\tconst relativePath = toPosix(relative(root, filePath));\n\tconst agentsPrefix = `${toPosix(relative(root, join(srcRoot, \"agents\")))}/`;\n\tconst workflowsPrefix = `${toPosix(relative(root, join(srcRoot, \"workflows\")))}/`;\n\tconst triggersPrefix = `${toPosix(relative(root, join(srcRoot, \"triggers\")))}/`;\n\tif (relativePath.startsWith(agentsPrefix) && /\\.(ts|mts)$/.test(relativePath) && !/\\.(int\\.)?test\\.(ts|mts)$/.test(relativePath)) {\n\t\tconst id = entryIdFromFile(join(srcRoot, \"agents\"), filePath, { nestedEntry: \"agent\" });\n\t\treturn id ? {\n\t\t\tentryKey: `agents/${id}`,\n\t\t\tentryPath: filePath\n\t\t} : null;\n\t}\n\tif (relativePath.startsWith(workflowsPrefix) && /\\.(ts|mts)$/.test(relativePath) && !/\\.(int\\.)?test\\.(ts|mts)$/.test(relativePath)) {\n\t\tconst id = entryIdFromFile(join(srcRoot, \"workflows\"), filePath, { nestedEntry: \"workflow\" });\n\t\treturn id ? {\n\t\t\tentryKey: `workflows/${id}`,\n\t\t\tentryPath: filePath\n\t\t} : null;\n\t}\n\tif (relativePath.startsWith(triggersPrefix) && /\\.(ts|mts)$/.test(relativePath) && !/\\.(int\\.)?test\\.(ts|mts)$/.test(relativePath)) {\n\t\tconst id = entryIdFromFile(join(srcRoot, \"triggers\"), filePath, { nestedEntry: \"trigger\" });\n\t\treturn id ? {\n\t\t\tentryKey: `triggers/${id}`,\n\t\t\tentryPath: filePath\n\t\t} : null;\n\t}\n\treturn null;\n}\nfunction shouldSkipIgnoredModule(filePath, phase) {\n\treturn shouldSkipKeystrokeModuleFile(readKeystrokeIgnoreDirective(filePath), phase);\n}\nfunction isSrcTypeScriptFile(srcRoot, filePath) {\n\tconst relativePath = toPosix(relative(srcRoot, filePath));\n\tif (relativePath.startsWith(\"..\")) return false;\n\treturn /\\.(ts|mts)$/.test(relativePath);\n}\nfunction walkTree(root, dir, srcRoot, phase, collectSources, sourceFiles, buildEntries, ignoredFiles, totals) {\n\tfor (const name of readdirSync(dir).sort()) {\n\t\tif (collectSources && (sourceFiles.length >= 2e3 || totals.bytes >= 8388608)) return;\n\t\tconst absolute = join(dir, name);\n\t\tconst stats = statSync(absolute);\n\t\tif (stats.isDirectory()) {\n\t\t\tif (IGNORED_DIRS.has(name)) continue;\n\t\t\twalkTree(root, absolute, srcRoot, phase, collectSources, sourceFiles, buildEntries, ignoredFiles, totals);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!stats.isFile()) continue;\n\t\tconst isUnderSrc = isSrcTypeScriptFile(srcRoot, absolute);\n\t\tconst skipIgnored = isUnderSrc ? shouldSkipIgnoredModule(absolute, phase) : false;\n\t\tif (isUnderSrc && skipIgnored) ignoredFiles.push(normalizeBuildFilePath(absolute));\n\t\tconst buildEntry = classifyBuildEntry(root, srcRoot, absolute);\n\t\tif (buildEntry && !skipIgnored) buildEntries[buildEntry.entryKey] = buildEntry.entryPath;\n\t\tif (!collectSources) continue;\n\t\tif (stats.size > 262144 || isIgnoredFile(name)) continue;\n\t\tconst buffer = readFileSync(absolute);\n\t\tif (isProbablyBinary(buffer)) continue;\n\t\ttotals.bytes += buffer.byteLength;\n\t\tsourceFiles.push({\n\t\t\tpath: toPosix(relative(root, absolute)),\n\t\t\tcontents: buffer.toString(\"utf8\"),\n\t\t\thash: createHash(\"sha256\").update(buffer).digest(\"hex\")\n\t\t});\n\t}\n}\n/**\n* One full-tree walk of the project: classifies tsdown entries and optionally\n* collects deploy source files (path + contents + hash) under snapshot limits.\n*/\nfunction walkProject(root, srcDirOrOptions = \"src\", maybeOptions) {\n\tconst srcDir = typeof srcDirOrOptions === \"string\" ? srcDirOrOptions : srcDirOrOptions.srcDir ?? \"src\";\n\tconst options = typeof srcDirOrOptions === \"string\" ? maybeOptions ?? {} : srcDirOrOptions;\n\tconst collectSources = options.collectSources ?? false;\n\tconst phase = options.phase ?? \"build\";\n\tconst sourceFiles = [];\n\tconst buildEntries = {};\n\tconst ignoredFiles = [];\n\twalkTree(root, root, join(root, srcDir), phase, collectSources, sourceFiles, buildEntries, ignoredFiles, { bytes: 0 });\n\treturn {\n\t\tsourceFiles,\n\t\tbuildEntries,\n\t\tignoredFiles\n\t};\n}\n//#endregion\nexport { keystrokeIgnoreGuardPlugin as n, walkProject as t };\n\n//# sourceMappingURL=walk-project-eZ95LOUW.mjs.map","import { isBuiltin } from \"node:module\";\n\n/** Native addons kept external — resolved from the CLI runtime at app start. */\nexport const NATIVE_RUNTIME_DEPS = [\"pg\", \"better-sqlite3\", \"@parcel/watcher\"];\n\n/**\n * Framework/runtime `@keystrokehq/*` shipped in the project-server image, so user-app builds\n * keep them external and resolve them from the runtime at boot. Everything else under the scope\n * (Composio catalog integrations like `@keystrokehq/posthog`, …) is bundled into the artifact.\n *\n * This set MUST equal the `@keystrokehq/*` dependency closure of `@keystrokehq/project-runtime`\n * (the deploy image) — `deps.test.ts` enforces it. To change what stays external, change what the\n * runtime image depends on; do not edit this list by hand. `exa`/`googlesuper` are runtime\n * integrations the framework imports directly (e.g. prebuilt web fetch); `slack` is a gateway\n * integration mounted server-side.\n */\nexport const RUNTIME_KEYSTROKE_PACKAGES = new Set([\n \"access-control\",\n \"action\",\n \"agent\",\n \"app\",\n \"auth\",\n \"build\",\n \"config\",\n \"credentials\",\n \"database\",\n \"exa\",\n \"gateway\",\n \"googlesuper\",\n \"hosting\",\n \"http\",\n \"keystroke\",\n \"manifest\",\n \"mcp\",\n \"memory\",\n \"oauth\",\n \"platform-database\",\n \"project-runtime\",\n \"projects\",\n \"runtime\",\n \"sandbox\",\n \"scheduler\",\n \"sdk\",\n \"secrets\",\n \"shared\",\n \"slack\",\n \"storage\",\n \"tracing\",\n \"trigger\",\n \"tsdown-config\",\n \"web-search\",\n \"worker\",\n \"workflow\",\n]);\n\n/** Matches framework/runtime `@keystrokehq/*` kept external during user-app builds. */\nexport const FRAMEWORK_KEYSTROKE_EXTERNAL = new RegExp(\n `^@keystrokehq\\\\/(?:${[...RUNTIME_KEYSTROKE_PACKAGES].sort().join(\"|\")})(?:\\\\/|$)`,\n);\n\nfunction keystrokePackageName(name) {\n if (!name.startsWith(\"@keystrokehq/\")) {\n return null;\n }\n\n return name.slice(\"@keystrokehq/\".length).split(\"/\")[0] ?? null;\n}\n\nfunction isRuntimeKeystrokePackage(name) {\n const pkg = keystrokePackageName(name);\n return pkg !== null && RUNTIME_KEYSTROKE_PACKAGES.has(pkg);\n}\n\n/** Kept external so .d.ts emission does not inline internal/inferred types. */\nexport const LIBRARY_EXTERNAL_DEPS = [\"better-auth\", /^@better-auth\\//, /^better-auth\\//];\n\n/** Non-auth runtime deps kept external for published entry bundles (platform, etc.). */\nexport const BUNDLED_ENTRY_RUNTIME_EXTERNAL_DEPS = [\n ...NATIVE_RUNTIME_DEPS,\n \"dockerode\",\n \"ssh2\",\n \"cpu-features\",\n \"microsandbox\",\n /^@aws-sdk\\//,\n /^@napi-rs\\//,\n \"hono\",\n /^@hono\\//,\n \"undici\",\n];\n\n/** Kept external when bundling published entry points (cli, keystroke, platform). */\nexport const BUNDLED_ENTRY_EXTERNAL_DEPS = [\n ...BUNDLED_ENTRY_RUNTIME_EXTERNAL_DEPS,\n ...LIBRARY_EXTERNAL_DEPS,\n];\n\n/** Bundle into CLI — device login uses Better Auth client only. */\nexport const BETTER_AUTH_CLIENT_BUNDLE_PATTERNS = [\n /^better-auth\\/client$/,\n /^better-auth\\/client\\//,\n];\n\n/** Server adapters and root entry — must not ship in the CLI bundle. */\nexport const BETTER_AUTH_SERVER_EXTERNAL_PATTERNS = [\n /^better-auth$/,\n /^@better-auth\\//,\n /^better-auth\\/(?!client(\\/|$)).+/,\n];\n\nexport function isNativeRuntimeDep(id) {\n return NATIVE_RUNTIME_DEPS.some((dep) => id === dep || id.startsWith(`${dep}/`));\n}\n\nfunction packageName(id) {\n if (id.startsWith(\"@\")) {\n const [scope, name] = id.split(\"/\");\n return name ? `${scope}/${name}` : id;\n }\n\n return id.split(\"/\")[0] ?? id;\n}\n\nfunction isRuntimeExternal(id) {\n const name = packageName(id);\n if (isNativeRuntimeDep(name)) {\n return true;\n }\n\n if (name.startsWith(\"@keystrokehq/\")) {\n return isRuntimeKeystrokePackage(name);\n }\n\n if (name === \"better-auth\" || name.startsWith(\"@better-auth/\")) {\n return true;\n }\n\n return false;\n}\n\n/** Library packages resolve npm deps from node_modules at runtime. */\nexport function libraryBuildDepsConfig() {\n return {\n alwaysBundle: (_id) => null,\n neverBundle: [...NATIVE_RUNTIME_DEPS, /^@keystrokehq\\//, ...LIBRARY_EXTERNAL_DEPS],\n onlyBundle: false,\n };\n}\n\n/** Bundle npm deps into dist; resolve @keystrokehq/* and natives from the runtime. */\nexport function userAppBuildDepsConfig() {\n return {\n alwaysBundle: (id, _importer) => {\n if (id.startsWith(\".\") || id.startsWith(\"/\") || isBuiltin(id)) {\n return null;\n }\n\n return isRuntimeExternal(id) ? null : true;\n },\n neverBundle: [...NATIVE_RUNTIME_DEPS, FRAMEWORK_KEYSTROKE_EXTERNAL, ...LIBRARY_EXTERNAL_DEPS],\n onlyBundle: false,\n };\n}\n\n/**\n * Published entry packages (cli, keystroke, platform): declare bundled @keystrokehq/*\n * in dependencies (changesets release graph ignores devDependencies). Inlining is\n * driven by alwaysBundle below, not by dep kind. Runtime npm deps stay external.\n */\nexport function bundledEntryDepsConfig() {\n return {\n alwaysBundle: [/^@keystrokehq\\//],\n neverBundle: [...BUNDLED_ENTRY_EXTERNAL_DEPS],\n onlyBundle: false,\n };\n}\n\n/** Published CLI: inline better-auth client + @better-auth/*; keep server adapters external. */\nexport const BETTER_AUTH_CLI_BUNDLE_PATTERNS = [\n ...BETTER_AUTH_CLIENT_BUNDLE_PATTERNS,\n /^@better-auth\\//,\n];\n\nexport const BETTER_AUTH_CLI_EXTERNAL_PATTERNS = [\n /^better-auth$/,\n /^better-auth\\/(?!client(\\/|$)).+/,\n /^@better-auth\\/drizzle-adapter/,\n \"drizzle-orm\",\n];\n\n/** Rolldown/tsdown — native bindings; stay in CLI node_modules at runtime. */\nexport const CLI_BUILD_TOOL_EXTERNAL_PATTERNS = [\"tsdown\", \"rolldown\", /^@rolldown\\//, \"tsx\"];\n\n/** CLI: inline better-auth/client; keep server + drizzle adapters external. */\nexport function cliBundledEntryDepsConfig() {\n return {\n alwaysBundle: [/^@keystrokehq\\//, ...BETTER_AUTH_CLI_BUNDLE_PATTERNS],\n neverBundle: [\n ...BUNDLED_ENTRY_RUNTIME_EXTERNAL_DEPS,\n ...BETTER_AUTH_CLI_EXTERNAL_PATTERNS,\n ...CLI_BUILD_TOOL_EXTERNAL_PATTERNS,\n ],\n onlyBundle: false,\n };\n}\n","import { bundledEntryDepsConfig, libraryBuildDepsConfig, userAppBuildDepsConfig } from \"./deps.js\";\n\nexport {\n isNativeRuntimeDep,\n NATIVE_RUNTIME_DEPS,\n bundledEntryDepsConfig,\n cliBundledEntryDepsConfig,\n libraryBuildDepsConfig,\n userAppBuildDepsConfig,\n} from \"./deps.js\";\n\nexport const baseTsdownConfig = {\n format: [\"esm\", \"cjs\"],\n dts: true,\n clean: true,\n sourcemap: true,\n target: \"node20\",\n deps: libraryBuildDepsConfig(),\n};\n\n/** tsdown config for published bundles (cli, keystroke, platform). */\nexport const bundledEntryTsdownConfig = {\n format: [\"esm\", \"cjs\"],\n dts: true,\n clean: true,\n sourcemap: true,\n target: \"node20\",\n deps: bundledEntryDepsConfig(),\n};\n","import { n as keystrokeIgnoreGuardPlugin, t as walkProject } from \"./walk-project-eZ95LOUW.mjs\";\nimport { t as resolveModuleDirs } from \"./resolve-module-dirs-BPHQhRGy.mjs\";\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\nimport { packAssetDirs } from \"@keystrokehq/sandbox/files\";\nimport { baseTsdownConfig, userAppBuildDepsConfig } from \"@keystrokehq/tsdown-config\";\nimport { build, mergeConfig } from \"tsdown\";\nimport { buildStoredRouteManifestForProject } from \"@keystrokehq/manifest\";\n//#region src/resolve-runtime-artifact.ts\nfunction packageRoot(nodeModules, scope, name) {\n\tconst direct = scope ? join(nodeModules, scope, name) : join(nodeModules, name);\n\tif (existsSync(join(direct, \"package.json\"))) return direct;\n\tconst pnpmDir = join(nodeModules, \".pnpm\");\n\tif (!existsSync(pnpmDir)) return null;\n\tfor (const entry of readdirSync(pnpmDir)) {\n\t\tconst candidate = scope ? join(pnpmDir, entry, \"node_modules\", scope, name) : join(pnpmDir, entry, \"node_modules\", name);\n\t\tif (existsSync(join(candidate, \"package.json\"))) return candidate;\n\t}\n\treturn null;\n}\n/** Resolve a file shipped with `@keystrokehq/build` inside the CLI runtime. */\nfunction resolveRuntimeBuildArtifact(runtimeNodeModules, relativePath) {\n\tconst pkgRoot = packageRoot(runtimeNodeModules, \"@keystrokehq\", \"build\");\n\tif (!pkgRoot) throw new Error(\"Keystroke runtime is missing @keystrokehq/build\");\n\tconst artifact = join(pkgRoot, relativePath);\n\tif (!existsSync(artifact)) throw new Error(`Keystroke runtime artifact not found: ${relativePath}`);\n\treturn artifact;\n}\n//#endregion\n//#region src/vitest-plugin.ts\nconst ASSETS_MODULE$1 = \"@keystrokehq/assets\";\nconst virtualPrefix = `\\0${ASSETS_MODULE$1}:`;\n/** Vitest plugin resolving `@keystrokehq/assets` from disk. */\nfunction agentAssetsVitestPlugin(appRoot = process.cwd()) {\n\tlet manifest = null;\n\treturn {\n\t\tname: \"keystroke-assets\",\n\t\tresolveId(source) {\n\t\t\tif (source !== ASSETS_MODULE$1) return null;\n\t\t\treturn `${virtualPrefix}manifest`;\n\t\t},\n\t\tload(id) {\n\t\t\tif (id !== `${virtualPrefix}manifest`) return null;\n\t\t\tmanifest ??= packAssetDirs(appRoot);\n\t\t\treturn `export default ${JSON.stringify(manifest)};`;\n\t\t}\n\t};\n}\nfunction findAppRootFromConfig(configFile) {\n\tif (!configFile) return process.cwd();\n\treturn dirname(configFile);\n}\nfunction agentAssetsVitestPluginFromConfig(configFile) {\n\treturn agentAssetsVitestPlugin(findAppRootFromConfig(configFile));\n}\n//#endregion\n//#region src/resolve-build-filter.ts\n/** Resolve exact build-entry keys for a filtered deploy build. */\nfunction resolveBuildFilter(filter, buildEntries) {\n\tif (filter.length === 0) throw new Error(\"At least one --filter entry is required\");\n\tconst matched = {};\n\tfor (const key of [...new Set(filter)]) {\n\t\tconst entryPath = buildEntries[key];\n\t\tif (!entryPath) throw new Error(`Unknown build entry \"${key}\". Use keys like agents/foo or workflows/bar from walkProject.`);\n\t\tmatched[key] = entryPath;\n\t}\n\treturn matched;\n}\n//#endregion\n//#region src/build-filtered.ts\nfunction toPosix(path) {\n\treturn path.replace(/\\\\/g, \"/\");\n}\nfunction distRelativePath(entryKey) {\n\treturn `${entryKey}.mjs`;\n}\nasync function buildSingleEntry(root, entryKey, entryPath, ignoredFiles) {\n\tmkdirSync(join(root, \".keystroke\"), { recursive: true });\n\tconst scratchRoot = mkdtempSync(join(root, \".keystroke\", \"filter-build-\"));\n\tconst outDir = join(scratchRoot, \"dist\");\n\tconst relativePath = distRelativePath(entryKey);\n\tawait build(mergeConfig(baseTsdownConfig, {\n\t\tentry: { [entryKey]: entryPath },\n\t\tformat: [\"esm\"],\n\t\toutDir,\n\t\tclean: true,\n\t\tdts: false,\n\t\tloader: { \".md\": \"text\" },\n\t\tdeps: userAppBuildDepsConfig(),\n\t\tplugins: [keystrokeIgnoreGuardPlugin({\n\t\t\troot,\n\t\t\tignoredFiles\n\t\t})]\n\t}));\n\treturn {\n\t\tscratchRoot,\n\t\trelativePath\n\t};\n}\nasync function manifestEntriesForBuiltModule(root, entryPath, relativePath, contents, sourceMap) {\n\tconst moduleFile = toPosix(relative(root, entryPath));\n\tconst distPath = join(root, \"dist\", relativePath);\n\tconst distMapPath = `${distPath}.map`;\n\tconst previousDist = existsSync(distPath) ? readFileSync(distPath) : void 0;\n\tconst hadMap = existsSync(distMapPath);\n\tconst previousMap = hadMap ? readFileSync(distMapPath) : void 0;\n\tmkdirSync(dirname(distPath), { recursive: true });\n\twriteFileSync(distPath, contents);\n\tif (sourceMap) writeFileSync(distMapPath, sourceMap);\n\ttry {\n\t\treturn (await buildStoredRouteManifestForProject(root, { reloadModules: true })).entries.filter((entry) => \"moduleFile\" in entry && entry.moduleFile === moduleFile);\n\t} finally {\n\t\tif (previousDist) writeFileSync(distPath, previousDist);\n\t\telse rmSync(distPath, { force: true });\n\t\tif (previousMap) writeFileSync(distMapPath, previousMap);\n\t\telse if (sourceMap || hadMap) rmSync(distMapPath, { force: true });\n\t}\n}\n/** Build selected modules in isolation for a filtered deploy merge. */\nasync function buildFilteredApp(options) {\n\tconst root = options.root ?? process.cwd();\n\tconst srcDir = options.srcDir ?? \"src\";\n\tconst phase = options.phase ?? \"deploy\";\n\tconst collectSources = options.collectSources ?? false;\n\tconst previous = process.cwd();\n\tconst walked = walkProject(root, {\n\t\tsrcDir,\n\t\tcollectSources,\n\t\tphase\n\t});\n\tconst matched = resolveBuildFilter(options.filter, walked.buildEntries);\n\tconst files = [];\n\tconst manifestEntries = [];\n\ttry {\n\t\tprocess.chdir(root);\n\t\tfor (const [entryKey, entryPath] of Object.entries(matched)) {\n\t\t\tconst { scratchRoot, relativePath } = await buildSingleEntry(root, entryKey, entryPath, walked.ignoredFiles);\n\t\t\ttry {\n\t\t\t\tconst builtPath = join(scratchRoot, \"dist\", relativePath);\n\t\t\t\tconst mapPath = `${builtPath}.map`;\n\t\t\t\tconst contents = readFileSync(builtPath);\n\t\t\t\tconst sourceMap = existsSync(mapPath) ? readFileSync(mapPath) : void 0;\n\t\t\t\tfiles.push({\n\t\t\t\t\tentryKey,\n\t\t\t\t\trelativePath,\n\t\t\t\t\tcontents,\n\t\t\t\t\tsourceMap\n\t\t\t\t});\n\t\t\t\tmanifestEntries.push(...await manifestEntriesForBuiltModule(root, entryPath, relativePath, contents, sourceMap));\n\t\t\t} finally {\n\t\t\t\trmSync(scratchRoot, {\n\t\t\t\t\trecursive: true,\n\t\t\t\t\tforce: true\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tprocess.chdir(previous);\n\t}\n\treturn {\n\t\tfiles,\n\t\tmanifestEntries,\n\t\tsourceFiles: walked.sourceFiles\n\t};\n}\n//#endregion\n//#region src/index.ts\nconst ASSETS_MODULE = \"@keystrokehq/assets\";\nconst VIRTUAL_PREFIX = `\\0${ASSETS_MODULE}:`;\nfunction renderAssetModule(manifest) {\n\treturn `export default ${JSON.stringify(manifest)};\\n`;\n}\n/** Rolldown plugin: pack src/skills + src/files and expose `@keystrokehq/assets`. */\nfunction agentAssetsPlugin(options) {\n\tconst srcDir = options.srcDir ?? \"src\";\n\tlet manifest = null;\n\treturn {\n\t\tname: \"keystroke-assets\",\n\t\tbuildStart() {\n\t\t\tmanifest = packAssetDirs(options.root, srcDir);\n\t\t},\n\t\tresolveId(source) {\n\t\t\tif (source !== ASSETS_MODULE) return null;\n\t\t\treturn `${VIRTUAL_PREFIX}manifest`;\n\t\t},\n\t\tload(id) {\n\t\t\tif (id !== `${VIRTUAL_PREFIX}manifest` || !manifest) return null;\n\t\t\treturn renderAssetModule(manifest);\n\t\t},\n\t\tbuildEnd() {\n\t\t\tif (!manifest) return;\n\t\t\tconst outDir = join(options.root, options.outDir ?? \"dist\", \".keystroke\");\n\t\t\tmkdirSync(outDir, { recursive: true });\n\t\t\twriteFileSync(join(outDir, \"assets.mjs\"), renderAssetModule(manifest));\n\t\t}\n\t};\n}\n/** Full tsdown config for user keystroke apps (config + discovered modules only). */\nfunction createAppBuildConfig(options = {}, walked) {\n\tconst root = options.root ?? process.cwd();\n\tconst srcDir = options.srcDir ?? \"src\";\n\tconst outDir = options.outDir ?? \"dist\";\n\tconst configEntry = existsSync(join(root, \"keystroke.config.ts\")) ? join(root, \"keystroke.config.ts\") : void 0;\n\tconst walkedResult = walked ?? walkProject(root, {\n\t\tsrcDir,\n\t\tphase: options.phase\n\t});\n\tconst discovered = walkedResult.buildEntries;\n\tconst ignoredFiles = walkedResult.ignoredFiles;\n\tconst entries = {\n\t\t...configEntry ? { config: configEntry } : {},\n\t\t...discovered\n\t};\n\tif (Object.keys(entries).length === 0) throw new Error(\"Nothing to build — add keystroke.config.ts or modules under src/\");\n\treturn mergeConfig(baseTsdownConfig, {\n\t\tentry: entries,\n\t\tformat: [\"esm\"],\n\t\toutDir: join(root, outDir),\n\t\tclean: options.clean ?? true,\n\t\tdts: false,\n\t\tloader: { \".md\": \"text\" },\n\t\tdeps: userAppBuildDepsConfig(),\n\t\tplugins: [keystrokeIgnoreGuardPlugin({\n\t\t\troot,\n\t\t\tignoredFiles\n\t\t}), agentAssetsPlugin({\n\t\t\troot,\n\t\t\tsrcDir,\n\t\t\toutDir\n\t\t})]\n\t});\n}\n/** Build user agents, workflows, triggers, and config to `dist/`. */\nasync function buildApp(options = {}) {\n\tconst root = options.root ?? process.cwd();\n\tconst srcDir = options.srcDir ?? \"src\";\n\tconst emitManifest = options.emitManifest ?? true;\n\tconst collectSources = options.collectSources ?? false;\n\tconst phase = options.phase ?? \"build\";\n\tconst previous = process.cwd();\n\tconst walked = walkProject(root, {\n\t\tsrcDir,\n\t\tcollectSources,\n\t\tphase\n\t});\n\ttry {\n\t\tprocess.chdir(root);\n\t\tawait build(createAppBuildConfig({\n\t\t\t...options,\n\t\t\troot\n\t\t}, {\n\t\t\tbuildEntries: walked.buildEntries,\n\t\t\tignoredFiles: walked.ignoredFiles\n\t\t}));\n\t\tif (emitManifest) {\n\t\t\tconst { emitStoredRouteManifestForProject } = await import(\"@keystrokehq/manifest\");\n\t\t\tawait emitStoredRouteManifestForProject(root);\n\t\t}\n\t} finally {\n\t\tprocess.chdir(previous);\n\t}\n\treturn { sourceFiles: walked.sourceFiles };\n}\n/**\n* Watch `src/` and rebuild `dist/` on change.\n*\n* NOT true hot reload — each change runs a full tsdown rebuild. Callers should\n* restart the API server in `onRebuild` so discovery picks up new/changed modules.\n*/\nasync function watchApp(options = {}) {\n\tconst { runWatchApp } = await import(\"./watch-app-DTIeKrbl.mjs\");\n\tawait runWatchApp((watchOptions) => buildApp({\n\t\t...watchOptions,\n\t\temitManifest: false,\n\t\tcollectSources: false\n\t}), options);\n}\n//#endregion\nexport { agentAssetsVitestPlugin, agentAssetsVitestPluginFromConfig, buildApp, buildFilteredApp, createAppBuildConfig, resolveBuildFilter, resolveModuleDirs, resolveRuntimeBuildArtifact, watchApp };\n\n//# sourceMappingURL=index.mjs.map"],"mappings":";;;;;;;;;AAMA,SAAS,UAAU,MAAM;CACxB,OAAO,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG;AAChC;AACA,SAAS,oBAAoB,MAAM,UAAU;CAC5C,OAAO,UAAU,SAAS,MAAM,uBAAuB,QAAQ,CAAC,CAAC;AAClE;;AAEA,SAAS,uBAAuB,UAAU;CACzC,MAAM,WAAW,QAAQ,QAAQ;CACjC,IAAI;EACH,OAAO,aAAa,OAAO,QAAQ;CACpC,QAAQ;EACP,OAAO;CACR;AACD;AACA,SAAS,kBAAkB,IAAI,MAAM;CACpC,IAAI,GAAG,WAAW,IAAI,GAAG,OAAO;CAChC,MAAM,aAAa,uBAAuB,GAAG,WAAW,SAAS,IAAI,cAAc,EAAE,IAAI,EAAE;CAC3F,IAAI,CAAC,WAAW,WAAW,uBAAuB,IAAI,CAAC,GAAG,OAAO;CACjE,OAAO;AACR;AACA,SAAS,uBAAuB,MAAM,aAAa,UAAU;CAC5D,MAAM,UAAU,oBAAoB,MAAM,WAAW;CACrD,IAAI,UAAU,OAAO,kBAAkB,QAAQ,8BAA8B,oBAAoB,MAAM,QAAQ,EAAE;CACjH,OAAO,kBAAkB,QAAQ;AAClC;;AAEA,SAAS,2BAA2B,SAAS;CAC5C,MAAM,OAAO,uBAAuB,QAAQ,IAAI;CAChD,MAAM,eAAe,IAAI,IAAI,QAAQ,aAAa,KAAK,aAAa,uBAAuB,QAAQ,CAAC,CAAC;CACrG,SAAS,iBAAiB,UAAU,UAAU;EAC7C,MAAM,aAAa,uBAAuB,QAAQ;EAClD,IAAI,CAAC,aAAa,IAAI,UAAU,GAAG;EACnC,MAAM,IAAI,MAAM,uBAAuB,MAAM,YAAY,QAAQ,CAAC;CACnE;CACA,OAAO;EACN,MAAM;EACN,MAAM,UAAU,QAAQ,UAAU,gBAAgB;GACjD,IAAI,gBAAgB,WAAW,CAAC,UAAU,OAAO;GACjD,MAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,UAAU;IACrD,GAAG;IACH,UAAU;GACX,CAAC;GACD,IAAI,CAAC,UAAU,OAAO;GACtB,iBAAiB,OAAO,aAAa,WAAW,WAAW,SAAS,IAAI,QAAQ;GAChF,OAAO;EACR;EACA,KAAK,IAAI;GACR,MAAM,aAAa,kBAAkB,IAAI,IAAI;GAC7C,IAAI,CAAC,YAAY,OAAO;GACxB,iBAAiB,UAAU;GAC3B,OAAO;EACR;CACD;AACD;AAGA,MAAM,eAAe,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AACD,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AACzB,SAAS,cAAc,MAAM;CAC5B,OAAO,iBAAiB,KAAK,IAAI,KAAK,iBAAiB,KAAK,IAAI;AACjE;AACA,SAASA,UAAQ,MAAM;CACtB,OAAO,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG;AAChC;AACA,SAAS,iBAAiB,QAAQ;CACjC,MAAM,eAAe,KAAK,IAAI,OAAO,QAAQ,GAAG;CAChD,KAAK,IAAI,QAAQ,GAAG,QAAQ,cAAc,SAAS,GAAG,IAAI,OAAO,WAAW,GAAG,OAAO;CACtF,OAAO;AACR;AACA,SAAS,mBAAmB,MAAM,SAAS,UAAU;CACpD,MAAM,eAAeA,UAAQ,SAAS,MAAM,QAAQ,CAAC;CACrD,MAAM,eAAe,GAAGA,UAAQ,SAAS,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,EAAE;CACzE,MAAM,kBAAkB,GAAGA,UAAQ,SAAS,MAAM,KAAK,SAAS,WAAW,CAAC,CAAC,EAAE;CAC/E,MAAM,iBAAiB,GAAGA,UAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,CAAC,CAAC,EAAE;CAC7E,IAAI,aAAa,WAAW,YAAY,KAAK,cAAc,KAAK,YAAY,KAAK,CAAC,4BAA4B,KAAK,YAAY,GAAG;EACjI,MAAM,KAAK,gBAAgB,KAAK,SAAS,QAAQ,GAAG,UAAU,EAAE,aAAa,QAAQ,CAAC;EACtF,OAAO,KAAK;GACX,UAAU,UAAU;GACpB,WAAW;EACZ,IAAI;CACL;CACA,IAAI,aAAa,WAAW,eAAe,KAAK,cAAc,KAAK,YAAY,KAAK,CAAC,4BAA4B,KAAK,YAAY,GAAG;EACpI,MAAM,KAAK,gBAAgB,KAAK,SAAS,WAAW,GAAG,UAAU,EAAE,aAAa,WAAW,CAAC;EAC5F,OAAO,KAAK;GACX,UAAU,aAAa;GACvB,WAAW;EACZ,IAAI;CACL;CACA,IAAI,aAAa,WAAW,cAAc,KAAK,cAAc,KAAK,YAAY,KAAK,CAAC,4BAA4B,KAAK,YAAY,GAAG;EACnI,MAAM,KAAK,gBAAgB,KAAK,SAAS,UAAU,GAAG,UAAU,EAAE,aAAa,UAAU,CAAC;EAC1F,OAAO,KAAK;GACX,UAAU,YAAY;GACtB,WAAW;EACZ,IAAI;CACL;CACA,OAAO;AACR;AACA,SAAS,wBAAwB,UAAU,OAAO;CACjD,OAAO,8BAA8B,6BAA6B,QAAQ,GAAG,KAAK;AACnF;AACA,SAAS,oBAAoB,SAAS,UAAU;CAC/C,MAAM,eAAeA,UAAQ,SAAS,SAAS,QAAQ,CAAC;CACxD,IAAI,aAAa,WAAW,IAAI,GAAG,OAAO;CAC1C,OAAO,cAAc,KAAK,YAAY;AACvC;AACA,SAAS,SAAS,MAAM,KAAK,SAAS,OAAO,gBAAgB,aAAa,cAAc,cAAc,QAAQ;CAC7G,KAAK,MAAM,QAAQ,YAAY,GAAG,EAAE,KAAK,GAAG;EAC3C,IAAI,mBAAmB,YAAY,UAAU,OAAO,OAAO,SAAS,UAAU;EAC9E,MAAM,WAAW,KAAK,KAAK,IAAI;EAC/B,MAAM,QAAQ,SAAS,QAAQ;EAC/B,IAAI,MAAM,YAAY,GAAG;GACxB,IAAI,aAAa,IAAI,IAAI,GAAG;GAC5B,SAAS,MAAM,UAAU,SAAS,OAAO,gBAAgB,aAAa,cAAc,cAAc,MAAM;GACxG;EACD;EACA,IAAI,CAAC,MAAM,OAAO,GAAG;EACrB,MAAM,aAAa,oBAAoB,SAAS,QAAQ;EACxD,MAAM,cAAc,aAAa,wBAAwB,UAAU,KAAK,IAAI;EAC5E,IAAI,cAAc,aAAa,aAAa,KAAK,uBAAuB,QAAQ,CAAC;EACjF,MAAM,aAAa,mBAAmB,MAAM,SAAS,QAAQ;EAC7D,IAAI,cAAc,CAAC,aAAa,aAAa,WAAW,YAAY,WAAW;EAC/E,IAAI,CAAC,gBAAgB;EACrB,IAAI,MAAM,OAAO,UAAU,cAAc,IAAI,GAAG;EAChD,MAAM,SAAS,aAAa,QAAQ;EACpC,IAAI,iBAAiB,MAAM,GAAG;EAC9B,OAAO,SAAS,OAAO;EACvB,YAAY,KAAK;GAChB,MAAMA,UAAQ,SAAS,MAAM,QAAQ,CAAC;GACtC,UAAU,OAAO,SAAS,MAAM;GAChC,MAAM,WAAW,QAAQ,EAAE,OAAO,MAAM,EAAE,OAAO,KAAK;EACvD,CAAC;CACF;AACD;;;;;AAKA,SAAS,YAAY,MAAM,kBAAkB,OAAO,cAAc;CACjE,MAAM,SAAS,OAAO,oBAAoB,WAAW,kBAAkB,gBAAgB,UAAU;CACjG,MAAM,UAAU,OAAO,oBAAoB,WAAW,gBAAgB,CAAC,IAAI;CAC3E,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,cAAc,CAAC;CACrB,MAAM,eAAe,CAAC;CACtB,MAAM,eAAe,CAAC;CACtB,SAAS,MAAM,MAAM,KAAK,MAAM,MAAM,GAAG,OAAO,gBAAgB,aAAa,cAAc,cAAc,EAAE,OAAO,EAAE,CAAC;CACrH,OAAO;EACN;EACA;EACA;CACD;AACD;;;;ACtKA,MAAa,sBAAsB;CAAC;CAAM;CAAkB;AAAiB;;;;;;;;;;;;AAa7E,MAAa,6BAA6B,IAAI,IAAI;CAChD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAa,+BAA+B,IAAI,OAC9C,sBAAsB,CAAC,GAAG,0BAA0B,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,WACzE;AAEA,SAAS,qBAAqB,MAAM;CAClC,IAAI,CAAC,KAAK,WAAW,eAAe,GAClC,OAAO;CAGT,OAAO,KAAK,MAAM,EAAsB,EAAE,MAAM,GAAG,EAAE,MAAM;AAC7D;AAEA,SAAS,0BAA0B,MAAM;CACvC,MAAM,MAAM,qBAAqB,IAAI;CACrC,OAAO,QAAQ,QAAQ,2BAA2B,IAAI,GAAG;AAC3D;;AAGA,MAAa,wBAAwB;CAAC;CAAe;CAAmB;AAAgB;;AAiBxF,MAAa,8BAA8B,CACzC,GAAG;CAdH,GAAG;CACH;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAKG,GACH,GAAG,qBACL;;AAGA,MAAa,qCAAqC,CAChD,yBACA,wBACF;AASA,SAAgB,mBAAmB,IAAI;CACrC,OAAO,oBAAoB,MAAM,QAAQ,OAAO,OAAO,GAAG,WAAW,GAAG,IAAI,EAAE,CAAC;AACjF;AAEA,SAAS,YAAY,IAAI;CACvB,IAAI,GAAG,WAAW,GAAG,GAAG;EACtB,MAAM,CAAC,OAAO,QAAQ,GAAG,MAAM,GAAG;EAClC,OAAO,OAAO,GAAG,MAAM,GAAG,SAAS;CACrC;CAEA,OAAO,GAAG,MAAM,GAAG,EAAE,MAAM;AAC7B;AAEA,SAAS,kBAAkB,IAAI;CAC7B,MAAM,OAAO,YAAY,EAAE;CAC3B,IAAI,mBAAmB,IAAI,GACzB,OAAO;CAGT,IAAI,KAAK,WAAW,eAAe,GACjC,OAAO,0BAA0B,IAAI;CAGvC,IAAI,SAAS,iBAAiB,KAAK,WAAW,eAAe,GAC3D,OAAO;CAGT,OAAO;AACT;;AAGA,SAAgB,yBAAyB;CACvC,OAAO;EACL,eAAe,QAAQ;EACvB,aAAa;GAAC,GAAG;GAAqB;GAAmB,GAAG;EAAqB;EACjF,YAAY;CACd;AACF;;AAGA,SAAgB,yBAAyB;CACvC,OAAO;EACL,eAAe,IAAI,cAAc;GAC/B,IAAI,GAAG,WAAW,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,UAAU,EAAE,GAC1D,OAAO;GAGT,OAAO,kBAAkB,EAAE,IAAI,OAAO;EACxC;EACA,aAAa;GAAC,GAAG;GAAqB;GAA8B,GAAG;EAAqB;EAC5F,YAAY;CACd;AACF;;;;;;AAOA,SAAgB,yBAAyB;CACvC,OAAO;EACL,cAAc,CAAC,iBAAiB;EAChC,aAAa,CAAC,GAAG,2BAA2B;EAC5C,YAAY;CACd;AACF;AAG+C,CAC7C,GAAG,kCAEL;;;ACzKA,MAAa,mBAAmB;CAC9B,QAAQ,CAAC,OAAO,KAAK;CACrB,KAAK;CACL,OAAO;CACP,WAAW;CACX,QAAQ;CACR,MAAM,uBAAuB;AAC/B;AASQ,uBAAuB;;;AClB/B,SAAS,YAAY,aAAa,OAAO,MAAM;CAC9C,MAAM,SAAS,QAAQ,KAAK,aAAa,OAAO,IAAI,IAAI,KAAK,aAAa,IAAI;CAC9E,IAAI,WAAW,KAAK,QAAQ,cAAc,CAAC,GAAG,OAAO;CACrD,MAAM,UAAU,KAAK,aAAa,OAAO;CACzC,IAAI,CAAC,WAAW,OAAO,GAAG,OAAO;CACjC,KAAK,MAAM,SAAS,YAAY,OAAO,GAAG;EACzC,MAAM,YAAY,QAAQ,KAAK,SAAS,OAAO,gBAAgB,OAAO,IAAI,IAAI,KAAK,SAAS,OAAO,gBAAgB,IAAI;EACvH,IAAI,WAAW,KAAK,WAAW,cAAc,CAAC,GAAG,OAAO;CACzD;CACA,OAAO;AACR;;AAEA,SAAS,4BAA4B,oBAAoB,cAAc;CACtE,MAAM,UAAU,YAAY,oBAAoB,gBAAgB,OAAO;CACvE,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,iDAAiD;CAC/E,MAAM,WAAW,KAAK,SAAS,YAAY;CAC3C,IAAI,CAAC,WAAW,QAAQ,GAAG,MAAM,IAAI,MAAM,yCAAyC,cAAc;CAClG,OAAO;AACR;;AA+BA,SAAS,mBAAmB,QAAQ,cAAc;CACjD,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,yCAAyC;CAClF,MAAM,UAAU,CAAC;CACjB,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,GAAG;EACvC,MAAM,YAAY,aAAa;EAC/B,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,wBAAwB,IAAI,+DAA+D;EAC3H,QAAQ,OAAO;CAChB;CACA,OAAO;AACR;AAGA,SAAS,QAAQ,MAAM;CACtB,OAAO,KAAK,QAAQ,OAAO,GAAG;AAC/B;AACA,SAAS,iBAAiB,UAAU;CACnC,OAAO,GAAG,SAAS;AACpB;AACA,eAAe,iBAAiB,MAAM,UAAU,WAAW,cAAc;CACxE,UAAU,KAAK,MAAM,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;CACvD,MAAM,cAAc,YAAY,KAAK,MAAM,cAAc,eAAe,CAAC;CACzE,MAAM,SAAS,KAAK,aAAa,MAAM;CACvC,MAAM,eAAe,iBAAiB,QAAQ;CAC9C,MAAM,MAAM,YAAY,kBAAkB;EACzC,OAAO,GAAG,WAAW,UAAU;EAC/B,QAAQ,CAAC,KAAK;EACd;EACA,OAAO;EACP,KAAK;EACL,QAAQ,EAAE,OAAO,OAAO;EACxB,MAAM,uBAAuB;EAC7B,SAAS,CAAC,2BAA2B;GACpC;GACA;EACD,CAAC,CAAC;CACH,CAAC,CAAC;CACF,OAAO;EACN;EACA;CACD;AACD;AACA,eAAe,8BAA8B,MAAM,WAAW,cAAc,UAAU,WAAW;CAChG,MAAM,aAAa,QAAQ,SAAS,MAAM,SAAS,CAAC;CACpD,MAAM,WAAW,KAAK,MAAM,QAAQ,YAAY;CAChD,MAAM,cAAc,GAAG,SAAS;CAChC,MAAM,eAAe,WAAW,QAAQ,IAAI,aAAa,QAAQ,IAAI,KAAK;CAC1E,MAAM,SAAS,WAAW,WAAW;CACrC,MAAM,cAAc,SAAS,aAAa,WAAW,IAAI,KAAK;CAC9D,UAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,cAAc,UAAU,QAAQ;CAChC,IAAI,WAAW,cAAc,aAAa,SAAS;CACnD,IAAI;EACH,QAAQ,MAAM,mCAAmC,MAAM,EAAE,eAAe,KAAK,CAAC,GAAG,QAAQ,QAAQ,UAAU,gBAAgB,SAAS,MAAM,eAAe,UAAU;CACpK,UAAU;EACT,IAAI,cAAc,cAAc,UAAU,YAAY;OACjD,OAAO,UAAU,EAAE,OAAO,KAAK,CAAC;EACrC,IAAI,aAAa,cAAc,aAAa,WAAW;OAClD,IAAI,aAAa,QAAQ,OAAO,aAAa,EAAE,OAAO,KAAK,CAAC;CAClE;AACD;;AAEA,eAAe,iBAAiB,SAAS;CACxC,MAAM,OAAO,QAAQ,QAAQ,QAAQ,IAAI;CACzC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,WAAW,QAAQ,IAAI;CAC7B,MAAM,SAAS,YAAY,MAAM;EAChC;EACA;EACA;CACD,CAAC;CACD,MAAM,UAAU,mBAAmB,QAAQ,QAAQ,OAAO,YAAY;CACtE,MAAM,QAAQ,CAAC;CACf,MAAM,kBAAkB,CAAC;CACzB,IAAI;EACH,QAAQ,MAAM,IAAI;EAClB,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,OAAO,GAAG;GAC5D,MAAM,EAAE,aAAa,iBAAiB,MAAM,iBAAiB,MAAM,UAAU,WAAW,OAAO,YAAY;GAC3G,IAAI;IACH,MAAM,YAAY,KAAK,aAAa,QAAQ,YAAY;IACxD,MAAM,UAAU,GAAG,UAAU;IAC7B,MAAM,WAAW,aAAa,SAAS;IACvC,MAAM,YAAY,WAAW,OAAO,IAAI,aAAa,OAAO,IAAI,KAAK;IACrE,MAAM,KAAK;KACV;KACA;KACA;KACA;IACD,CAAC;IACD,gBAAgB,KAAK,GAAG,MAAM,8BAA8B,MAAM,WAAW,cAAc,UAAU,SAAS,CAAC;GAChH,UAAU;IACT,OAAO,aAAa;KACnB,WAAW;KACX,OAAO;IACR,CAAC;GACF;EACD;CACD,UAAU;EACT,QAAQ,MAAM,QAAQ;CACvB;CACA,OAAO;EACN;EACA;EACA,aAAa,OAAO;CACrB;AACD;AAGA,MAAM,gBAAgB;AACtB,MAAM,iBAAiB,KAAK,cAAc;AAC1C,SAAS,kBAAkB,UAAU;CACpC,OAAO,kBAAkB,KAAK,UAAU,QAAQ,EAAE;AACnD;;AAEA,SAAS,kBAAkB,SAAS;CACnC,MAAM,SAAS,QAAQ,UAAU;CACjC,IAAI,WAAW;CACf,OAAO;EACN,MAAM;EACN,aAAa;GACZ,WAAW,cAAc,QAAQ,MAAM,MAAM;EAC9C;EACA,UAAU,QAAQ;GACjB,IAAI,WAAW,eAAe,OAAO;GACrC,OAAO,GAAG,eAAe;EAC1B;EACA,KAAK,IAAI;GACR,IAAI,OAAO,GAAG,eAAe,aAAa,CAAC,UAAU,OAAO;GAC5D,OAAO,kBAAkB,QAAQ;EAClC;EACA,WAAW;GACV,IAAI,CAAC,UAAU;GACf,MAAM,SAAS,KAAK,QAAQ,MAAM,QAAQ,UAAU,QAAQ,YAAY;GACxE,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;GACrC,cAAc,KAAK,QAAQ,YAAY,GAAG,kBAAkB,QAAQ,CAAC;EACtE;CACD;AACD;;AAEA,SAAS,qBAAqB,UAAU,CAAC,GAAG,QAAQ;CACnD,MAAM,OAAO,QAAQ,QAAQ,QAAQ,IAAI;CACzC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,cAAc,WAAW,KAAK,MAAM,qBAAqB,CAAC,IAAI,KAAK,MAAM,qBAAqB,IAAI,KAAK;CAC7G,MAAM,eAAe,UAAU,YAAY,MAAM;EAChD;EACA,OAAO,QAAQ;CAChB,CAAC;CACD,MAAM,aAAa,aAAa;CAChC,MAAM,eAAe,aAAa;CAClC,MAAM,UAAU;EACf,GAAG,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;EAC5C,GAAG;CACJ;CACA,IAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,MAAM,kEAAkE;CACzH,OAAO,YAAY,kBAAkB;EACpC,OAAO;EACP,QAAQ,CAAC,KAAK;EACd,QAAQ,KAAK,MAAM,MAAM;EACzB,OAAO,QAAQ,SAAS;EACxB,KAAK;EACL,QAAQ,EAAE,OAAO,OAAO;EACxB,MAAM,uBAAuB;EAC7B,SAAS,CAAC,2BAA2B;GACpC;GACA;EACD,CAAC,GAAG,kBAAkB;GACrB;GACA;GACA;EACD,CAAC,CAAC;CACH,CAAC;AACF;;AAEA,eAAe,SAAS,UAAU,CAAC,GAAG;CACrC,MAAM,OAAO,QAAQ,QAAQ,QAAQ,IAAI;CACzC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,WAAW,QAAQ,IAAI;CAC7B,MAAM,SAAS,YAAY,MAAM;EAChC;EACA;EACA;CACD,CAAC;CACD,IAAI;EACH,QAAQ,MAAM,IAAI;EAClB,MAAM,MAAM,qBAAqB;GAChC,GAAG;GACH;EACD,GAAG;GACF,cAAc,OAAO;GACrB,cAAc,OAAO;EACtB,CAAC,CAAC;EACF,IAAI,cAAc;GACjB,MAAM,EAAE,sCAAsC,MAAM,OAAO;GAC3D,MAAM,kCAAkC,IAAI;EAC7C;CACD,UAAU;EACT,QAAQ,MAAM,QAAQ;CACvB;CACA,OAAO,EAAE,aAAa,OAAO,YAAY;AAC1C;;;;;;;AAOA,eAAe,SAAS,UAAU,CAAC,GAAG;CACrC,MAAM,EAAE,gBAAgB,MAAM,OAAO;CACrC,MAAM,aAAa,iBAAiB,SAAS;EAC5C,GAAG;EACH,cAAc;EACd,gBAAgB;CACjB,CAAC,GAAG,OAAO;AACZ"}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: keystroke-credentials
|
|
3
|
-
description: Manage keystroke credentials — vault API keys and OAuth via keystroke credentials / keystroke connect, scopes, and getting creds into the cloud. Use when wiring Exa, Google, Slack, or custom API keys, and when a deployed run fails with missing credentials.
|
|
4
|
-
metadata:
|
|
5
|
-
keystroke-domain: credentials
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Credentials
|
|
9
|
-
|
|
10
|
-
Secrets live in a **credential store** (vault for API keys, OAuth stores for tokens) — never in source.
|
|
11
|
-
|
|
12
|
-
There are **two separate stores**: your **local** keystroke server and the **cloud** platform. `keystroke deploy` uploads your built code only — it never copies `.env` or local credentials. Provision creds for **every target you run on**.
|
|
13
|
-
|
|
14
|
-
## `.env` vs the credential store
|
|
15
|
-
|
|
16
|
-
| Holds | `.env` | Credential store |
|
|
17
|
-
| ----------------------------------------------------------------------------------------------------------------- | --------------------- | ----------------------- |
|
|
18
|
-
| Model keys (`ANTHROPIC_API_KEY`), DB URL, OAuth **app** config (`SLACK_CLIENT_ID`, `GOOGLE_*`, `SLACK_BOT_TOKEN`) | yes — local boot only | — |
|
|
19
|
-
| API-key + OAuth credential **instances** resolved by actions at runtime | — | yes |
|
|
20
|
-
| Reaches the cloud? | no | yes, when set vs. cloud |
|
|
21
|
-
|
|
22
|
-
The local server reads `.env` at boot; OAuth **app** env auto-seeds the local OAuth app so you can `connect`. **API-key credentials (Exa, custom) are not read from `.env`** — create them with `keystroke credentials set`.
|
|
23
|
-
|
|
24
|
-
## Scopes — default to `project`
|
|
25
|
-
|
|
26
|
-
A credential is stored at one scope:
|
|
27
|
-
|
|
28
|
-
| Scope | CLI | Means |
|
|
29
|
-
| --------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
30
|
-
| **project** (default) | `--scope project --project-id <id>` | Tied to one project. **Use this unless told otherwise** — you're provisioning the project you're working in. |
|
|
31
|
-
| **org** | `--scope org` | Shared by **every user and project in the org**. Only set org scope when the user explicitly asks for it. |
|
|
32
|
-
| **user** | `--scope user` | A single user's personal credential — a different use case, not project/deploy setup. |
|
|
33
|
-
|
|
34
|
-
`--scope` is required (there is no implicit default), so always pass it — pick `project` by default. Get the active project id from `keystroke config show`.
|
|
35
|
-
|
|
36
|
-
At runtime an action resolves a credential by checking the **org** scope first, then the **project** scope.
|
|
37
|
-
|
|
38
|
-
## Set an API key
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
# default: scope to the project you're deploying; read the value from your shell / .env
|
|
42
|
-
keystroke credentials set exa --scope project --project-id <id> --set apiKey=@env:EXA_API_KEY
|
|
43
|
-
|
|
44
|
-
# or paste the value directly
|
|
45
|
-
keystroke credentials set exa --scope project --project-id <id> --set apiKey=sk-...
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
- The field name (`apiKey`) comes from the integration's `defineCredential`.
|
|
49
|
-
- `@env:VAR` reads from your shell or project `.env`.
|
|
50
|
-
- `set` always creates a **new** instance. To change an existing one: `keystroke credentials update <id>`. A second instance in the same scope needs `--label <name>` (and `--default` to pick the one to resolve).
|
|
51
|
-
|
|
52
|
-
## Connect OAuth (Google, Slack, etc)
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
keystroke auth login
|
|
56
|
-
keystroke connect google
|
|
57
|
-
keystroke connect slack
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
`connect` completes the browser flow and stores the OAuth token in the active target's store, ready for any action that uses that integration. Run it against each target you deploy to.
|
|
61
|
-
|
|
62
|
-
## Targets: local vs cloud
|
|
63
|
-
|
|
64
|
-
`keystroke credentials` and `keystroke connect` follow the active runtime, exactly like other commands: **local** while `keystroke dev` runs or after `config use local`; the **deployed project** after `config use cloud` or with `--project`. A credential set locally does not exist in the cloud, and vice versa. See [cli skill](.agents/skills/keystroke-cli/SKILL.md).
|
|
65
|
-
|
|
66
|
-
## Before deploy: provision the cloud
|
|
67
|
-
|
|
68
|
-
The cloud store starts **empty**. After the first deploy:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
keystroke deploy --project <id> # uploads code only — no creds, no .env
|
|
72
|
-
keystroke config use cloud # target the deployed project
|
|
73
|
-
keystroke connect google # OAuth against cloud
|
|
74
|
-
keystroke credentials set exa --scope project --project-id <id> --set apiKey=@env:EXA_API_KEY
|
|
75
|
-
keystroke credentials list # verify against the active (cloud) target
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
A missing-credential error on a deployed run almost always means a credential set locally was never set in the cloud.
|
|
79
|
-
|
|
80
|
-
## Use in actions
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import { defineAction } from "@keystrokehq/action";
|
|
84
|
-
import { slackCredential } from "@keystrokehq/slack";
|
|
85
|
-
import { postMessage } from "@keystrokehq/slack/actions";
|
|
86
|
-
|
|
87
|
-
export const notify = defineAction({
|
|
88
|
-
slug: "notify",
|
|
89
|
-
credentials: [slackCredential] as const,
|
|
90
|
-
run: async (input, credentials) => postMessage.run(input, credentials),
|
|
91
|
-
});
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Integration actions (Exa search, Gmail send, Slack post) resolve credentials automatically from the active target's store when the plugin is configured.
|
|
95
|
-
|
|
96
|
-
## Audit
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
keystroke credentials list # instances for the active target
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Failed integration call → confirm you are on the right target (`keystroke config show`), the credential exists **for that target and scope**, OAuth was completed, and the action declares the right credential key.
|
|
103
|
-
|
|
104
|
-
## Next references
|
|
105
|
-
|
|
106
|
-
- [cli-and-oauth.md](references/cli-and-oauth.md) — auth, connect, local vs cloud stores
|
|
107
|
-
|
|
108
|
-
Related: [cli](.agents/skills/keystroke-cli/SKILL.md), [actions](.agents/skills/keystroke-actions/SKILL.md), [gateways](.agents/skills/keystroke-gateways/SKILL.md).
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Auth, connect, OAuth
|
|
2
|
-
|
|
3
|
-
## Log in once
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
keystroke auth login
|
|
7
|
-
keystroke auth status
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
Token is stored in the OS keychain and reused for **cloud** CLI commands. Switching between local dev and cloud (`keystroke config use local` / `cloud`) does not require logging in again. See [cli skill](.agents/skills/keystroke-cli/SKILL.md) for target routing.
|
|
11
|
-
|
|
12
|
-
## Connect integrations (OAuth)
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
keystroke connect google
|
|
16
|
-
keystroke connect slack
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Complete the browser flow once per provider. The token is stored server-side in the active target's store, ready for actions that use the integration. Run `connect` against each target you deploy to.
|
|
20
|
-
|
|
21
|
-
## Set an API key
|
|
22
|
-
|
|
23
|
-
For API keys that are not OAuth (e.g. Exa). The field name (`apiKey`) comes from the integration's `defineCredential`:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
# default to project scope — provision the project you're working in
|
|
27
|
-
keystroke credentials set exa --scope project --project-id <id> --set apiKey=@env:EXA_API_KEY
|
|
28
|
-
keystroke credentials list
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
`--scope` is required; there is no implicit default, so always pass it:
|
|
32
|
-
|
|
33
|
-
| Scope | When |
|
|
34
|
-
| ------------------- | ---------------------------------------------------------------------------- |
|
|
35
|
-
| `project` (default) | Tie the credential to one project — use this unless told otherwise. |
|
|
36
|
-
| `org` | Share with **every user and project** in the org — only on explicit request. |
|
|
37
|
-
| `user` | A single user's personal credential — different use case. |
|
|
38
|
-
|
|
39
|
-
`set` always creates a new instance; use `keystroke credentials update <id>` to change one, and `--label <name>` to add a second in the same scope. At runtime a credential resolves **org first, then project**.
|
|
40
|
-
|
|
41
|
-
## `.env` vs the credential store
|
|
42
|
-
|
|
43
|
-
| Holds | `.env` | Credential store |
|
|
44
|
-
| ---------------------------------------------------------------------------------------------- | --------------------- | ----------------------- |
|
|
45
|
-
| Model keys (`ANTHROPIC_API_KEY`), DB URL, OAuth **app** config (`SLACK_CLIENT_ID`, `GOOGLE_*`) | yes — local boot only | — |
|
|
46
|
-
| API-key + OAuth credential instances resolved at runtime | — | yes |
|
|
47
|
-
| Reaches the cloud? | no | yes, when set vs. cloud |
|
|
48
|
-
|
|
49
|
-
API-key credentials are **not** read from `.env` — create them with `keystroke credentials set`. `keystroke credentials` / `keystroke connect` target the **active** runtime (local while `keystroke dev` runs or after `config use local`; cloud after deploy / `config use cloud` / `--project`). The stores are independent; `keystroke deploy` never copies `.env` or local credentials, so re-provision against the cloud target after deploy.
|
|
50
|
-
|
|
51
|
-
Dashboard at `:3000` can also manage credentials and gateway attachments.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"version-CKAYz1xm.mjs","names":[],"sources":["../src/resolve-platform-url.ts","../src/config.ts","../src/project/resolve-cli-root.ts","../src/init/package-manager.ts","../src/version.ts"],"sourcesContent":["import { originFromPublicUrl } from \"@keystrokehq/shared\";\n\nexport const DEFAULT_WEB_URL = \"https://app.keystroke.ai\";\nexport const DEFAULT_PLATFORM_URL = \"https://api.keystroke.ai\";\nexport const LOCAL_WEB_URL = \"http://localhost:3000\";\nexport const LOCAL_PLATFORM_URL = \"http://localhost:3002\";\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_URL;\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 {\n DEFAULT_PLATFORM_URL,\n DEFAULT_WEB_URL,\n knownPlatformUrlForWebUrl,\n resolvePlatformUrlForWebUrl,\n} from \"./resolve-platform-url\";\n\nexport type ApiTargetMode = \"local\" | \"platform\";\n\nexport type CliConfig = {\n serverUrl: string;\n webUrl: string;\n platformUrl: string;\n activeOrganizationId?: string;\n activeProjectId?: string;\n apiTarget?: ApiTargetMode;\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\nexport function getEffectiveApiTarget(config: Conf<CliConfig>): ApiTargetMode {\n const explicit = config.get(\"apiTarget\");\n if (explicit === \"local\" || explicit === \"platform\") {\n return explicit;\n }\n\n return \"local\";\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 serverUrl: {\n type: \"string\",\n default: \"http://localhost:3001\",\n },\n webUrl: {\n type: \"string\",\n default: DEFAULT_WEB_URL,\n },\n platformUrl: {\n type: \"string\",\n default: DEFAULT_PLATFORM_URL,\n },\n activeOrganizationId: {\n type: \"string\",\n },\n activeProjectId: {\n type: \"string\",\n },\n apiTarget: {\n type: \"string\",\n enum: [\"local\", \"platform\"],\n },\n },\n });\n\n syncPlatformUrlWithWebUrl(config);\n return config;\n}\n\nexport function getServerUrl(config: Conf<CliConfig>): string {\n return config.get(\"serverUrl\");\n}\n\nexport function getWebUrl(config: Conf<CliConfig>): string {\n return config.get(\"webUrl\");\n}\n\nexport function getPlatformUrl(config: Conf<CliConfig>): string {\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 { 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, `keystroke dev` fails 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 { 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"],"mappings":"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"}
|