@keystrokehq/cli 0.1.45 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { $ as GetCredentialResponseSchema, $t as SkillSummaryListResponseSchema, A as CreateCustomAppRequestSchema, An as WorkflowCanvasCredentialBindingsSchema, At as PROJECT_REACHABILITY_REQUEST_TIMEOUT_MS, B as CredentialConsumerListQuerySchema, Bn as WorkflowSummaryListResponseSchema, Bt as ProjectPullStateSchema, C as ConnectAuthorizeUrlResponseSchema, Cn as UploadProjectSourceManifestRequestSchema, Ct as ListProjectMetricsResponseSchema, D as CreateCredentialInstanceBodySchema, Dn as UserAvatarSchema, Dt as OrganizationSidebarBrandingPatchSchema, E as CreateApiKeyResponseSchema, En as UserAvatarPatchSchema, Et as OpenApiDiscoverResponseSchema, F as CreateProjectRequestSchema, Fn as WorkflowRunInputsPutBodySchema, Ft as PresignOrgLogoResponseSchema, G as DOCS_QUERY_TOOL, Gn as WorkspaceTriggerRunListResponseSchema, Gt as PromptInputSchema, H as CredentialInstanceListResponseSchema, Hn as WorkspaceTriggerFileSchema, Ht as ProjectResponseSchema, I as CreateProjectResponseSchema, In as WorkflowRunInputsSchema, It as PresignProjectSourceRequestSchema, J as DownloadActiveProjectArtifactResponseSchema, Jt as QueuedAgentPromptResponseSchema, K as DOCS_SEARCH_TOOL, Kn as WorkspaceWorkflowOverviewSchema, Kt as PromptResponseSchema, L as CredentialAssignmentListQuerySchema, Ln as WorkflowRunListResponseSchema, Lt as PresignProjectSourceResponseSchema, M as CreateOrganizationRequestSchema, Mn as WorkflowCanvasSchema, Mt as PresignChatAttachmentRequestSchema, N as CreateOrganizationResponseSchema, Nn as WorkflowRunDetailResponseSchema, Nt as PresignChatAttachmentResponseSchema, O as CreateCredentialsRequestSchema, On as UserPreferencesPatchSchema, Ot as OrganizationSidebarBrandingSchema, P as CreateProjectArtifactResponseSchema, Pn as WorkflowRunHooksResponseSchema, Pt as PresignOrgLogoRequestSchema, Q as GatewayAttachmentRecordSchema, Qn as listenPortFromPublicUrl, Qt as SkillSummaryDetailResponseSchema, R as CredentialAssignmentListResponseSchema, Rn as WorkflowRunResponseSchema, Rt as PresignUserAvatarRequestSchema, S as CompleteProjectArtifactResponseSchema, Sn as UpdateProjectSettingsRequestSchema, St as ListProjectMembersResponseSchema, T as CreateApiKeyRequestSchema, Tn as UpsertGatewayAttachmentBodySchema, Tt as McpDiscoverResponseSchema, U as CredentialInstanceRecordSchema, Un as WorkspaceTriggerListResponseSchema, Ut as ProjectSettingsResponseSchema, V as CredentialConsumerListResponseSchema, Vn as WorkspaceTriggerDetailSchema, Vt as ProjectReachabilityResponseSchema, Wn as WorkspaceTriggerOverviewSchema, Wt as ProjectSlugAvailabilityResponseSchema, X as ErrorResponseSchema, Xn as detectProjectPackageManagerFromSnapshot, Y as DownloadActiveProjectSourceResponseSchema, Yn as deriveCustomAppDisplay, Yt as QueuedRunResponseSchema, Z as ExecuteKeystrokeToolRequestSchema, Zn as isAcceptableInstallExit, Zt as RecentResourceListResponseSchema, _ as ChannelAccountListResponseSchema, _n as UpdateOrganizationMemberResponseSchema, _t as ListOrganizationInvitationsResponseSchema, a as AgentSessionDetailResponseSchema, an as StartOAuthConnectionInputSchema, ar as resolveConnectAppSlug, at as HistoryRunListQuerySchema, b as ChannelDirectoryListResponseSchema, bn as UpdateProjectMemberResponseSchema, bt as ListProjectDeploymentsResponseSchema, c as AgentSummaryListResponseSchema, cn as SubmitTeamRequestRequestSchema, cr as slugifyAppName, ct as InviteOrganizationMembersResponseSchema, d as AssignCredentialBodySchema, dn as TriggerRunDetailResponseSchema, en as SlugAvailabilityResponseSchema, et as GetCustomAppResponseSchema, f as BindChannelBodySchema, fn as TriggerRunListResponseSchema, ft as ListAgentMemoryFilesResponseSchema, g as CatalogAppsPageResponseSchema, gn as UpdateOrganizationMemberRequestSchema, gt as ListCredentialsResponseSchema, h as CatalogAppDetailResponseSchema, hn as UpdateCredentialRequestSchema, ht as ListAppsResponseSchema, i as AgentSessionChatStateResponseSchema, in as StartMcpOAuthConnectionResultSchema, it as HistoryRunDetailResponseSchema, j as CreateCustomAppResponseSchema, jn as WorkflowCanvasRunSchema, jt as PollRunResponseSchema, k as CreateCredentialsResponseSchema, kn as UserPreferencesSchema, kt as PROJECT_PULL_STATE_RELATIVE_PATH, l as AgentTriggerSummaryListResponseSchema, ln as TriggerDetailResponseSchema, lt as InviteProjectMembersRequestSchema, m as CatalogActionsPageResponseSchema, mn as UpdateCredentialInstanceBodySchema, mt as ListApiKeysResponseSchema, n as AcceptOrganizationInvitationResponseSchema, nn as StartKeystrokeConnectionResultSchema, nr as parseErrorResponse, nt as HealthResponseSchema, o as AgentSessionListResponseSchema, on as StartOAuthConnectionResultSchema, or as resolveDocsMcpUrl, ot as HistoryRunListResponseSchema, p as CatalogActionDetailResponseSchema, pn as UpdateChannelBindingBodySchema, pt as ListAgentWorkspaceFilesResponseSchema, q as DeclineOrganizationInvitationResponseSchema, qn as buildConnectDeeplink, r as ActiveOrganizationResponseSchema, rn as StartMcpOAuthConnectionInputSchema, rt as HistoryRunCancelResponseSchema, s as AgentSummaryDetailResponseSchema, sn as SubmitMarketingContactRequestSchema, sr as resolvePublicPlatformOrigin, st as InviteOrganizationMembersRequestSchema, t as ACTIVE_ORG_HEADER, tn as StartKeystrokeConnectionInputSchema, tr as parseAppSlug, tt as GraphqlDiscoverResponseSchema, u as AppSlugAvailabilityResponseSchema, un as TriggerListResponseSchema, ut as InviteProjectMembersResponseSchema, v as ChannelConnectionListResponseSchema, vn as UpdateOrganizationRequestSchema, vt as ListOrganizationMembersResponseSchema, w as ConnectProvidersResponseSchema, wn as UploadProjectSourceResponseSchema, wt as ListProjectsResponseSchema, x as ChannelPlatformSchema, xn as UpdateProjectRequestSchema, xt as ListProjectFilesResponseSchema, y as ChannelConnectionSchema, yn as UpdateProjectMemberRequestSchema, yt as ListOrganizationsResponseSchema, z as CredentialAssignmentRecordSchema, zn as WorkflowSummaryDetailResponseSchema, zt as PresignUserAvatarResponseSchema } from "./dist-DtDJareY.mjs";
3
3
  import { i as packProjectArtifact, n as withMcpReadClient, r as mergeFilteredArtifact, t as mapInParallelBatches } from "./dist-83uw4_yr.mjs";
4
- import { a as installPlaygroundDependencies, c as createCliConfig, d as getEffectiveApiTarget, f as getPlatformUrl, g as resolvePlatformUrlForWebUrl, i as installDependencies$1, l as getCliConfigDir, m as DEFAULT_PLATFORM_URL, n as buildPlaygroundWorkspace, o as resolvePackageManager, p as getWebUrl, s as resolveCliRoot, t as readCliVersion, u as getConfigDir } from "./version-D2psJMX3.mjs";
4
+ import { _ as getPlatformUrl, c as detectPackageManager, d as resolveGithubPackagesToken, f as resolvePackageManager, g as getEffectiveApiTarget, h as getConfigDir, i as isReleaseAgeBlock, l as installDependencies$1, m as getCliConfigDir, n as resolveCliRoot, o as detectManagerFromLockfile, p as createCliConfig, s as buildPlaygroundWorkspace, t as readCliVersion, u as installPlaygroundDependencies, v as getWebUrl, x as resolvePlatformUrlForWebUrl, y as DEFAULT_PLATFORM_URL } from "./version-key3f4tc.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import { Command } from "commander";
7
7
  import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
8
  import { Entry } from "@napi-rs/keyring";
9
9
  import { confirm, input, select } from "@inquirer/prompts";
10
10
  import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
11
- import { access, lstat, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
11
+ import { access, lstat, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from "node:fs/promises";
12
12
  import { spawn, spawnSync } from "node:child_process";
13
13
  import { pathToFileURL } from "node:url";
14
14
  //#region ../../node_modules/.pnpm/ky@2.0.2/node_modules/ky/distribution/errors/KyError.js
@@ -6480,12 +6480,102 @@ function registerAuthCommand(program) {
6480
6480
  registerAuthStatusCommand(auth);
6481
6481
  }
6482
6482
  //#endregion
6483
+ //#region src/update/ensure-sdk-current.ts
6484
+ const KEYSTROKE_SCOPE = "@keystrokehq/";
6485
+ function shouldSkip() {
6486
+ return Boolean(process.env.KEYSTROKE_SKIP_UPDATE || process.env.CI === "true" || process.env.CI === "1");
6487
+ }
6488
+ function readPackageJson(root) {
6489
+ const path = join(root, "package.json");
6490
+ if (!existsSync(path)) return;
6491
+ try {
6492
+ return JSON.parse(readFileSync(path, "utf8"));
6493
+ } catch {
6494
+ return;
6495
+ }
6496
+ }
6497
+ /** Exact semver pins and local/workspace specs are left alone; everything else floats to latest. */
6498
+ function isPinnedSdkSpec(spec) {
6499
+ if (!spec) return true;
6500
+ const trimmed = spec.trim();
6501
+ if (trimmed.startsWith("workspace:") || trimmed.startsWith("link:") || trimmed.startsWith("file:")) return true;
6502
+ return /^\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/.test(trimmed);
6503
+ }
6504
+ function listFloatingKeystrokePackages(root) {
6505
+ const pkg = readPackageJson(root);
6506
+ if (!pkg) return [];
6507
+ const packages = [];
6508
+ for (const [name, spec] of Object.entries(pkg.dependencies ?? {})) if (name.startsWith(KEYSTROKE_SCOPE) && !isPinnedSdkSpec(spec)) packages.push({
6509
+ name,
6510
+ dev: false
6511
+ });
6512
+ for (const [name, spec] of Object.entries(pkg.devDependencies ?? {})) if (name.startsWith(KEYSTROKE_SCOPE) && !isPinnedSdkSpec(spec)) packages.push({
6513
+ name,
6514
+ dev: true
6515
+ });
6516
+ return packages;
6517
+ }
6518
+ function updateCommand(manager, packageName, dev) {
6519
+ const spec = `${packageName}@latest`;
6520
+ if (manager === "npm") return {
6521
+ command: "npm",
6522
+ args: dev ? [
6523
+ "install",
6524
+ "-D",
6525
+ spec
6526
+ ] : ["install", spec]
6527
+ };
6528
+ return {
6529
+ command: manager,
6530
+ args: dev ? [
6531
+ "add",
6532
+ "-D",
6533
+ spec
6534
+ ] : ["add", spec]
6535
+ };
6536
+ }
6537
+ function warnReleaseAgeBlock(packageName) {
6538
+ process.stderr.write(`Warning: ${packageName}@latest is held back by your minimum-release-age setting; continuing with the currently installed version.\n`);
6539
+ }
6540
+ /**
6541
+ * Keep floating @keystrokehq/* project dependencies on latest before build/deploy.
6542
+ * The package manager no-ops when already current; minimum-release-age failures warn only.
6543
+ */
6544
+ function ensureSdkCurrent(root) {
6545
+ if (shouldSkip()) return;
6546
+ const packages = listFloatingKeystrokePackages(root);
6547
+ if (packages.length === 0) return;
6548
+ const manager = detectManagerFromLockfile(root) ?? detectPackageManager();
6549
+ const token = resolveGithubPackagesToken();
6550
+ const env = token ? {
6551
+ ...process.env,
6552
+ NODE_AUTH_TOKEN: token
6553
+ } : process.env;
6554
+ for (const pkg of packages) {
6555
+ const { command, args } = updateCommand(manager, pkg.name, pkg.dev);
6556
+ process.stderr.write(`Ensuring ${pkg.name} is up to date...\n`);
6557
+ const result = spawnSync(command, args, {
6558
+ cwd: root,
6559
+ env,
6560
+ encoding: "utf8"
6561
+ });
6562
+ if (result.status === 0) continue;
6563
+ const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
6564
+ if (isReleaseAgeBlock(output)) {
6565
+ warnReleaseAgeBlock(pkg.name);
6566
+ continue;
6567
+ }
6568
+ process.stderr.write(`Warning: failed to update ${pkg.name}; continuing.\n${output}`);
6569
+ }
6570
+ }
6571
+ //#endregion
6483
6572
  //#region src/commands/build.ts
6484
6573
  function registerBuildCommand(program) {
6485
6574
  program.command("build").description("Build the keystroke project for production").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
6486
6575
  try {
6487
6576
  const root = resolveProjectRoot(options.dir);
6488
- const { buildApp } = await import("./dist-B7fZRB8p.mjs");
6577
+ ensureSdkCurrent(root);
6578
+ const { buildApp } = await import("./dist-CTHhFGjP.mjs");
6489
6579
  await buildApp({ root });
6490
6580
  process.stdout.write(`Built ${root}\n`);
6491
6581
  } catch (error) {
@@ -6495,6 +6585,76 @@ function registerBuildCommand(program) {
6495
6585
  });
6496
6586
  }
6497
6587
  //#endregion
6588
+ //#region src/tooling/resolve-configs-dir.ts
6589
+ /** Directory holding bundled tool configs (oxlint/vitest). Ships under dist/ for end users. */
6590
+ function resolveConfigsDir(fromModuleUrl = import.meta.url) {
6591
+ const cliRoot = resolveCliRoot(fromModuleUrl);
6592
+ const candidates = [join(cliRoot, "configs"), join(cliRoot, "dist", "configs")];
6593
+ for (const candidate of candidates) if (existsSync(candidate)) return candidate;
6594
+ throw new Error("Bundled tool configs not found — run `pnpm --filter @keystrokehq/cli build`");
6595
+ }
6596
+ //#endregion
6597
+ //#region src/tooling/run-tool.ts
6598
+ const require = createRequire(import.meta.url);
6599
+ /**
6600
+ * Resolve a bundled dev tool's executable from the CLI's own node_modules. The tools
6601
+ * (oxlint, vitest, typescript) ship as CLI dependencies, so user projects don't declare
6602
+ * them. Their bins are Node launchers, so callers run them with `node <bin>`.
6603
+ */
6604
+ function resolveToolBin(pkg, binName) {
6605
+ const packageJsonPath = require.resolve(`${pkg}/package.json`);
6606
+ const { bin } = JSON.parse(readFileSync(packageJsonPath, "utf8"));
6607
+ const relative = typeof bin === "string" ? bin : bin?.[binName];
6608
+ if (!relative) throw new Error(`Package "${pkg}" does not expose a "${binName}" bin`);
6609
+ return join(dirname(packageJsonPath), relative);
6610
+ }
6611
+ /** Run a bundled tool bin as a child process, inheriting stdio. Resolves with its exit code. */
6612
+ function runToolBin(options) {
6613
+ const binPath = resolveToolBin(options.pkg, options.binName);
6614
+ return new Promise((resolve, reject) => {
6615
+ const child = spawn(process.execPath, [binPath, ...options.args], {
6616
+ cwd: options.cwd,
6617
+ env: options.env ?? process.env,
6618
+ stdio: "inherit"
6619
+ });
6620
+ child.on("error", reject);
6621
+ child.on("exit", (code) => resolve(code ?? 1));
6622
+ });
6623
+ }
6624
+ //#endregion
6625
+ //#region src/tooling/run-lint.ts
6626
+ /** Lint the project with the bundled oxlint + config. Resolves with the oxlint exit code. */
6627
+ function runLint(root, args = ["."]) {
6628
+ return runToolBin({
6629
+ pkg: "oxlint",
6630
+ binName: "oxlint",
6631
+ args: [
6632
+ "--config",
6633
+ join(resolveConfigsDir(), "oxlintrc.json"),
6634
+ ...args
6635
+ ],
6636
+ cwd: root
6637
+ });
6638
+ }
6639
+ //#endregion
6640
+ //#region src/tooling/run-typecheck.ts
6641
+ /**
6642
+ * Type-check the project with the bundled TypeScript. tsdown (build) strips types without
6643
+ * checking them, so build/deploy call this as a gate. Resolves with the tsc exit code.
6644
+ */
6645
+ async function runTypecheck(root) {
6646
+ return runToolBin({
6647
+ pkg: "typescript",
6648
+ binName: "tsc",
6649
+ args: [
6650
+ "--noEmit",
6651
+ "-p",
6652
+ join(root, "tsconfig.json")
6653
+ ],
6654
+ cwd: root
6655
+ });
6656
+ }
6657
+ //#endregion
6498
6658
  //#region src/commands/deploy.ts
6499
6659
  const POLL_INTERVAL_MS = 2e3;
6500
6660
  const DEPLOY_TIMEOUT_MS = 12e4;
@@ -6538,7 +6698,7 @@ async function sleep(ms) {
6538
6698
  }
6539
6699
  async function buildDeployArchive(client, root, projectId, filter) {
6540
6700
  if (filter?.length) {
6541
- const { buildFilteredApp } = await import("./dist-B7fZRB8p.mjs");
6701
+ const { buildFilteredApp } = await import("./dist-CTHhFGjP.mjs");
6542
6702
  const filtered = await buildFilteredApp({
6543
6703
  root,
6544
6704
  filter,
@@ -6560,7 +6720,7 @@ async function buildDeployArchive(client, root, projectId, filter) {
6560
6720
  sourceFiles: filtered.sourceFiles
6561
6721
  };
6562
6722
  }
6563
- const { buildApp } = await import("./dist-B7fZRB8p.mjs");
6723
+ const { buildApp } = await import("./dist-CTHhFGjP.mjs");
6564
6724
  const { sourceFiles } = await buildApp({
6565
6725
  root,
6566
6726
  collectSources: true,
@@ -6574,6 +6734,9 @@ async function buildDeployArchive(client, root, projectId, filter) {
6574
6734
  }
6575
6735
  async function runDeploy(options) {
6576
6736
  const root = resolveProjectRoot(options.dir);
6737
+ ensureSdkCurrent(root);
6738
+ if (await runLint(root) !== 0) throw new Error("lint failed");
6739
+ if (await runTypecheck(root) !== 0) throw new Error("typecheck failed");
6577
6740
  const config = createCliConfig();
6578
6741
  const client = createCliPlatformClient(config);
6579
6742
  await ensureLinkedOrganization(config, root);
@@ -6682,7 +6845,7 @@ function runtimeChildEnv(parentEnv, overrides) {
6682
6845
  //#region src/project/bootstrap-run.ts
6683
6846
  /** Node args + env for `@keystrokehq/build` bootstrap (shared by start + dev). */
6684
6847
  async function resolveBootstrapRun(options) {
6685
- const { resolveRuntimeBuildArtifact } = await import("./dist-B7fZRB8p.mjs");
6848
+ const { resolveRuntimeBuildArtifact } = await import("./dist-CTHhFGjP.mjs");
6686
6849
  const loader = pathToFileURL(resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/runtime-loader.mjs")).href;
6687
6850
  const bootstrap = resolveRuntimeBuildArtifact(options.runtimeNodeModules, "dist/standalone-bootstrap.mjs");
6688
6851
  const args = [`--import=${loader}`];
@@ -6831,7 +6994,7 @@ async function runDev(options) {
6831
6994
  process.on("SIGINT", shutdown);
6832
6995
  process.on("SIGTERM", shutdown);
6833
6996
  try {
6834
- const { watchApp } = await import("./dist-B7fZRB8p.mjs");
6997
+ const { watchApp } = await import("./dist-CTHhFGjP.mjs");
6835
6998
  await watchApp({
6836
6999
  root,
6837
7000
  clean: false,
@@ -7031,21 +7194,9 @@ async function confirmTargetDir(targetDir) {
7031
7194
  });
7032
7195
  }
7033
7196
  //#endregion
7034
- //#region src/init/catalog-versions.ts
7035
- const INIT_CATALOG_VERSIONS = {
7036
- zod: "^4.4.3",
7037
- oxlint: "^1.66.0",
7038
- typescript: "^6.0.3",
7039
- vitest: "^4.1.7",
7040
- "@types/node": "^25.9.1"
7041
- };
7042
- const INIT_KEYSTROKE_VERSION = "^0.1.33";
7043
- //#endregion
7044
7197
  //#region src/init/copy-template.ts
7045
7198
  function renderTemplate(content, variables) {
7046
- let rendered = content.replaceAll("{{projectName}}", variables.projectName).replaceAll("{{keystrokeVersion}}", INIT_KEYSTROKE_VERSION).replaceAll("{{version}}", variables.version);
7047
- for (const [dep, version] of Object.entries(INIT_CATALOG_VERSIONS)) rendered = rendered.replaceAll(`{{catalog:${dep}}}`, version);
7048
- return rendered;
7199
+ return content.replaceAll("{{projectName}}", variables.projectName);
7049
7200
  }
7050
7201
  async function copyEntry(sourcePath, targetPath, variables) {
7051
7202
  if ((await stat(sourcePath)).isDirectory()) {
@@ -7070,8 +7221,6 @@ function resolveTemplateDir(templateName, fromModuleUrl = import.meta.url) {
7070
7221
  }
7071
7222
  //#endregion
7072
7223
  //#region src/init/project-files.ts
7073
- const PROJECT_NPMRC = `@keystrokehq:registry=https://registry.npmjs.org
7074
- `;
7075
7224
  const PROJECT_GITIGNORE = `node_modules/
7076
7225
  dist/
7077
7226
  data/
@@ -7094,39 +7243,28 @@ function buildPlaygroundPackageJson(projectName, targetDir, monorepoRoot) {
7094
7243
  dev: "keystroke dev",
7095
7244
  build: "keystroke build",
7096
7245
  start: "keystroke start",
7097
- lint: "oxlint .",
7098
- typecheck: "tsc --noEmit",
7099
- "test:unit": "vitest run --project unit",
7100
- "test:int": "vitest run --project integration"
7246
+ lint: "keystroke lint",
7247
+ typecheck: "keystroke typecheck",
7248
+ test: "keystroke test"
7101
7249
  },
7102
7250
  dependencies: {
7103
7251
  "@keystrokehq/action": linkSpec(targetDir, join(monorepoRoot, "packages/action")),
7104
7252
  "@keystrokehq/agent": linkSpec(targetDir, join(monorepoRoot, "packages/agent")),
7105
7253
  "@keystrokehq/config": linkSpec(targetDir, join(monorepoRoot, "packages/config")),
7106
7254
  "@keystrokehq/workflow": linkSpec(targetDir, join(monorepoRoot, "packages/workflow")),
7107
- zod: INIT_CATALOG_VERSIONS.zod
7255
+ zod: "latest"
7108
7256
  },
7109
7257
  devDependencies: {
7110
7258
  "@keystrokehq/cli": linkSpec(targetDir, join(monorepoRoot, "apps/cli")),
7111
- "@keystrokehq/tsconfig": linkSpec(targetDir, join(monorepoRoot, "packages/tsconfig")),
7112
- "@types/node": INIT_CATALOG_VERSIONS["@types/node"],
7113
- oxlint: INIT_CATALOG_VERSIONS.oxlint,
7114
- typescript: INIT_CATALOG_VERSIONS.typescript,
7115
- vitest: INIT_CATALOG_VERSIONS.vitest
7259
+ "@types/node": "latest",
7260
+ typescript: "latest",
7261
+ vitest: "latest"
7116
7262
  }
7117
7263
  }, null, 2)}\n`;
7118
7264
  }
7119
7265
  /** Patch hello-world scaffold for monorepo playground/ (link deps, no GitHub Packages). */
7120
7266
  async function applyPlaygroundManifest(targetDir, projectName, monorepoRoot) {
7121
7267
  await writeFile(join(targetDir, "package.json"), buildPlaygroundPackageJson(projectName, targetDir, monorepoRoot));
7122
- try {
7123
- await unlink(join(targetDir, ".npmrc"));
7124
- } catch {}
7125
- const tsconfigPath = join(targetDir, "tsconfig.json");
7126
- const tsconfig = JSON.parse(await readFile(tsconfigPath, "utf8"));
7127
- tsconfig.include = ["src", "keystroke.config.ts"];
7128
- if (tsconfig.compilerOptions) tsconfig.compilerOptions.rootDir = ".";
7129
- await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
7130
7268
  }
7131
7269
  //#endregion
7132
7270
  //#region src/skills/agents-guide-version.ts
@@ -7233,7 +7371,6 @@ async function scaffoldEmptySrcDirs(targetDir) {
7233
7371
  //#region src/init/scaffold-project-dotfiles.ts
7234
7372
  /** Write dotfiles npm/pnpm deploy omits from bundled templates. */
7235
7373
  async function scaffoldProjectDotfiles(targetDir) {
7236
- await writeFile(join(targetDir, ".npmrc"), PROJECT_NPMRC);
7237
7374
  await writeFile(join(targetDir, ".gitignore"), PROJECT_GITIGNORE);
7238
7375
  }
7239
7376
  //#endregion
@@ -7306,10 +7443,7 @@ async function runInit(options) {
7306
7443
  if (!await confirmTargetDir(targetDir)) throw new Error("Init cancelled");
7307
7444
  } else if (!options.yes) throw new Error(`Directory "${targetDir}" is not empty. Pass --yes to merge or choose an empty directory.`);
7308
7445
  }
7309
- await copyTemplate(resolveTemplateDir(options.template ?? "hello-world"), targetDir, {
7310
- projectName,
7311
- version: options.version
7312
- });
7446
+ await copyTemplate(resolveTemplateDir(options.template ?? "hello-world"), targetDir, { projectName });
7313
7447
  await scaffoldEmptySrcDirs(targetDir);
7314
7448
  if (options.noExample) {
7315
7449
  await removeExampleFiles(targetDir);
@@ -7346,15 +7480,14 @@ function registerInitCommand(program) {
7346
7480
  packageManager: options.pm,
7347
7481
  noExample: options.example === false,
7348
7482
  project,
7349
- organization: options.organization,
7350
- version: readCliVersion()
7483
+ organization: options.organization
7351
7484
  });
7352
7485
  process.stdout.write(`Created keystroke project "${result.projectName}" at ${result.targetDir}\n`);
7353
7486
  process.stdout.write("\nNext steps:\n");
7354
7487
  process.stdout.write(` cd ${result.targetDir}\n`);
7355
7488
  process.stdout.write(" keystroke auth login # once\n");
7356
7489
  if (!project) process.stdout.write(" keystroke project link --project <slug> # link this directory to a platform project\n");
7357
- process.stdout.write(" keystroke deploy # build + ship src/ to the platform\n");
7490
+ process.stdout.write(" keystroke deploy # lint + typecheck + build + ship dist/\n");
7358
7491
  } catch (error) {
7359
7492
  const message = error instanceof Error ? error.message : "Init failed";
7360
7493
  process.stderr.write(`${message}\n`);
@@ -7363,6 +7496,43 @@ function registerInitCommand(program) {
7363
7496
  });
7364
7497
  }
7365
7498
  //#endregion
7499
+ //#region src/commands/lint.ts
7500
+ function registerLintCommand(program) {
7501
+ program.command("lint").description("Lint the project with the bundled oxlint").option("--dir <path>", "Project directory", process.cwd()).allowUnknownOption(true).argument("[args...]", "Extra arguments forwarded to oxlint").action(async (args, options) => {
7502
+ const root = resolveProjectRoot(options.dir);
7503
+ process.exitCode = await runLint(root, args.length > 0 ? args : void 0);
7504
+ });
7505
+ }
7506
+ //#endregion
7507
+ //#region src/commands/test.ts
7508
+ function registerTestCommand(program) {
7509
+ program.command("test").description("Run tests with the bundled vitest (--project unit|integration)").option("--dir <path>", "Project directory", process.cwd()).allowUnknownOption(true).argument("[args...]", "Extra arguments forwarded to vitest").action(async (args, options) => {
7510
+ const root = resolveProjectRoot(options.dir);
7511
+ const code = await runToolBin({
7512
+ pkg: "vitest",
7513
+ binName: "vitest",
7514
+ args: [
7515
+ "run",
7516
+ "--root",
7517
+ root,
7518
+ "--config",
7519
+ join(resolveConfigsDir(), "vitest.config.mjs"),
7520
+ ...args
7521
+ ],
7522
+ cwd: root
7523
+ });
7524
+ process.exitCode = code;
7525
+ });
7526
+ }
7527
+ //#endregion
7528
+ //#region src/commands/typecheck.ts
7529
+ function registerTypecheckCommand(program) {
7530
+ program.command("typecheck").description("Type-check the project with the bundled TypeScript").option("--dir <path>", "Project directory", process.cwd()).action(async (options) => {
7531
+ const root = resolveProjectRoot(options.dir);
7532
+ process.exitCode = await runTypecheck(root);
7533
+ });
7534
+ }
7535
+ //#endregion
7366
7536
  //#region src/commands/organization/run-organization.ts
7367
7537
  async function runOrganizationUpdate(config, input) {
7368
7538
  await withActivePlatformClient(config, async (platform) => {
@@ -7857,7 +8027,7 @@ async function runStart(options) {
7857
8027
  const apiPort = Number(new URL(serverUrl).port || 80);
7858
8028
  const runtimeNodeModules = resolveCliRuntimeNodeModules(resolveCliRoot(import.meta.url));
7859
8029
  ensureNativeDeps(runtimeNodeModules);
7860
- const { buildApp } = await import("./dist-B7fZRB8p.mjs");
8030
+ const { buildApp } = await import("./dist-CTHhFGjP.mjs");
7861
8031
  await buildApp({
7862
8032
  root,
7863
8033
  clean: false
@@ -8407,6 +8577,9 @@ function createProgram() {
8407
8577
  registerSkillsCommand(program);
8408
8578
  registerSkillCommand(program);
8409
8579
  registerBuildCommand(program);
8580
+ registerLintCommand(program);
8581
+ registerTypecheckCommand(program);
8582
+ registerTestCommand(program);
8410
8583
  registerDeployCommand(program);
8411
8584
  registerPullCommand(program);
8412
8585
  registerDevCommand(program);
@@ -8419,7 +8592,7 @@ function createProgram() {
8419
8592
  return program;
8420
8593
  }
8421
8594
  async function runCli(argv) {
8422
- const { maybeAutoUpdate } = await import("./maybe-auto-update-4tu8zRcS.mjs");
8595
+ const { maybeAutoUpdate } = await import("./maybe-auto-update-DPhUOdEF.mjs");
8423
8596
  await maybeAutoUpdate(argv);
8424
8597
  createProgram().parse(argv);
8425
8598
  }