@flisk-sh/flisk 1.4.2 → 1.4.5

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +119 -43
  3. package/cli/dist/backend-languages/bun.js +5 -0
  4. package/cli/dist/backend-languages/go.js +3 -1
  5. package/cli/dist/cli.js +9 -0
  6. package/cli/dist/commands/completion.js +8 -1
  7. package/cli/dist/commands/config.js +130 -55
  8. package/cli/dist/commands/doctor.js +16 -15
  9. package/cli/dist/commands/logs.js +1 -0
  10. package/cli/dist/commands/project.js +1 -0
  11. package/cli/dist/commands/resource.js +39 -11
  12. package/cli/dist/commands/status.js +18 -9
  13. package/cli/dist/commands/up.js +102 -17
  14. package/cli/dist/frontend-frameworks/next.js +197 -0
  15. package/cli/dist/frontend-frameworks/react.js +81 -12
  16. package/cli/dist/frontend-frameworks/registry.js +5 -4
  17. package/cli/dist/frontend-frameworks/vue.js +82 -12
  18. package/cli/dist/generator/resource-templates.js +2 -4
  19. package/cli/dist/generator/template-engine.js +5 -3
  20. package/cli/dist/utils/cold-preflight.js +3 -2
  21. package/cli/dist/utils/config-explain.js +197 -0
  22. package/cli/dist/utils/demo-reset.js +22 -0
  23. package/cli/dist/utils/discovery-paths.js +7 -1
  24. package/cli/dist/utils/host-port-plan.js +8 -3
  25. package/cli/dist/utils/port-conflict-fix.js +16 -14
  26. package/cli/dist/utils/port-occupant.js +35 -0
  27. package/cli/dist/utils/project-features.js +7 -16
  28. package/cli/dist/utils/project-templates.js +8 -8
  29. package/cli/dist/utils/resource-features.js +5 -5
  30. package/cli/dist/utils/service-manifest.js +1 -0
  31. package/cli/dist/utils/service-urls.js +11 -0
  32. package/cli/dist/utils/startup-report.js +4 -3
  33. package/cli/dist/utils/tar.js +33 -28
  34. package/cli/dist/utils/tilt-process.js +4 -3
  35. package/cli/dist/utils/windows-doctor.js +18 -15
  36. package/cli/dist-bundle/{chunk-IGN5UC3P.js → chunk-4J2FLFUA.js} +14 -7
  37. package/cli/dist-bundle/{chunk-ETKUVKJ2.js → chunk-BMHPPX2Q.js} +10 -10
  38. package/cli/dist-bundle/chunk-BP2M4OJ4.js +2 -0
  39. package/cli/dist-bundle/{chunk-53L2JN7G.js → chunk-CGTWXWBU.js} +1 -1
  40. package/cli/dist-bundle/chunk-GPUJ55MI.js +3 -0
  41. package/cli/dist-bundle/{chunk-5QBYM33Q.js → chunk-LUUJ4JB7.js} +1 -1
  42. package/cli/dist-bundle/chunk-PEZQEZVV.js +17 -0
  43. package/cli/dist-bundle/{chunk-MWOVYIBB.js → chunk-SFOFTVYM.js} +5 -5
  44. package/cli/dist-bundle/{chunk-3XODDLRJ.js → chunk-TIYTGN5R.js} +1 -1
  45. package/cli/dist-bundle/{chunk-YNCBBJ4V.js → chunk-U42XZWXB.js} +1 -1
  46. package/cli/dist-bundle/chunk-ULMQVD7J.js +122 -0
  47. package/cli/dist-bundle/chunk-V36PT2HF.js +24 -0
  48. package/cli/dist-bundle/{chunk-I7TGIK5N.js → chunk-VMVTECCK.js} +1 -1
  49. package/cli/dist-bundle/{chunk-DU2BN46C.js → chunk-Z5QEE4SW.js} +1 -1
  50. package/cli/dist-bundle/cli.js +607 -375
  51. package/cli/dist-bundle/cold-preflight-3BNDOLGS.js +2 -0
  52. package/cli/dist-bundle/{demo-stage-OHNTP2UJ.js → demo-stage-G4W23BXW.js} +1 -1
  53. package/cli/dist-bundle/{extension-fetch-VEFSCG4B.js → extension-fetch-KIPYDIRM.js} +1 -1
  54. package/cli/dist-bundle/{open-XROJ6YEY.js → open-HQFT6WDC.js} +1 -1
  55. package/cli/dist-bundle/project-JZO2CPZZ.js +2 -0
  56. package/cli/dist-bundle/{project-templates-EYSQG2EO.js → project-templates-IMJ3OX5I.js} +1 -1
  57. package/cli/dist-bundle/{services-BIMF6MVU.js → services-GLFKZBBZ.js} +1 -1
  58. package/cli/dist-bundle/{tilt-port-owner-ZY5M2JC4.js → tilt-port-owner-PJN4MPYE.js} +1 -1
  59. package/cli/package.json +1 -1
  60. package/package.json +1 -1
  61. package/runtime/engine/topologies/platform/docker/compose/compose.star +40 -4
  62. package/runtime/engine/topologies/platform/docker/dockerfile/language_dockerfile.star +6 -0
  63. package/runtime/engine/topologies/platform/docker/dockerfile/next_dockerfile.star +83 -0
  64. package/runtime/engine/topologies/platform/docker/index.star +4 -0
  65. package/runtime/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +7 -0
  66. package/runtime/engine/topologies/platform/docker/networking/traefik.star +85 -46
  67. package/runtime/engine/topologies/tilt/common/utils_output.star +1 -0
  68. package/runtime/engine/topologies/tilt/generators/validators.star +1 -1
  69. package/runtime/engine/topologies/tilt/generators/vite/frontend.star +2 -2
  70. package/runtime/engine/topologies/tilt/generators/vite/generators.star +3 -0
  71. package/runtime/engine/topologies/tilt/manifest/constants.star +3 -0
  72. package/runtime/engine/topologies/tilt/manifest/parser.star +9 -3
  73. package/runtime/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +8 -3
  74. package/runtime/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +50 -24
  75. package/runtime/engine/topologies/tilt/resources/orchestrator/generators/env.star +11 -2
  76. package/runtime/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +23 -9
  77. package/cli/dist-bundle/chunk-43XWL2PB.js +0 -61
  78. package/cli/dist-bundle/chunk-5F7YP5IR.js +0 -17
  79. package/cli/dist-bundle/chunk-K6SOCO6V.js +0 -3
  80. package/cli/dist-bundle/chunk-YHYRGWUH.js +0 -24
  81. package/cli/dist-bundle/chunk-YL56J2WX.js +0 -2
  82. package/cli/dist-bundle/cold-preflight-ZOPR7PWJ.js +0 -2
  83. package/cli/dist-bundle/project-7PTIOHGF.js +0 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Notable changes to the `flisk` CLI. Versions match [npm](https://www.npmjs.com/package/@flisk-sh/flisk?activeTab=versions) and the [binary releases](https://github.com/flisk-sh/releases/releases).
4
4
 
5
+ ## 1.4.3 (2026-10-25)
6
+
7
+ - `flisk init` is now an alias of `flisk project`. It accepts the same template names and flags.
8
+
5
9
  ## 1.3.195 (2026-10-21)
6
10
 
7
11
  - `flisk demo` and `flisk restaurant` now clone the demo template into a fixed directory (`~/.flisk/flisk-demo/`) instead of creating `tdk-restaurant-example-N` directories in the current workspace. Previous runs are cleaned up automatically. The `restaurant` template still creates a named directory in the current folder when used explicitly.
package/README.md CHANGED
@@ -81,7 +81,11 @@ Stop my Flisk stack with flisk down and confirm nothing is left running.
81
81
  <details>
82
82
  <summary>Connect your agent to Flisk as an MCP server</summary>
83
83
 
84
- Add this to your agent's MCP settings:
84
+ Install the CLI, then add the Flisk MCP server to your agent's settings:
85
+
86
+ ```bash
87
+ npm install -g @flisk-sh/flisk
88
+ ```
85
89
 
86
90
  ```json
87
91
  {
@@ -223,12 +227,9 @@ Fastest way (recommended): open the [Flisk starter](https://github.com/flisk-sh/
223
227
 
224
228
  </details>
225
229
 
226
- ### ⚡ A running stack in about 14 seconds
230
+ ### ⚡ A one-backend stack is healthy in about 14 seconds
227
231
 
228
- On a one-backend quickstart with warm image layers, `flisk up` reaches a healthy API in 12.8 to 13.8 seconds ([timing notes](docs/benchmarks/quickstart-timing.md)). An 8-service stack settles in 32 to 42 seconds warm and about 4.5 minutes on its first cold build ([benchmark](docs/benchmarks/results/tdk-up-warm-start-2026-10-11/summary.md)). No vendor lock-in and no hand-written plumbing. Flisk works with:
229
- * **Runtimes & Frameworks:** Bun, Node, Python, Go, Rust, React, Vue, Svelte, Elysia, Fastify, NestJS
230
- * **Databases & Tooling:** Prisma, Drizzle, Atlas, Dbmate
231
- * **Messaging & Gateway:** NATS, Traefik
232
+ On a one-backend quickstart with warm image layers, `flisk up` reaches a healthy API in 12.8 to 13.8 seconds ([timing notes](docs/benchmarks/quickstart-timing.md)). An 8-service stack settles in 32 to 42 seconds warm and about 4.5 minutes on its first cold build ([benchmark](docs/benchmarks/results/tdk-up-warm-start-2026-10-11/summary.md)). No vendor lock-in and no hand-written plumbing.
232
233
 
233
234
  ### 🤖 Run your AI agents next to your services
234
235
 
@@ -311,6 +312,12 @@ See [how `flisk up` works](docs/how-flisk-up-works.md) for the full startup sequ
311
312
  | Catch config drift | Compares generated files with what Flisk last wrote | `flisk config verify` |
312
313
  | Keep Flisk current | Upgrades the CLI in place | `flisk upgrade` |
313
314
 
315
+ Flisk works with:
316
+
317
+ * **Runtimes & Frameworks:** Bun, Node, Python, Go, Rust, React, Vue, Svelte, Elysia, Fastify, NestJS
318
+ * **Databases & Tooling:** Prisma, Drizzle, Atlas, Dbmate
319
+ * **Messaging & Gateway:** NATS, Traefik
320
+
314
321
  ## Who uses Flisk
315
322
 
316
323
  Teams that run `flisk up` on their own code (listed with their consent in [ADOPTERS.md](docs/project/ADOPTERS.md)):
@@ -326,67 +333,134 @@ If Flisk saves you time, a ⭐ on [this repo](https://github.com/flisk-sh/flisk)
326
333
 
327
334
  ## Quick start
328
335
 
329
- There are two ways to get started. Both end with `flisk up <stack>`.
336
+ Get a running local stack in **3 commands**. Works on macOS, Linux, and Windows (via WSL2).
330
337
 
331
- | | Guided scaffolder | Core CLI (manual) |
332
- | --- | --- | --- |
333
- | Best for | A first run: pick your services and get a ready project | Full control, or adding Flisk to an existing folder |
334
- | Package | [`create-microservices`](https://github.com/flisk-sh/create-microservices#readme) | [`@flisk-sh/flisk`](https://www.npmjs.com/package/@flisk-sh/flisk) (this repo) |
338
+ ### Prerequisites (install once)
339
+
340
+ | Tool | Version | Install | Install path |
341
+ |------|---------|---------|--------------|
342
+ | **Docker** | Engine 25+, Compose 2.20.2+ | [docker.com](https://www.docker.com/products/docker-desktop/) | All paths |
343
+ | **Tilt** | 0.25+ | `curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh \| bash` | All paths |
344
+ | **Node.js** | 22.12+ | [nodejs.org](https://nodejs.org/) | npm path (`npm install -g @flisk-sh/flisk`) |
345
+ | **Bun** | 1.2+ | `curl -fsSL https://bun.sh/install \| bash` | Bun path (`bun add -g @flisk-sh/flisk`) |
335
346
 
336
- ### Option A: guided scaffolder (recommended for beginners)
347
+ > **Conditional prerequisites**: Node.js is only required when you install Flisk via npm (`npm install -g @flisk-sh/flisk`). Bun is only required when you install via Bun or your project has generated JavaScript services. Docker and Tilt are required for every path.
337
348
 
338
- **Prerequisites.** Install these first. The scaffolder checks your machine while it creates the project and stops if something is missing:
349
+ > **Windows?** Use WSL2 Ubuntu. See the [Windows & WSL2 guide](docs/wsl2.md) for the recommended setup.
339
350
 
340
- - Node.js 22.12 or newer, and npm
341
- - Docker, installed and running (Engine 25+, Compose 2.20.2+)
342
- - [Tilt](https://docs.tilt.dev/install.html)
343
- - [Bun](https://bun.sh/) 1.2+
351
+ ---
344
352
 
345
- Run these commands from the directory where you want the new project folder to be created. The target directory must be new or empty; existing files are never overwritten.
353
+ ### Fastest path: one-command demo (no manual steps)
346
354
 
347
355
  ```bash
356
+ # 1. Install Flisk
348
357
  npm install -g @flisk-sh/flisk
349
- npm init create-microservices my-project
350
- cd my-project
351
- flisk up main
358
+
359
+ # 2. Run the demo — scaffolds a project, installs deps, boots the stack, opens the frontend
360
+ flisk demo
352
361
  ```
353
362
 
354
- - `npm install -g @flisk-sh/flisk` installs the `flisk` command. Skip it if `flisk --version` already works.
355
- - `npm init create-microservices my-project` asks how many services to create, then each service's name and type (`backend`, `frontend`, `worker`, or `mcp`).
356
- - `flisk up main` starts the stack. `main` is the default stack name; if you pass `--stack <name>` to the scaffolder, use that name instead. The scaffolder prints the exact `flisk up` command when it finishes.
363
+ That's it. The demo clones the starter into `~/.flisk/flisk-demo`, installs dependencies, starts the stack, and opens the frontend in your browser. Press `Ctrl+C` to stop, then run `flisk down` to clean up.
357
364
 
358
- The scaffolder creates the project configuration and a skeleton for each service you selected, using Flisk CLI Core. It does not start any containers; `flisk up` does that.
365
+ ---
359
366
 
360
- To skip the prompts and get a default `api` (backend) and `web` (frontend):
367
+ ### Full control: manual project setup
368
+
369
+ If you want to build your own service structure:
361
370
 
362
371
  ```bash
363
- npm init create-microservices my-project -- --yes
372
+ # 1. Install Flisk (skip if already installed)
373
+ npm install -g @flisk-sh/flisk
374
+
375
+ # 2. Create a project with a backend API
376
+ mkdir my-project && cd my-project
377
+ flisk project --yes
378
+ flisk resource api --type backend --stack main --yes
379
+
380
+ # 3. Start the stack
381
+ flisk up main
364
382
  ```
365
383
 
366
- For service types, all options, and non-interactive usage, see the [`create-microservices` README](https://github.com/flisk-sh/create-microservices#readme).
384
+ `flisk up` prints the URLs (e.g., `http://api.main.localhost/api/api/health`). Try it:
367
385
 
368
- > [!NOTE]
369
- > Two similarly named packages exist. [`create-flisk`](https://github.com/flisk-sh/create-flisk) is a landing-page app and does not scaffold projects. [`create-microservices`](https://github.com/flisk-sh/create-microservices#readme) is the project scaffolder used above.
386
+ ```bash
387
+ curl http://api.main.localhost/api/api/health
388
+ ```
370
389
 
371
- ### Option B: core CLI (manual)
390
+ To add a frontend later:
372
391
 
373
- Use this to create the project and each resource yourself with `flisk`. [Install the CLI](#installation) first. Preview what a stack will start before any container runs:
392
+ ```bash
393
+ flisk resource web --type frontend --stack main --yes
394
+ flisk up main
395
+ ```
396
+
397
+ ---
398
+
399
+ ### Alternative: guided scaffolder
400
+
401
+ Prefer interactive prompts? The `create-microservices` package asks for your service types and generates a ready project:
374
402
 
375
403
  ```bash
376
- flisk up shop --dry-run
404
+ npm install -g @flisk-sh/flisk
405
+ npm init create-microservices my-project
406
+ cd my-project
407
+ flisk up main
377
408
  ```
378
409
 
379
- Then try the full flow:
410
+ To skip prompts and get a default `api` + `web`:
380
411
 
381
412
  ```bash
382
- mkdir shop && cd shop
383
- flisk project --yes
384
- flisk resource orders-api --type backend --stack shop --yes
385
- flisk up shop
386
- curl http://api.shop.localhost/api/orders/health
413
+ npm init create-microservices my-project -- --yes
387
414
  ```
388
415
 
389
- `flisk up` prints the host ports it chose. It uses port 80 when it is free, so URLs carry no port. Otherwise it picks one from 8080-8180, and the URLs it prints include that port (on Linux and WSL2 a non-root user cannot check port 80, so the range is used there). Use the URL `flisk up` prints, or set `FLISK_HTTP_PORT`. A resource named `orders-api` is served at `/api/orders` (a trailing `-api` is dropped); `flisk up` prints the exact URLs.
416
+ See the [`create-microservices` README](https://github.com/flisk-sh/create-microservices#readme) for all options.
417
+
418
+ ---
419
+
420
+ ### Verify it works
421
+
422
+ After `flisk up`, you'll see output like:
423
+
424
+ ```
425
+ Flisk is up.
426
+ Tilt UI: http://localhost:10350
427
+ Services:
428
+ ✓ api → http://api.main.localhost/api/api/health
429
+ ✓ web → http://web.main.localhost
430
+ Stop: flisk down
431
+ Logs: flisk logs <service>
432
+ Next: flisk help # or visit https://flisk.sh/docs
433
+ ```
434
+
435
+ - **Tilt UI**: Open to watch live updates, see logs, and debug
436
+ - **Services**: Click the URLs or curl the health endpoints
437
+ - **Stop**: `flisk down` stops everything; containers persist for inspection
438
+
439
+ ---
440
+
441
+ ### Common next steps
442
+
443
+ | Goal | Command |
444
+ |------|---------|
445
+ | See running services | `flisk ui` |
446
+ | Check environment health | `flisk doctor` |
447
+ | View service logs | `flisk logs api` |
448
+ | Restart a service | `flisk restart api` |
449
+ | Preview without starting | `flisk up main --dry-run` |
450
+ | Catch config drift | `flisk config verify` |
451
+ | Upgrade Flisk | `flisk upgrade` |
452
+
453
+ ### Troubleshooting
454
+
455
+ | Issue | Fix |
456
+ |-------|-----|
457
+ | `flisk doctor` fails | Run the fix commands it prints, then retry |
458
+ | Port 80/5432 in use | `flisk doctor` shows the owner; stop it or set `FLISK_HTTP_PORT` |
459
+ | Docker not running | Start Docker Desktop / `systemctl start docker` |
460
+ | Windows native | Use WSL2 Ubuntu; see [Windows guide](docs/wsl2.md) |
461
+ | `flisk up` refuses | Run `flisk doctor` first; it explains what's missing |
462
+
463
+ Full troubleshooting: [docs/troubleshooting.md](docs/troubleshooting.md)
390
464
 
391
465
  ### What Flisk writes for you
392
466
 
@@ -526,7 +600,7 @@ Runnable examples show Flisk on real stacks. Start with the smallest one:
526
600
 
527
601
  ## Use Flisk with your AI agent
528
602
 
529
- The repository ships agent skills for common Flisk work, including `flisk-doctor` (environment checks) and `flisk-troubleshoot` (fixing `flisk` and Tilt errors), under [`.agents/skills`](.agents/skills). Agents working in this repo also follow [AGENTS.md](AGENTS.md). Use these skills to let your agent check your setup and explain failures instead of guessing at Docker or Tilt configuration.
603
+ The repository ships five agent skills for common Flisk work under [`.agents/skills`](.agents/skills): `flisk-doctor` (environment checks), `flisk-up` (preview and start a stack), `flisk-resource` (create a service), `flisk-status` (health and URLs), and `flisk-troubleshoot` (fixing `flisk` and Tilt errors). Agents working in this repo also follow [AGENTS.md](AGENTS.md). Use these skills to let your agent check your setup and explain failures instead of guessing at Docker or Tilt configuration.
530
604
 
531
605
  ## Installation
532
606
 
@@ -598,7 +672,7 @@ published on 21 September 2026. Those dates describe the current repository and
598
672
 
599
673
  ## Requirements and support
600
674
 
601
- For the local runtime, install Docker (Desktop, OrbStack, or Colima; Engine 25+, Compose 2.20.2+) and [Tilt](https://docs.tilt.dev/install.html). Bun 1.2+ is used by the default generated services. Flisk selects host ports from bounded fallback ranges for HTTP, HTTPS, and Postgres; set `FLISK_HTTP_PORT`, `FLISK_HTTPS_PORT`, or `FLISK_POSTGRES_PORT` to override them. Dev ports listen on `127.0.0.1` only, so other machines on your network cannot reach them. Set `FLISK_BIND_ADDRESS` (for example `0.0.0.0`, to test from a phone) to change that; `flisk doctor` warns when it is a wildcard address. Flisk supports macOS, Linux, and Windows through WSL2 Ubuntu; native Windows supports CLI inspection only. Run `flisk doctor` to check local readiness (supports `--no-ping` to skip service health checks and `--ping-timeout <ms>`). See [WSL2 setup](docs/wsl2.md).
675
+ For the local runtime, install Docker (Desktop, OrbStack, or Colima; Engine 25+, Compose 2.20.2+) and [Tilt](https://docs.tilt.dev/install.html). Bun 1.2+ is used by the default generated services. Flisk selects host ports from bounded fallback ranges for HTTP, HTTPS, and Postgres; set `FLISK_HTTP_PORT`, `FLISK_HTTPS_PORT`, or `FLISK_POSTGRES_PORT` to override them. Dev ports listen on `127.0.0.1` only, so other machines on your network cannot reach them. Set `FLISK_BIND_ADDRESS` (for example `0.0.0.0`, to test from a phone) to change that; `flisk doctor` warns when it is a wildcard address. Flisk supports macOS, Linux, and **Windows through WSL2 Ubuntu**; native Windows supports CLI inspection only (`flisk --version`, `flisk doctor`, `flisk up --dry-run`). `flisk up` exits with a clear refusal pointing to WSL2. See the **[Windows & WSL2 guide](docs/wsl2.md)** for the recommended setup, prerequisites, verification steps, and troubleshooting.
602
676
 
603
677
  On native Windows, `flisk --version`, `flisk doctor`, and `flisk up --dry-run` are inspect-only commands. `flisk up` exits 1 with “Landscape startup needs Ubuntu on WSL2. Native Windows is inspect-only.”
604
678
 
@@ -639,7 +713,7 @@ No. Core CLI is MIT and needs no key to run `flisk up`. Premium extras are optio
639
713
  <details>
640
714
  <summary><strong>Which platforms are supported?</strong></summary>
641
715
 
642
- macOS and Linux are supported directly. Windows is supported through WSL2 Ubuntu; native Windows supports CLI inspection only (`flisk --version`, `flisk doctor`, and `flisk up --dry-run`). See [Requirements and support](#requirements-and-support) and [WSL2 setup](docs/wsl2.md).
716
+ macOS and Linux are supported directly. Windows is supported through WSL2 Ubuntu; native Windows supports CLI inspection only (`flisk --version`, `flisk doctor`, `flisk up --dry-run`). See [Requirements and support](#requirements-and-support) and the **[Windows & WSL2 guide](docs/wsl2.md)** for the recommended setup, prerequisites, verification steps, and troubleshooting.
643
717
 
644
718
  </details>
645
719
 
@@ -735,3 +809,5 @@ Thank you to everyone who has shipped code, docs, and fixes to Flisk since July
735
809
  Flisk is MIT-licensed; see [LICENSE](LICENSE). The [license boundary](docs/project/GOVERNANCE.md#license-boundary-and-donation-scope) says which code is MIT and which is downloaded with a key.
736
810
 
737
811
  Project governance: [GOVERNANCE.md](docs/project/GOVERNANCE.md), [MAINTAINERS.md](docs/project/MAINTAINERS.md), [ADOPTERS.md](docs/project/ADOPTERS.md).
812
+
813
+ <img src='https://raw.githubusercontent.com/flisk-sh/flisk-emoji/main/png/flisk-thunder-64.png' width='20' alt='flisk'> Using Flisk in Slack or Discord? Get the [Flisk green thunder emoji](https://github.com/flisk-sh/flisk-emoji) (SVG and PNG, MIT).
@@ -24,9 +24,14 @@ app.get('/health/db', async (c) => {
24
24
  `
25
25
  : "";
26
26
  return `import { Hono } from 'hono';
27
+ import { cors } from 'hono/cors';
27
28
  ${drizzleImports}
28
29
  const app = new Hono();
29
30
 
31
+ // The frontend runs on its own *.localhost origin (app.<project>.localhost), so the browser needs CORS to call this API.
32
+ const LOCAL_FRONTEND_ORIGIN = /^https?:\\/\\/([a-z0-9-]+\\.)+localhost(:\\d+)?$/;
33
+ app.use('*', cors({ origin: (origin) => (LOCAL_FRONTEND_ORIGIN.test(origin) ? origin : undefined) }));
34
+
30
35
  // Health check endpoint (required by TILT_RESOURCE_DEFAULTS.star)
31
36
  app.get('/health', (c) => {
32
37
  return c.json({ status: 'ok', service: '${name}' });
@@ -34,7 +34,9 @@ import (
34
34
  func writeJSON(w http.ResponseWriter, status int, body any) {
35
35
  w.Header().Set("Content-Type", "application/json")
36
36
  w.WriteHeader(status)
37
- _ = json.NewEncoder(w).Encode(body)
37
+ if err := json.NewEncoder(w).Encode(body); err != nil {
38
+ log.Printf("failed to encode JSON response: %v", err)
39
+ }
38
40
  }
39
41
 
40
42
  func newMux() *http.ServeMux {
package/cli/dist/cli.js CHANGED
@@ -12,6 +12,7 @@ import { showHelp } from "./commands/help.js";
12
12
  import { createProgram } from "./program.js";
13
13
  import { ensureGlobalInstall } from "./utils/cli-command.js";
14
14
  import { formatColdPreflight, runColdPreflight } from "./utils/cold-preflight.js";
15
+ import { stopDemoStack } from "./utils/demo-reset.js";
15
16
  import { unknownHelpTarget } from "./utils/help-command.js";
16
17
  import { bareTemplateArg } from "./utils/project-templates.js";
17
18
  const program = createProgram();
@@ -68,6 +69,7 @@ if (templateArg) {
68
69
  }
69
70
  }
70
71
  const destination = isAbsolute(targetName) ? targetName : resolve(cwd(), targetName);
72
+ console.log(chalk.gray(`📁 Demo folder: ${destination}`));
71
73
  // Reusing an existing checkout is what keeps a second take free: the clone and the
72
74
  // dependency install are skipped, so the recording starts on the interesting part.
73
75
  let reused = false;
@@ -85,6 +87,13 @@ if (templateArg) {
85
87
  await openUrl(running.url);
86
88
  process.exit(0);
87
89
  }
90
+ // Take the old stack down before its folder goes, so a Traefik left behind does not keep port 80.
91
+ try {
92
+ stopDemoStack(destination);
93
+ }
94
+ catch (error) {
95
+ console.log(chalk.yellow(`Could not stop the previous demo stack: ${error.message}`));
96
+ }
88
97
  if (keep) {
89
98
  reused = true;
90
99
  }
@@ -463,7 +463,14 @@ _flisk_resources() {
463
463
  ${subCommandLists}
464
464
 
465
465
  ${typeValueFunctions}
466
- compdef _flisk flisk
466
+
467
+ # Autoloaded from fpath, this file is the body of _flisk, so run it now to complete the first TAB.
468
+ # Sourced (\`source <(flisk completion zsh)\`), register it instead.
469
+ if [ "$funcstack[1]" = "_flisk" ]; then
470
+ _flisk "$@"
471
+ else
472
+ compdef _flisk flisk
473
+ fi
467
474
  `;
468
475
  }
469
476
  /** The `_arguments` spec of one flag, with the values it completes when it has them. */
@@ -9,7 +9,8 @@ import { hasVerdaccioLicense } from "../generator/extension-fetch.js";
9
9
  import { generateMasterConfigs, readProjectConfig, TemplateEngine, verifyMasterConfigs, } from "../generator/template-engine.js";
10
10
  import { isMasterConfigFileName } from "../types/index.js";
11
11
  import { assertValid, handleDryRun } from "../utils/command-helpers.js";
12
- import { MASTER_CONFIG_FILES, PROJECT_JSON } from "../utils/constants.js";
12
+ import { explainConfigFile } from "../utils/config-explain.js";
13
+ import { MASTER_CONFIG_FILES, PROJECT_JSON, RESOURCE_DEFAULTS_FILE, TECH_STACK_FILE, } from "../utils/constants.js";
13
14
  import { clearDiscoveryCache } from "../utils/discovery-context.js";
14
15
  import { checkPrismaConsistency } from "../utils/doctor-wiring.js";
15
16
  import { errorFactories, requireProjectRoot, runCommand, showError } from "../utils/errors.js";
@@ -20,6 +21,12 @@ import { SERVICE_MANIFEST_SCHEMA_VERSION, validateServiceManifest, } from "../ut
20
21
  import { discoverResourcesWithProblems, discoverServiceManifestPaths, warnAboutSkippedFiles, } from "../utils/services.js";
21
22
  import { evaluateSharedPlatformPostgres } from "../utils/shared-platform-postgres.js";
22
23
  import { validateOptionalInfraService } from "../utils/validation.js";
24
+ /** Human wording for `flisk config explain`, one line per drift outcome. */
25
+ const DRIFT_LABELS = {
26
+ "blocks-up": "yes, until the edit is removed or --ignore-drift is passed",
27
+ none: "no",
28
+ unknown: "unknown",
29
+ };
23
30
  export const configCommand = new Command("config")
24
31
  .description("Manage project configuration and regenerate master files")
25
32
  .addCommand(new Command("regenerate")
@@ -36,72 +43,104 @@ export const configCommand = new Command("config")
36
43
  const newFiles = engine.generateAll(projectConfig);
37
44
  const outputDir = join(projectRoot, ".flisk", ".flisk-out");
38
45
  const filesToCheck = MASTER_CONFIG_FILES;
46
+ const fileGroups = [
47
+ {
48
+ title: "📋 Core orchestration",
49
+ files: [TECH_STACK_FILE, RESOURCE_DEFAULTS_FILE],
50
+ description: "Tilt tech stack and resource defaults; drives all service generation",
51
+ },
52
+ {
53
+ title: "📦 Project spec",
54
+ files: ["spec.master"],
55
+ description: "Compiled project specification; used by Tilt for service discovery",
56
+ },
57
+ ];
39
58
  let hasChanges = false;
40
- for (const filename of filesToCheck) {
41
- // Runtime validation with type guard eliminates type assertion
42
- if (!isMasterConfigFileName(filename)) {
43
- continue; // Skip unknown files (shouldn't happen with const array)
44
- }
45
- const newContent = newFiles[filename];
46
- const filePath = join(outputDir, filename);
47
- if (!existsSync(filePath)) {
48
- console.log(chalk.yellow(`📁 ${filename}`));
49
- console.log(chalk.gray(" Status: NEW (file does not exist)\n"));
50
- hasChanges = true;
51
- continue;
52
- }
53
- const currentContent = readFileSync(filePath, "utf-8");
54
- if (currentContent === newContent) {
55
- console.log(chalk.green(`✓ ${filename}`));
56
- console.log(chalk.gray(" Status: No changes\n"));
57
- }
58
- else {
59
- console.log(chalk.yellow(`📝 ${filename}`));
60
- console.log(chalk.gray(" Status: MODIFIED"));
61
- const currentLines = currentContent.split("\n").length;
62
- const newLines = newContent.split("\n").length;
63
- const lineDiff = newLines - currentLines;
64
- if (lineDiff > 0) {
65
- console.log(chalk.gray(` Lines: ${currentLines} → ${newLines} (+${lineDiff})`));
59
+ for (const group of fileGroups) {
60
+ let groupHasChanges = false;
61
+ const groupChanges = [];
62
+ for (const filename of group.files) {
63
+ if (!filesToCheck.includes(filename))
64
+ continue;
65
+ if (!isMasterConfigFileName(filename))
66
+ continue;
67
+ const newContent = newFiles[filename];
68
+ const filePath = join(outputDir, filename);
69
+ if (!existsSync(filePath)) {
70
+ groupHasChanges = true;
71
+ groupChanges.push({ filename, isNew: true, lineDiff: 0, diffLines: [] });
72
+ continue;
66
73
  }
67
- else if (lineDiff < 0) {
68
- console.log(chalk.gray(` Lines: ${currentLines} → ${newLines} (${lineDiff})`));
69
- }
70
- else {
71
- console.log(chalk.gray(` Lines: ${currentLines} (content changed)`));
72
- }
73
- const currentLinesArr = currentContent.split("\n");
74
- const newLinesArr = newContent.split("\n");
75
- let firstDiffLine = -1;
76
- for (let i = 0; i < Math.max(currentLinesArr.length, newLinesArr.length); i++) {
77
- if (currentLinesArr[i] !== newLinesArr[i]) {
78
- firstDiffLine = i;
79
- break;
74
+ const currentContent = readFileSync(filePath, "utf-8");
75
+ if (currentContent !== newContent) {
76
+ groupHasChanges = true;
77
+ const currentLines = currentContent.split("\n").length;
78
+ const newLines = newContent.split("\n").length;
79
+ const lineDiff = newLines - currentLines;
80
+ const currentLinesArr = currentContent.split("\n");
81
+ const newLinesArr = newContent.split("\n");
82
+ let firstDiffLine = -1;
83
+ for (let i = 0; i < Math.max(currentLinesArr.length, newLinesArr.length); i++) {
84
+ if (currentLinesArr[i] !== newLinesArr[i]) {
85
+ firstDiffLine = i;
86
+ break;
87
+ }
80
88
  }
81
- }
82
- if (firstDiffLine >= 0) {
83
- console.log(chalk.gray(` First change around line ${firstDiffLine + 1}:`));
84
- const contextStart = Math.max(0, firstDiffLine - 1);
85
- const contextEnd = Math.min(currentLinesArr.length, firstDiffLine + 2);
86
- for (let i = contextStart; i < contextEnd; i++) {
87
- const line = currentLinesArr[i];
88
- const newLine = newLinesArr[i];
89
- if (line !== newLine) {
90
- if (line !== undefined) {
91
- console.log(chalk.red(` - ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
89
+ const diffLines = [];
90
+ if (firstDiffLine >= 0) {
91
+ const contextStart = Math.max(0, firstDiffLine - 1);
92
+ const contextEnd = Math.min(currentLinesArr.length, firstDiffLine + 2);
93
+ for (let i = contextStart; i < contextEnd; i++) {
94
+ const line = currentLinesArr[i];
95
+ const newLine = newLinesArr[i];
96
+ if (line !== newLine) {
97
+ if (line !== undefined) {
98
+ diffLines.push(chalk.red(` - ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
99
+ }
100
+ if (newLine !== undefined) {
101
+ diffLines.push(chalk.green(` + ${newLine.substring(0, 60)}${newLine.length > 60 ? "..." : ""}`));
102
+ }
92
103
  }
93
- if (newLine !== undefined) {
94
- console.log(chalk.green(` + ${newLine.substring(0, 60)}${newLine.length > 60 ? "..." : ""}`));
104
+ else {
105
+ diffLines.push(chalk.gray(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
95
106
  }
96
107
  }
108
+ }
109
+ groupChanges.push({ filename, isNew: false, lineDiff, diffLines });
110
+ }
111
+ }
112
+ if (groupHasChanges) {
113
+ console.log(chalk.blue(`\n${group.title}`));
114
+ console.log(chalk.gray(` ${group.description}\n`));
115
+ for (const change of groupChanges) {
116
+ if (change.isNew) {
117
+ console.log(chalk.yellow(` 📁 ${change.filename}`));
118
+ console.log(chalk.gray(" Status: NEW (file does not exist)\n"));
119
+ }
120
+ else {
121
+ console.log(chalk.yellow(` 📝 ${change.filename}`));
122
+ console.log(chalk.gray(" Status: MODIFIED"));
123
+ if (change.lineDiff > 0) {
124
+ console.log(chalk.gray(` Lines: +${change.lineDiff}`));
125
+ }
126
+ else if (change.lineDiff < 0) {
127
+ console.log(chalk.gray(` Lines: ${change.lineDiff}`));
128
+ }
97
129
  else {
98
- console.log(chalk.gray(` ${line.substring(0, 60)}${line.length > 60 ? "..." : ""}`));
130
+ console.log(chalk.gray(" Lines: content changed"));
99
131
  }
132
+ for (const diffLine of change.diffLines) {
133
+ console.log(diffLine);
134
+ }
135
+ console.log("");
100
136
  }
101
137
  }
102
- console.log("");
103
138
  hasChanges = true;
104
139
  }
140
+ else {
141
+ console.log(chalk.green(`\n✅ ${group.title} — all up to date`));
142
+ console.log(chalk.gray(` ${group.description}\n`));
143
+ }
105
144
  }
106
145
  if (hasChanges) {
107
146
  console.log(chalk.blue("💡 Run without --dry-run to apply these changes.\n"));
@@ -268,6 +307,42 @@ export const configCommand = new Command("config")
268
307
  return;
269
308
  }
270
309
  await runCommand(action);
310
+ }))
311
+ .addCommand(new Command("explain")
312
+ .description("Explain whether a project file is Flisk-generated and what editing it does on flisk up")
313
+ .argument("<file>", "Project file to explain, relative to the current directory or absolute")
314
+ .option("--json", "Emit a machine-readable explanation")
315
+ .action(async (file, options) => {
316
+ const action = async () => {
317
+ const projectRoot = options.json ? findProjectRoot() : requireProjectRoot();
318
+ if (!projectRoot)
319
+ throw errorFactories.notInProject();
320
+ const explanation = explainConfigFile(projectRoot, file);
321
+ if (options.json) {
322
+ console.log(JSON.stringify(createMachineEnvelope(explanation)));
323
+ return;
324
+ }
325
+ console.log(chalk.blue(`${explanation.file}\n`));
326
+ console.log(` Ownership: ${explanation.ownership}`);
327
+ console.log(` ${explanation.reason}`);
328
+ if (explanation.source)
329
+ console.log(` Source: ${explanation.source}`);
330
+ console.log(` Edited now: ${explanation.isEditedNow ? "yes" : "no"}`);
331
+ console.log(` Editing it blocks flisk up: ${DRIFT_LABELS[explanation.driftOnUp]}`);
332
+ console.log(chalk.blue("\nNext:"));
333
+ for (const step of explanation.next)
334
+ console.log(chalk.gray(` - ${step}`));
335
+ };
336
+ if (options.json) {
337
+ try {
338
+ await action();
339
+ }
340
+ catch (error) {
341
+ writeMachineError(error);
342
+ }
343
+ return;
344
+ }
345
+ await runCommand(action);
271
346
  }))
272
347
  .addCommand(new Command("edit").description("Open .flisk/project.json in your $EDITOR").action(async () => {
273
348
  await runCommand(async () => {