@tdk-landscape/tdk-cli-core 1.3.54 → 1.3.56

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/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ Notable changes to the `tdk` CLI. Versions match [npm](https://www.npmjs.com/pac
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ - `tdk project` adds `.env`, `.tdk/.tdk-out/`, `.tdk/.project-id` and `node_modules/` to `.gitignore`. `.env` holds a generated database password and was easy to commit by accident.
8
+ - `tdk doctor` checks that host ports 80, 443 and 5432 are free and names what holds them (usually a local Postgres). `tdk up` prints the same warning before starting Tilt.
9
+ - `tdk project` no longer tells you to edit `.env` first: the defaults work, and the Verdaccio variables are marked as belonging to the paid registry.
10
+ ## 1.3.55 (2026-09-27)
11
+
12
+ - Dropped the `ora` dependency (only `tdk upgrade` used it) in favor of a small built-in spinner: 50 installed packages instead of 61, and no more duplicate versions of cli-cursor, restore-cursor, onetime and signal-exit.
13
+ - `tdk doctor` outside a project checks only Docker, Compose and Tilt, and reports "This machine is ready for TDK". Before, running it right after installing (as the installer suggests) failed with "Master configs missing … Environment not ready".
14
+
15
+ ## 1.3.54 (2026-09-27)
16
+
7
17
  - The npm package ships only what the CLI needs at runtime: 294 files and 458 kB, down from 678 files and 888 kB. Repo tooling, tests, source maps, CI config and the openspec docs are no longer included.
8
18
 
9
19
  ## 1.3.53 (2026-09-27)
package/README.md CHANGED
@@ -26,7 +26,7 @@ tdk up shop # run it with hot reload
26
26
 
27
27
  ![tdk scaffolding a backend and a frontend, then listing the stack](docs/demo.svg)
28
28
 
29
- **Requirements:** Docker (Desktop, OrbStack or Colima; Engine 25+, Compose 2.20+), [Tilt](https://docs.tilt.dev/install.html), [Bun](https://bun.sh) for the generated services, and Node.js 22.12+ for the CLI. macOS and Linux are supported. Windows is untested (WSL2 may work). Run `tdk doctor` to check all of it.
29
+ **Requirements:** Docker (Desktop, OrbStack or Colima; Engine 25+, Compose 2.20+), [Tilt](https://docs.tilt.dev/install.html), [Bun](https://bun.sh) for the generated services, and Node.js 22.12+ for the CLI. Ports 80, 443 and 5432 must be free (a local Postgres is the usual conflict). macOS and Linux are supported. Windows is untested (WSL2 may work). Run `tdk doctor` to check all of it.
30
30
 
31
31
  This is the core monorepo for TDK: the `tdk` CLI, the Starlark-based Tilt orchestration engine that powers it, and the discovery system that turns a directory of services into a running local landscape.
32
32
 
@@ -144,6 +144,7 @@ TDK has no telemetry or analytics. The CLI only goes online when you ask it to:
144
144
  - `tdk upgrade` checks the latest release on GitHub.
145
145
  - With `TDK_LICENSE_KEY` set, `tdk project` and `tdk up` download the paid bundle from `tdk-extension-dist.oranguman.workers.dev` and re-check the key every 12 hours. Without a key, nothing is sent.
146
146
  - Docker and Tilt pull images and packages as they normally would.
147
+ - Tilt, which TDK runs, has its own anonymous usage analytics. Turn them off with `tilt analytics opt out`.
147
148
 
148
149
  ## FAQ
149
150
 
@@ -172,7 +173,7 @@ make pre-commit-run # run pre-commit hooks on all files
172
173
  tdk doctor
173
174
  ```
174
175
 
175
- Verifies Docker, Bun, Tilt, required ports, and master config files are all in place before you run `tdk up`.
176
+ Checks Docker, Compose and Tilt. Inside a project it also checks the generated configs, `.env`, service scripts and that the ingress ports are free, before you run `tdk up`.
176
177
 
177
178
  ## Community
178
179
 
@@ -4,7 +4,7 @@ import { dirname, join, normalize } from "node:path";
4
4
  import chalk from "chalk";
5
5
  import { Command } from "commander";
6
6
  import { MASTER_CONFIG_FILES, QUICKSTART_DOCS_URL, REQUIRED_PACKAGE_SCRIPTS, } from "../utils/constants.js";
7
- import { checkIngressPorts, checkPrivateNpmRegistry, checkTiltResourceHealth, } from "../utils/doctor-runtime.js";
7
+ import { checkHostPorts, checkIngressPorts, checkPrivateNpmRegistry, checkTiltResourceHealth, } from "../utils/doctor-runtime.js";
8
8
  import { validateEnvFile } from "../utils/env-validator.js";
9
9
  import { formatCount } from "../utils/formatting.js";
10
10
  import { findProjectRoot } from "../utils/paths.js";
@@ -681,11 +681,13 @@ export const doctorCommand = new Command("doctor")
681
681
  console.log(`${chalk.red("✗")} --ping-timeout must be a positive number of milliseconds`);
682
682
  process.exit(1);
683
683
  }
684
- const checks = [
684
+ const machineChecks = [
685
685
  checkDockerRuntime,
686
686
  checkTilt,
687
687
  checkDockerCompose,
688
688
  checkDockerVersions,
689
+ ];
690
+ const projectChecks = [
689
691
  checkMasterConfigs,
690
692
  checkGeneratedProjectRuntimeAssets,
691
693
  checkStarlarkLoadExports,
@@ -695,6 +697,8 @@ export const doctorCommand = new Command("doctor")
695
697
  checkEnvironmentVariables,
696
698
  // Preflight: catch "port 80 already allocated" BEFORE claiming ready.
697
699
  checkIngressPorts,
700
+ // Preflight: a local Postgres or web server on 5432/80/443.
701
+ () => checkHostPorts(),
698
702
  // Preflight: Verdaccio down causes ImageBuild bun install ConnectionRefused.
699
703
  checkPrivateNpmRegistry,
700
704
  // Runtime checks: skip gracefully if the stack isn't started yet.
@@ -704,8 +708,13 @@ export const doctorCommand = new Command("doctor")
704
708
  ];
705
709
  // Runs last: needs routable services (and working Traefik) to mean anything.
706
710
  if (options.ping) {
707
- checks.push(() => checkServiceHealth(pingTimeout));
711
+ projectChecks.push(() => checkServiceHealth(pingTimeout));
708
712
  }
713
+ // Right after installing, people run `tdk doctor` before they have a
714
+ // project. Only the machine checks mean anything there; the project checks
715
+ // would all fail with "run tdk project".
716
+ const inProject = Boolean(findProjectRoot());
717
+ const checks = inProject ? [...machineChecks, ...projectChecks] : machineChecks;
709
718
  let allPassed = true;
710
719
  for (const checkFn of checks) {
711
720
  const result = await checkFn();
@@ -728,7 +737,18 @@ export const doctorCommand = new Command("doctor")
728
737
  }
729
738
  }
730
739
  console.log("");
731
- if (allPassed) {
740
+ if (allPassed && !inProject) {
741
+ console.log(`${chalk.gray("○")} ${chalk.gray("Not in a TDK project, so project checks were skipped")}`);
742
+ console.log("");
743
+ console.log(`${chalk.green(chalk.bold("✓"))} This machine is ready for TDK`);
744
+ console.log("");
745
+ console.log("Next steps:");
746
+ console.log(" 1. mkdir my-app && cd my-app");
747
+ console.log(" 2. tdk project --yes");
748
+ console.log(" 3. tdk resource api --type backend --stack my-app");
749
+ console.log(" 4. tdk up my-app");
750
+ }
751
+ else if (allPassed) {
732
752
  console.log(`${chalk.green(chalk.bold("✓"))} Environment ready for TDK`);
733
753
  console.log("");
734
754
  console.log("Next steps:");
@@ -8,7 +8,7 @@ import { generateMasterConfigs, readProjectConfig } from "../generator/template-
8
8
  import { MASTER_CONFIG_FILES } from "../utils/constants.js";
9
9
  import { ensureEnvFile, validateEnvFile } from "../utils/env-validator.js";
10
10
  import { errorFactories, runCommand, showErrorAndExit } from "../utils/errors.js";
11
- import { ensureDirectory, writeJsonFile } from "../utils/file-helpers.js";
11
+ import { ensureDirectory, ensureGitignore, writeJsonFile } from "../utils/file-helpers.js";
12
12
  import { showCancelled, showCommandHeader, showDetail, showStep, showSuccess, } from "../utils/formatting.js";
13
13
  import { findProjectRoot } from "../utils/paths.js";
14
14
  import { PROJECT_FEATURES } from "../utils/project-features.js";
@@ -218,6 +218,10 @@ export const projectCommand = new Command("project")
218
218
  }
219
219
  showStep("\n📋 Regenerating master configuration files...\n");
220
220
  await generateMasterConfigs(projectRoot);
221
+ const ignored = ensureGitignore(projectRoot);
222
+ if (ignored.length > 0) {
223
+ showSuccess(`Added to .gitignore: ${ignored.join(", ")}`);
224
+ }
221
225
  console.log(chalk.green("\n✅ Project configuration regenerated!"));
222
226
  showDetail("\nGenerated in .tdk/.tdk-out/:", 0);
223
227
  for (const file of MASTER_CONFIG_FILES) {
@@ -354,8 +358,7 @@ export const projectCommand = new Command("project")
354
358
  showStep("\n🔧 Setting up environment variables...\n");
355
359
  const envCreated = ensureEnvFile(projectRoot);
356
360
  if (envCreated) {
357
- showSuccess("Created: .env (with required variables)");
358
- showDetail("→ Edit .env to set VERDACCIO_URL_DOCKER, TILT_ENV, etc.");
361
+ showSuccess("Created: .env (the defaults work as-is)");
359
362
  }
360
363
  else {
361
364
  showSuccess("Found: .env (environment already configured)");
@@ -368,6 +371,10 @@ export const projectCommand = new Command("project")
368
371
  }
369
372
  showDetail("→ Edit .env and fill in these values before running `tdk up`", 1);
370
373
  }
374
+ const ignored = ensureGitignore(projectRoot);
375
+ if (ignored.length > 0) {
376
+ showSuccess(`Added to .gitignore: ${ignored.join(", ")}`);
377
+ }
371
378
  console.log(chalk.green("\n✅ Project configuration complete!"));
372
379
  showDetail("\nGenerated files in .tdk/.tdk-out/:", 0);
373
380
  for (const file of MASTER_CONFIG_FILES) {
@@ -378,9 +385,9 @@ export const projectCommand = new Command("project")
378
385
  showDetail("\nSource file:", 0);
379
386
  showDetail("- .tdk/project.json (edit this to change project structure)");
380
387
  showDetail("\nNext steps:", 0);
381
- showDetail("1. Edit .env to set required values (VERDACCIO_URL_DOCKER, TILT_ENV)");
382
- showDetail("2. Run `tdk config regenerate` after editing .tdk/project.json");
383
- showDetail("3. Run `tdk up` to start development");
388
+ showDetail("1. tdk resource api --type backend --stack app # scaffold a service");
389
+ showDetail("2. tdk up app # start it");
390
+ showDetail("\nAfter editing .tdk/project.json, run `tdk config regenerate`.", 0);
384
391
  });
385
392
  });
386
393
  //# sourceMappingURL=project.js.map
@@ -3,6 +3,7 @@ import chalk from "chalk";
3
3
  import { Command } from "commander";
4
4
  import { ensureProjectRuntimeAssets } from "../generator/template-engine.js";
5
5
  import { handleDryRun } from "../utils/command-helpers.js";
6
+ import { checkHostPorts } from "../utils/doctor-runtime.js";
6
7
  import { errorFactories, handleTiltFailure, withTiltCheck } from "../utils/errors.js";
7
8
  import { formatCount } from "../utils/formatting.js";
8
9
  import { findProjectRoot } from "../utils/paths.js";
@@ -84,6 +85,14 @@ export const upCommand = new Command("up")
84
85
  if (handleDryRun(options, "not starting services", dryRunCommand)) {
85
86
  return;
86
87
  }
88
+ // Warn rather than block: a stale local Postgres on 5432 makes Tilt fail
89
+ // halfway through startup with a bind error that's hard to read.
90
+ const hostPorts = await checkHostPorts();
91
+ if (!hostPorts.didPass && !options.quiet) {
92
+ console.log(chalk.yellow(`\n⚠️ ${hostPorts.message}`));
93
+ if (hostPorts.fix)
94
+ console.log(chalk.gray(` ${hostPorts.fix}\n`));
95
+ }
87
96
  if (options.force && !options.quiet) {
88
97
  console.log(chalk.yellow("Force flag set - killing any existing Tilt processes..."));
89
98
  execSync("killall tilt 2>/dev/null || true", { shell: "/bin/sh", stdio: "pipe" });
@@ -5,11 +5,11 @@ import { dirname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import chalk from "chalk";
7
7
  import { Command } from "commander";
8
- import ora from "ora";
9
8
  import { getErrorMessage, logVerbose, showErrorAndExit } from "../utils/errors.js";
10
9
  import { showCancelled } from "../utils/formatting.js";
11
10
  import { getPackageVersion } from "../utils/paths.js";
12
11
  import { promptConfirm } from "../utils/prompt.js";
12
+ import { startSpinner } from "../utils/spinner.js";
13
13
  function isStandaloneBinary(tdkPath) {
14
14
  try {
15
15
  const fileInfo = execSync(`file -b ${JSON.stringify(tdkPath)}`, { encoding: "utf-8" });
@@ -138,7 +138,7 @@ export async function upgradeViaBinary(tdkPath, release) {
138
138
  console.log(chalk.cyan(` chmod +x ${tdkPath}`));
139
139
  return false;
140
140
  }
141
- const spinner = ora(`Downloading ${release.assetName} (${release.tag})...`).start();
141
+ const spinner = startSpinner(`Downloading ${release.assetName} (${release.tag})...`);
142
142
  // Download to /tmp first (both the binary and the engine bundle below) so a
143
143
  // failed network step can't leave a half-written binary at tdkPath.
144
144
  const tmpPath = `/tmp/tdk-upgrade-${release.assetName}`;
@@ -204,7 +204,7 @@ function getCurrentVersion() {
204
204
  }
205
205
  }
206
206
  async function getLatestVersion() {
207
- const spinner = ora("Checking for latest version...").start();
207
+ const spinner = startSpinner("Checking for latest version...");
208
208
  try {
209
209
  const result = execSync("npm view @tdk-landscape/tdk-cli-core version", {
210
210
  encoding: "utf-8",
@@ -224,7 +224,7 @@ async function getLatestVersion() {
224
224
  }
225
225
  }
226
226
  async function upgradeViaNpm() {
227
- const spinner = ora("Upgrading via npm...").start();
227
+ const spinner = startSpinner("Upgrading via npm...");
228
228
  try {
229
229
  execSync("npm install -g @tdk-landscape/tdk-cli-core@latest", {
230
230
  stdio: "inherit",
@@ -252,7 +252,7 @@ async function upgradeViaNpm() {
252
252
  }
253
253
  }
254
254
  async function upgradeViaBun() {
255
- const spinner = ora("Upgrading via bun...").start();
255
+ const spinner = startSpinner("Upgrading via bun...");
256
256
  try {
257
257
  execSync("bun install -g @tdk-landscape/tdk-cli-core@latest", {
258
258
  stdio: "inherit",
@@ -280,7 +280,7 @@ async function upgradeViaBun() {
280
280
  }
281
281
  }
282
282
  async function upgradeViaGit(path) {
283
- const spinner = ora("Pulling latest changes from git...").start();
283
+ const spinner = startSpinner("Pulling latest changes from git...");
284
284
  try {
285
285
  execSync("git rev-parse --git-dir", {
286
286
  cwd: path,
@@ -492,7 +492,7 @@ export const upgradeCommand = new Command("upgrade")
492
492
  process.exit(1);
493
493
  }
494
494
  console.log();
495
- const verifySpinner = ora("Verifying upgrade...").start();
495
+ const verifySpinner = startSpinner("Verifying upgrade...");
496
496
  try {
497
497
  const newVersion = execSync("tdk version", { encoding: "utf-8" }).trim();
498
498
  verifySpinner.succeed(`Verified: now running ${chalk.green(newVersion)}`);
@@ -1,5 +1,6 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
+ import { createServer } from "node:net";
3
4
  import { join } from "node:path";
4
5
  import { formatCount } from "./formatting.js";
5
6
  import { findProjectRoot } from "./paths.js";
@@ -322,6 +323,90 @@ export function checkIngressPorts(exec = execSync, projectName = getProjectName(
322
323
  fix: `Stop the foreign container(s), e.g. \`docker stop ${foreign[0]?.name}\`, or shut down the other TDK/Tilt project using that Traefik. Then re-run \`tdk up\`.`,
323
324
  };
324
325
  }
326
+ /** Host ports the generated stack publishes: Traefik (80, 443) and Postgres (5432). */
327
+ export const HOST_PORTS = { 80: "HTTP", 443: "HTTPS", 5432: "Postgres" };
328
+ function probeAddress(port, host) {
329
+ return new Promise((resolve) => {
330
+ const server = createServer();
331
+ server.once("error", (err) =>
332
+ // EACCES: ports below 1024 need root on Linux, so we can't tell.
333
+ resolve(err.code === "EADDRINUSE" ? "in-use" : "unknown"));
334
+ server.once("listening", () => server.close(() => resolve("free")));
335
+ server.listen(port, host);
336
+ });
337
+ }
338
+ /**
339
+ * Probes both the wildcard and loopback address: a Homebrew Postgres listens on
340
+ * 127.0.0.1 only, which a wildcard bind alone doesn't detect.
341
+ */
342
+ export async function probeHostPort(port) {
343
+ const results = await Promise.all([
344
+ probeAddress(port, "0.0.0.0"),
345
+ probeAddress(port, "127.0.0.1"),
346
+ ]);
347
+ if (results.includes("in-use"))
348
+ return "in-use";
349
+ return results.includes("free") ? "free" : "unknown";
350
+ }
351
+ /**
352
+ * Catches host ports taken by something other than this project's containers,
353
+ * most often a local Postgres on 5432 or a web server on 80. Docker-held 80/443
354
+ * are reported by checkIngressPorts, so only 5432 is checked against other
355
+ * containers here.
356
+ */
357
+ export async function checkHostPorts(exec = execSync, projectName = getProjectName(), probe = probeHostPort) {
358
+ const ports = Object.keys(HOST_PORTS).map(Number);
359
+ const inUse = [];
360
+ for (const port of ports) {
361
+ if ((await probe(port)) === "in-use")
362
+ inUse.push(port);
363
+ }
364
+ if (inUse.length === 0) {
365
+ return {
366
+ name: "Host Ports",
367
+ didPass: true,
368
+ message: `Host ports ${ports.join(", ")} are free`,
369
+ };
370
+ }
371
+ let dockerPs = "";
372
+ try {
373
+ dockerPs = exec("docker ps --format '{{.Names}}\\t{{.Ports}}'", {
374
+ stdio: "pipe",
375
+ encoding: "utf-8",
376
+ timeout: EXEC_TIMEOUT_MS,
377
+ });
378
+ }
379
+ catch {
380
+ // Can't attribute ports without Docker; treat them as held by the host.
381
+ }
382
+ const holders = parsePublishedPortHolders(dockerPs, inUse);
383
+ const prefix = toComposeProjectPrefix(projectName).toLowerCase();
384
+ const isOwn = (name) => {
385
+ const lower = name.toLowerCase();
386
+ return lower.startsWith(`${prefix}_`) || lower.startsWith(`${prefix}-`);
387
+ };
388
+ const problems = [];
389
+ for (const port of inUse) {
390
+ const holder = holders.find((h) => h.publishedPorts.includes(port));
391
+ if (!holder) {
392
+ problems.push(`${port} (${HOST_PORTS[port]}) is used by a program on this machine`);
393
+ }
394
+ else if (port === 5432 && !isOwn(holder.name)) {
395
+ problems.push(`${port} (${HOST_PORTS[port]}) is published by container ${holder.name}`);
396
+ }
397
+ }
398
+ if (problems.length === 0) {
399
+ return { name: "Host Ports", didPass: true, message: "Host ports are held by this project" };
400
+ }
401
+ const first = inUse.find((port) => problems.some((p) => p.startsWith(`${port} `))) ?? inUse[0];
402
+ return {
403
+ name: "Host Ports",
404
+ didPass: false,
405
+ message: `Ports TDK needs are taken:\n ${problems.join("\n ")}`,
406
+ fix: `Find what holds a port with \`lsof -nP -iTCP:${first} -sTCP:LISTEN\` and stop it ` +
407
+ "(for a local Postgres: `brew services stop postgresql` or quit Postgres.app), then run `tdk up`.",
408
+ };
409
+ }
325
410
  /**
326
411
  * When a Tilt session is active, surface resource update errors (Traefik port
327
412
  * binds, image builds, etc.) instead of claiming the environment is ready
@@ -4,14 +4,14 @@ import { join } from "node:path";
4
4
  const REQUIRED_ENV_VARS = [
5
5
  {
6
6
  name: "VERDACCIO_URL_DOCKER",
7
- description: "Docker-internal URL for npm registry",
7
+ description: "Docker-internal URL of the private npm registry (Verdaccio, a paid feature)",
8
8
  required: true,
9
9
  default: "http://verdaccio:4873",
10
10
  example: "http://verdaccio:4873",
11
11
  },
12
12
  {
13
13
  name: "VERDACCIO_URL",
14
- description: "Local development URL for npm registry",
14
+ description: "Local URL of the private npm registry (Verdaccio, a paid feature)",
15
15
  required: false,
16
16
  default: "http://localhost:4873",
17
17
  },
@@ -44,8 +44,8 @@ function generateDbPassword() {
44
44
  export function generateEnvFile(_projectRoot) {
45
45
  const lines = [
46
46
  "# 🔧 TDK Environment Configuration",
47
- "# Auto-generated by TDK CLI - edit as needed",
48
- "# These variables are required for services to run",
47
+ "# Generated by `tdk project`. The defaults work as-is; edit only to change them.",
48
+ "# Keep this file out of git (it holds a generated database password).",
49
49
  "#",
50
50
  "# After editing, run: tdk config regenerate && tdk up",
51
51
  "",
@@ -53,7 +53,7 @@ export function generateEnvFile(_projectRoot) {
53
53
  for (const envVar of REQUIRED_ENV_VARS) {
54
54
  lines.push(`# ${envVar.description}`);
55
55
  if (envVar.required) {
56
- lines.push(`# ⚠️ REQUIRED - set this or services will fail`);
56
+ lines.push("# Required (the value below is a working default)");
57
57
  }
58
58
  if (envVar.example) {
59
59
  lines.push(`# Example: ${envVar.example}`);
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import chalk from "chalk";
4
4
  export function writeFilesWithProgress(basePath, tasks, onProgress) {
@@ -42,4 +42,25 @@ export function ensureDirectory(dirPath) {
42
42
  mkdirSync(dirPath, { recursive: true });
43
43
  }
44
44
  }
45
+ /** Generated files that must never be committed: .env holds a generated DB password. */
46
+ const GITIGNORE_ENTRIES = [".env", ".tdk/.tdk-out/", ".tdk/.project-id", "node_modules/"];
47
+ /**
48
+ * Appends the TDK entries missing from the project's .gitignore (creating it
49
+ * if needed), so the first `git add .` doesn't commit .env or generated
50
+ * output. Returns the entries it added.
51
+ */
52
+ export function ensureGitignore(projectRoot) {
53
+ const gitignorePath = resolve(projectRoot, ".gitignore");
54
+ const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
55
+ const lines = new Set(existing.split("\n").map((line) => line.trim().replace(/\/$/, "")));
56
+ const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.has(entry.replace(/\/$/, "")));
57
+ if (missing.length === 0)
58
+ return [];
59
+ const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
60
+ const header = existing
61
+ ? "\n# TDK (generated files and secrets)\n"
62
+ : "# TDK (generated files and secrets)\n";
63
+ appendFileSync(gitignorePath, `${prefix}${header}${missing.join("\n")}\n`);
64
+ return missing;
65
+ }
45
66
  //# sourceMappingURL=file-helpers.js.map
@@ -0,0 +1,39 @@
1
+ import chalk from "chalk";
2
+ const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
3
+ export function startSpinner(initialText) {
4
+ const stream = process.stderr;
5
+ const animate = stream.isTTY === true;
6
+ let frame = 0;
7
+ let text = initialText;
8
+ let timer;
9
+ const render = () => stream.write(`\r\x1b[2K${chalk.cyan(FRAMES[frame])} ${text}`);
10
+ if (animate) {
11
+ render();
12
+ timer = setInterval(() => {
13
+ frame = (frame + 1) % FRAMES.length;
14
+ render();
15
+ }, 80);
16
+ }
17
+ else {
18
+ stream.write(`- ${text}\n`);
19
+ }
20
+ const finish = (symbol, message) => {
21
+ if (timer)
22
+ clearInterval(timer);
23
+ stream.write(`${animate ? "\r\x1b[2K" : ""}${symbol} ${message ?? text}\n`);
24
+ };
25
+ return {
26
+ get text() {
27
+ return text;
28
+ },
29
+ set text(value) {
30
+ text = value;
31
+ if (!animate)
32
+ stream.write(`- ${text}\n`);
33
+ },
34
+ succeed: (message) => finish(chalk.green("✔"), message),
35
+ fail: (message) => finish(chalk.red("✖"), message),
36
+ warn: (message) => finish(chalk.yellow("⚠"), message),
37
+ };
38
+ }
39
+ //# sourceMappingURL=spinner.js.map
package/cli/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tdk-cli-internal",
3
3
  "private": true,
4
- "version": "1.3.54",
4
+ "version": "1.3.56",
5
5
  "description": "TDK CLI - Tilt Development Kit command line interface",
6
6
  "keywords": [
7
7
  "tdk",
@@ -58,7 +58,6 @@
58
58
  "handlebars": "^4.7.8",
59
59
  "ink": "^7.1.1",
60
60
  "ink-select-input": "^6.2.0",
61
- "ora": "^9.4.1",
62
61
  "react": "^19.3.0"
63
62
  },
64
63
  "devDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.54",
3
+ "version": "1.3.56",
4
4
  "description": "Run 100 microservices on a 16 GB laptop without Kubernetes. Scaffold services and run them locally with hot reload, built on Tilt.",
5
5
  "homepage": "https://tdk-landscape.github.io/tdk-website",
6
6
  "repository": {
@@ -71,7 +71,6 @@
71
71
  "handlebars": "^4.7.8",
72
72
  "ink": "^7.1.1",
73
73
  "ink-select-input": "^6.2.0",
74
- "ora": "^9.4.1",
75
74
  "react": "^19.3.0"
76
75
  },
77
76
  "devDependencies": {