@flisk-sh/flisk 1.4.2 → 1.4.6
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 +4 -0
- package/README.md +148 -49
- package/cli/dist/backend-languages/bun.js +5 -0
- package/cli/dist/backend-languages/go.js +3 -1
- package/cli/dist/cli.js +9 -0
- package/cli/dist/commands/completion.js +8 -1
- package/cli/dist/commands/config.js +130 -55
- package/cli/dist/commands/doctor.js +66 -27
- package/cli/dist/commands/down.js +33 -1
- package/cli/dist/commands/logs.js +39 -1
- package/cli/dist/commands/project.js +12 -0
- package/cli/dist/commands/resource.js +39 -11
- package/cli/dist/commands/status.js +57 -19
- package/cli/dist/commands/up.js +221 -18
- package/cli/dist/commands/upgrade.js +2 -2
- package/cli/dist/frontend-frameworks/next.js +197 -0
- package/cli/dist/frontend-frameworks/react.js +81 -12
- package/cli/dist/frontend-frameworks/registry.js +5 -4
- package/cli/dist/frontend-frameworks/vue.js +82 -12
- package/cli/dist/generator/resource-templates.js +2 -4
- package/cli/dist/generator/template-engine.js +5 -3
- package/cli/dist/utils/bun-requirement.js +7 -4
- package/cli/dist/utils/cold-preflight.js +55 -34
- package/cli/dist/utils/config-explain.js +197 -0
- package/cli/dist/utils/demo-reset.js +22 -0
- package/cli/dist/utils/discovery-paths.js +7 -1
- package/cli/dist/utils/doctor-native.js +96 -0
- package/cli/dist/utils/host-port-plan.js +8 -3
- package/cli/dist/utils/native-project.js +41 -0
- package/cli/dist/utils/native-runtime.js +513 -0
- package/cli/dist/utils/native-service.js +95 -0
- package/cli/dist/utils/native-up.js +156 -0
- package/cli/dist/utils/platform.js +1 -1
- package/cli/dist/utils/port-conflict-fix.js +16 -14
- package/cli/dist/utils/port-occupant.js +35 -0
- package/cli/dist/utils/project-features.js +7 -16
- package/cli/dist/utils/project-templates.js +9 -9
- package/cli/dist/utils/resource-features.js +5 -5
- package/cli/dist/utils/service-manifest.js +20 -3
- package/cli/dist/utils/service-urls.js +11 -0
- package/cli/dist/utils/services.js +15 -2
- package/cli/dist/utils/startup-report.js +4 -3
- package/cli/dist/utils/tar.js +33 -28
- package/cli/dist/utils/tilt-logs.js +8 -0
- package/cli/dist/utils/tilt-process.js +4 -3
- package/cli/dist/utils/windows-doctor.js +18 -15
- package/cli/dist-bundle/chunk-BIVAAWBX.js +24 -0
- package/cli/dist-bundle/{chunk-YNCBBJ4V.js → chunk-C4UFBXRD.js} +1 -1
- package/cli/dist-bundle/{chunk-53L2JN7G.js → chunk-CAEMWNPF.js} +1 -1
- package/cli/dist-bundle/chunk-CDKEHFW6.js +35 -0
- package/cli/dist-bundle/{chunk-5QBYM33Q.js → chunk-DPQK5TIS.js} +1 -1
- package/cli/dist-bundle/chunk-ETXZ5LUG.js +18 -0
- package/cli/dist-bundle/chunk-GPUJ55MI.js +3 -0
- package/cli/dist-bundle/chunk-GT76VMUL.js +130 -0
- package/cli/dist-bundle/{chunk-IGN5UC3P.js → chunk-IDNES5PE.js} +14 -7
- package/cli/dist-bundle/{chunk-MWOVYIBB.js → chunk-MUDE4DZD.js} +5 -5
- package/cli/dist-bundle/chunk-QEBN6ZVQ.js +2 -0
- package/cli/dist-bundle/{chunk-I7TGIK5N.js → chunk-R7DWXISM.js} +1 -1
- package/cli/dist-bundle/{chunk-DU2BN46C.js → chunk-U5FCQF42.js} +1 -1
- package/cli/dist-bundle/{chunk-3XODDLRJ.js → chunk-WCGBVETR.js} +1 -1
- package/cli/dist-bundle/cli.js +626 -389
- package/cli/dist-bundle/cold-preflight-KUWOL2Q2.js +2 -0
- package/cli/dist-bundle/{demo-stage-OHNTP2UJ.js → demo-stage-QCC4IWXR.js} +1 -1
- package/cli/dist-bundle/{extension-fetch-VEFSCG4B.js → extension-fetch-KIPYDIRM.js} +1 -1
- package/cli/dist-bundle/{open-XROJ6YEY.js → open-AZNX4AC5.js} +1 -1
- package/cli/dist-bundle/project-5SWIGCNP.js +2 -0
- package/cli/dist-bundle/{project-templates-EYSQG2EO.js → project-templates-2VQPUBSQ.js} +1 -1
- package/cli/dist-bundle/{services-BIMF6MVU.js → services-EY5WKPHQ.js} +1 -1
- package/cli/dist-bundle/{tilt-port-owner-ZY5M2JC4.js → tilt-port-owner-UBU6JWOA.js} +1 -1
- package/cli/package.json +1 -1
- package/examples/{tdk-example → flisk-example}/README.md +2 -2
- package/package.json +2 -2
- package/runtime/discovery/AGENTS.md +1 -1
- package/runtime/discovery/TILT_DISCOVERY.star +1 -1
- package/runtime/discovery/deterministic.star +1 -1
- package/runtime/engine/AGENTS.md +3 -3
- package/runtime/engine/README.md +1 -1
- package/runtime/engine/REFACTORING_MANIFEST_SYSTEM.md +1 -1
- package/runtime/engine/assets/docker/wake-gateway/decide.ts +1 -1
- package/runtime/engine/assets/docker/wake-gateway/server.ts +2 -2
- package/runtime/engine/assets/scripts/mac-m1-resource-monitor.sh +6 -6
- package/runtime/engine/schemas/service-schema.json +99 -21
- package/runtime/engine/scripts/debug-container.sh +1 -1
- package/runtime/engine/scripts/generate-manifest.sh +2 -2
- package/runtime/engine/topologies/platform/docker/compose/compose.star +40 -4
- package/runtime/engine/topologies/platform/docker/compose/traefik_standalone.star +19 -4
- package/runtime/engine/topologies/platform/docker/constants.star +2 -2
- package/runtime/engine/topologies/platform/docker/dockerfile/language_dockerfile.star +6 -0
- package/runtime/engine/topologies/platform/docker/dockerfile/next_dockerfile.star +83 -0
- package/runtime/engine/topologies/platform/docker/index.star +4 -0
- package/runtime/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +7 -0
- package/runtime/engine/topologies/platform/docker/networking/traefik.star +85 -46
- package/runtime/engine/topologies/platform/docker/networking/traefik_static_routes.star +2 -2
- package/runtime/engine/topologies/tilt/common/utils_output.star +1 -0
- package/runtime/engine/topologies/tilt/generators/validators.star +1 -1
- package/runtime/engine/topologies/tilt/generators/vite/frontend.star +2 -2
- package/runtime/engine/topologies/tilt/generators/vite/generators.star +3 -0
- package/runtime/engine/topologies/tilt/manifest/constants.star +3 -0
- package/runtime/engine/topologies/tilt/manifest/mapper.star +1 -1
- package/runtime/engine/topologies/tilt/manifest/parser.star +9 -3
- package/runtime/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +9 -4
- package/runtime/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +50 -24
- package/runtime/engine/topologies/tilt/resources/orchestrator/generators/env.star +11 -2
- package/runtime/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +23 -9
- package/runtime/ext/ide-components/README.md +1 -1
- package/runtime/ext/ui-enhancements/extension.yaml +2 -2
- package/runtime/specs/specs/TILT_SERVICE_DEFAULTS.star +1 -1
- package/runtime/specs/specs/TILT_TECH_STACK.star +1 -1
- package/cli/dist-bundle/chunk-43XWL2PB.js +0 -61
- package/cli/dist-bundle/chunk-5F7YP5IR.js +0 -17
- package/cli/dist-bundle/chunk-ETKUVKJ2.js +0 -35
- package/cli/dist-bundle/chunk-K6SOCO6V.js +0 -3
- package/cli/dist-bundle/chunk-YHYRGWUH.js +0 -24
- package/cli/dist-bundle/chunk-YL56J2WX.js +0 -2
- package/cli/dist-bundle/cold-preflight-ZOPR7PWJ.js +0 -2
- package/cli/dist-bundle/project-7PTIOHGF.js +0 -2
- /package/examples/{tdk-example → flisk-example}/LICENSE +0 -0
- /package/examples/{tdk-example → flisk-example}/TILT_SERVICE_DEFAULTS.star +0 -0
- /package/examples/{tdk-example → flisk-example}/TILT_TECH_STACK.star +0 -0
- /package/examples/{tdk-example → flisk-example}/Tiltfile +0 -0
- /package/examples/{tdk-example → flisk-example}/services/platform/messaging/docker-compose.yml +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/src/index.ts +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/index.html +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/public/.gitkeep +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/main.tsx +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/orders.tsx +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/style.css +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/src/index.ts +0 -0
|
@@ -15,6 +15,7 @@ import { isPathDiscovered, readDiscoveryPaths } from "../utils/discovery-paths.j
|
|
|
15
15
|
import { checkCrashLoopingContainers } from "../utils/doctor-crashloop.js";
|
|
16
16
|
import { applyDoctorFixes, checkDuplicateFliskInstalls, hasFailedActions, planDoctorFixes, projectTiltPids, } from "../utils/doctor-fix.js";
|
|
17
17
|
import { checkDiskSpace, dockerDesktopStuck } from "../utils/doctor-host.js";
|
|
18
|
+
import { checkNativeCommands, checkNativeDependsOn, checkNativeRuntime, checkNativeServiceHealth, } from "../utils/doctor-native.js";
|
|
18
19
|
import { collectDoctorChecks, createDoctorReport, getDoctorExitCode, } from "../utils/doctor-report.js";
|
|
19
20
|
import { checkHealthRoutes, checkIngressPorts, checkPrivateNpmRegistry, checkTiltResourceHealth, projectConfigEnablesVerdaccio, summarizeAdvertisedProbes, summarizeServiceProbes, summarizeSmokeResults, } from "../utils/doctor-runtime.js";
|
|
20
21
|
import { checkStarlarkLoadExports } from "../utils/doctor-starlark.js";
|
|
@@ -25,6 +26,7 @@ import { evaluateFliskVersionFloor } from "../utils/flisk-version.js";
|
|
|
25
26
|
import { formatCount } from "../utils/formatting.js";
|
|
26
27
|
import { getHostPortPlan, resolveRuntimeIngressPort } from "../utils/host-port-config.js";
|
|
27
28
|
import { createHostPortPlan } from "../utils/host-port-plan.js";
|
|
29
|
+
import { findNativeProject } from "../utils/native-project.js";
|
|
28
30
|
import { findProjectRoot, getPackageVersion } from "../utils/paths.js";
|
|
29
31
|
import { promptConfirm } from "../utils/prompt.js";
|
|
30
32
|
import { EnvUnreadableError, envSecretValues, redactSecrets, redactValue, } from "../utils/secret-redaction.js";
|
|
@@ -291,7 +293,8 @@ export async function checkColima() {
|
|
|
291
293
|
name: "Colima",
|
|
292
294
|
didPass: false,
|
|
293
295
|
message: status.problem ?? "The Colima VM is not running",
|
|
294
|
-
fix: status.fix
|
|
296
|
+
fix: status.fix ??
|
|
297
|
+
"Start Colima: colima start\n Verify: colima status\n Docs: https://github.com/abiosoft/colima",
|
|
295
298
|
};
|
|
296
299
|
}
|
|
297
300
|
export async function checkDockerRuntime() {
|
|
@@ -309,7 +312,7 @@ export async function checkDockerRuntime() {
|
|
|
309
312
|
name: CONTAINER_RUNTIME_CHECK,
|
|
310
313
|
didPass: false,
|
|
311
314
|
message: "Docker is not running",
|
|
312
|
-
fix:
|
|
315
|
+
fix: "Start Docker Desktop, enable WSL2 integration, then retry: flisk doctor\n Verify: docker ps\n Docs: https://docs.docker.com/desktop/wsl/",
|
|
313
316
|
};
|
|
314
317
|
}
|
|
315
318
|
}
|
|
@@ -327,8 +330,8 @@ export async function checkDockerRuntime() {
|
|
|
327
330
|
return {
|
|
328
331
|
name: CONTAINER_RUNTIME_CHECK,
|
|
329
332
|
didPass: false,
|
|
330
|
-
message: "Docker daemon is not responding",
|
|
331
|
-
fix:
|
|
333
|
+
message: "Docker daemon is not responding (timeout)",
|
|
334
|
+
fix: "Restart Docker daemon: systemctl restart docker (Linux) or restart Docker Desktop/Colima\n Verify: docker ps\n Docs: https://docs.docker.com/config/daemon/",
|
|
332
335
|
};
|
|
333
336
|
}
|
|
334
337
|
}
|
|
@@ -349,7 +352,7 @@ export async function checkDockerRuntime() {
|
|
|
349
352
|
name: CONTAINER_RUNTIME_CHECK,
|
|
350
353
|
didPass: false,
|
|
351
354
|
message: "Colima is installed but not running",
|
|
352
|
-
fix:
|
|
355
|
+
fix: "Start Colima: colima start\n Verify: colima status\n Docs: https://github.com/abiosoft/colima",
|
|
353
356
|
};
|
|
354
357
|
}
|
|
355
358
|
if (await succeeds("podman ps")) {
|
|
@@ -364,14 +367,14 @@ export async function checkDockerRuntime() {
|
|
|
364
367
|
name: CONTAINER_RUNTIME_CHECK,
|
|
365
368
|
didPass: false,
|
|
366
369
|
message: "Docker daemon is not running",
|
|
367
|
-
fix:
|
|
370
|
+
fix: "Start Docker daemon: systemctl start docker (Linux) or start Docker Desktop\n Verify: docker ps\n Docs: https://docs.docker.com/engine/daemon/",
|
|
368
371
|
};
|
|
369
372
|
}
|
|
370
373
|
return {
|
|
371
374
|
name: CONTAINER_RUNTIME_CHECK,
|
|
372
375
|
didPass: false,
|
|
373
|
-
message: "Docker is not
|
|
374
|
-
fix:
|
|
376
|
+
message: "Docker is not installed",
|
|
377
|
+
fix: "Install Docker: https://docs.docker.com/get-docker/\n Verify: docker --version\n After install, start Docker and retry: flisk doctor",
|
|
375
378
|
};
|
|
376
379
|
}
|
|
377
380
|
export const checkDockerCompose = createExecCheck("Docker Compose", "docker compose version", "Docker Compose plugin available", "Docker Compose plugin not found", "Install Docker Compose: https://docs.docker.com/compose/install/");
|
|
@@ -442,7 +445,7 @@ export async function checkDockerVersions(exec = execAsync) {
|
|
|
442
445
|
name: "Docker Versions",
|
|
443
446
|
didPass: false,
|
|
444
447
|
message: `Docker is too old for generated healthchecks (they use start_interval):\n ${problems.join("\n ")}`,
|
|
445
|
-
fix: "Update Docker Desktop, or
|
|
448
|
+
fix: "Update Docker: Docker Desktop (auto-updates), or Linux: apt/yum/dnf update docker-ce docker-compose-plugin\n Verify: docker version --format '{{.Server.Version}}' && docker compose version --short\n Docs: https://docs.docker.com/engine/install/",
|
|
446
449
|
};
|
|
447
450
|
}
|
|
448
451
|
checkDockerVersions.requiresContainerRuntime = true;
|
|
@@ -457,7 +460,7 @@ export async function checkTilt(exec = execAsync) {
|
|
|
457
460
|
name: "Tilt CLI",
|
|
458
461
|
didPass: false,
|
|
459
462
|
message: "Tilt CLI not found",
|
|
460
|
-
fix:
|
|
463
|
+
fix: "Install Tilt: curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash\n Verify: tilt version\n Docs: https://docs.tilt.dev/install.html",
|
|
461
464
|
};
|
|
462
465
|
}
|
|
463
466
|
if (!versionMeetsMinimum(raw, MIN_TILT_VERSION)) {
|
|
@@ -465,7 +468,7 @@ export async function checkTilt(exec = execAsync) {
|
|
|
465
468
|
name: "Tilt CLI",
|
|
466
469
|
didPass: false,
|
|
467
470
|
message: `Tilt ${raw || "version unknown"} is below the required v${MIN_TILT_VERSION.join(".")} floor`,
|
|
468
|
-
fix: `
|
|
471
|
+
fix: `Upgrade Tilt to v${MIN_TILT_VERSION.join(".")} or newer: https://docs.tilt.dev/install.html\n Verify: tilt version\n If using Homebrew: brew upgrade tilt`,
|
|
469
472
|
};
|
|
470
473
|
}
|
|
471
474
|
return { name: "Tilt CLI", didPass: true, message: `Tilt ${raw} is available` };
|
|
@@ -490,7 +493,7 @@ export async function checkDockerOperatingSystem(exec = execAsync) {
|
|
|
490
493
|
name: "Docker OS",
|
|
491
494
|
didPass: false,
|
|
492
495
|
message: `Docker is using the ${osType || "unknown"} engine; Flisk requires Linux containers`,
|
|
493
|
-
fix: "Switch Docker Desktop to Linux containers
|
|
496
|
+
fix: "Switch Docker Desktop to Linux containers: Settings > General > Use the WSL 2 based engine\n Or on Windows: docker context use default (if using WSL2 backend)\n Verify: docker info --format '{{.OSType}}'\n Docs: https://docs.docker.com/desktop/wsl/",
|
|
494
497
|
};
|
|
495
498
|
}
|
|
496
499
|
return { name: "Docker OS", didPass: true, message: "Docker is using Linux containers" };
|
|
@@ -522,7 +525,7 @@ export async function checkBun(exec = execAsync) {
|
|
|
522
525
|
name: "Bun",
|
|
523
526
|
didPass: false,
|
|
524
527
|
message: `Bun ${rawVersion || "version unknown"} is below the required ${MIN_BUN_VERSION.join(".")} floor`,
|
|
525
|
-
fix: `
|
|
528
|
+
fix: `Upgrade Bun to ${MIN_BUN_VERSION.join(".")} or newer: https://bun.sh/install\n Verify: bun --version\n If using npm: npm install -g bun@latest`,
|
|
526
529
|
};
|
|
527
530
|
}
|
|
528
531
|
return {
|
|
@@ -535,8 +538,8 @@ export async function checkBun(exec = execAsync) {
|
|
|
535
538
|
return {
|
|
536
539
|
name: "Bun",
|
|
537
540
|
didPass: false,
|
|
538
|
-
message: "Bun is not
|
|
539
|
-
fix:
|
|
541
|
+
message: "Bun is not installed",
|
|
542
|
+
fix: "Install Bun: curl -fsSL https://bun.sh/install | bash\n Verify: bun --version\n Docs: https://bun.sh/docs/installation",
|
|
540
543
|
};
|
|
541
544
|
}
|
|
542
545
|
}
|
|
@@ -1284,8 +1287,13 @@ export const doctorCommand = new Command("doctor")
|
|
|
1284
1287
|
process.exit(2);
|
|
1285
1288
|
return;
|
|
1286
1289
|
}
|
|
1290
|
+
// A project whose services all declare `command` runs as local processes: doctor checks only what they need (#2231).
|
|
1291
|
+
const nativeProject = findNativeProject();
|
|
1292
|
+
const nativeResources = nativeProject?.resources ?? null;
|
|
1287
1293
|
if (!options.json) {
|
|
1288
|
-
console.log(
|
|
1294
|
+
console.log(nativeResources
|
|
1295
|
+
? "Flisk doctor checks what this project's local processes need; its services declare commands, so Docker and Tilt are not checked."
|
|
1296
|
+
: "Flisk doctor checks your local Docker + Tilt development environment; it does not check cluster deployments.");
|
|
1289
1297
|
}
|
|
1290
1298
|
const host = detectHost();
|
|
1291
1299
|
if (process.platform === "win32") {
|
|
@@ -1342,10 +1350,15 @@ export const doctorCommand = new Command("doctor")
|
|
|
1342
1350
|
console.log(`\n${chalk.bold("🔍 Flisk Doctor")}\n`);
|
|
1343
1351
|
console.log("Checking environment...\n");
|
|
1344
1352
|
}
|
|
1345
|
-
|
|
1353
|
+
// A directory of command services is a project for doctor even before `flisk up` writes its .flisk/project.json.
|
|
1354
|
+
const projectRoot = findProjectRoot() ?? nativeProject?.projectRoot ?? null;
|
|
1346
1355
|
// Repairs run before the checks so the checks report the state after the fix.
|
|
1347
1356
|
let fixActions;
|
|
1348
|
-
if (options.fix) {
|
|
1357
|
+
if (options.fix && nativeResources) {
|
|
1358
|
+
// The repairs are for Docker networks and Tilt probes, which a project of local processes does not have.
|
|
1359
|
+
fixActions = [];
|
|
1360
|
+
}
|
|
1361
|
+
else if (options.fix) {
|
|
1349
1362
|
try {
|
|
1350
1363
|
let projectName;
|
|
1351
1364
|
if (projectRoot) {
|
|
@@ -1387,16 +1400,19 @@ export const doctorCommand = new Command("doctor")
|
|
|
1387
1400
|
if (!options.json)
|
|
1388
1401
|
printFixActions(fixActions, options.dryRun);
|
|
1389
1402
|
}
|
|
1403
|
+
// The host port plan places the gateway and Postgres containers; a project of local processes has neither.
|
|
1390
1404
|
let hostPortPlan;
|
|
1391
1405
|
let portPlanError;
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1406
|
+
if (!nativeResources) {
|
|
1407
|
+
try {
|
|
1408
|
+
hostPortPlan = await getHostPortPlan(projectRoot ?? process.cwd());
|
|
1409
|
+
}
|
|
1410
|
+
catch (error) {
|
|
1411
|
+
hostPortPlan = null;
|
|
1412
|
+
portPlanError = error instanceof Error ? error.message : String(error);
|
|
1413
|
+
}
|
|
1398
1414
|
}
|
|
1399
|
-
const
|
|
1415
|
+
const containerMachineChecks = [
|
|
1400
1416
|
() => hostPortPlan
|
|
1401
1417
|
? {
|
|
1402
1418
|
name: "Host Ports",
|
|
@@ -1433,7 +1449,7 @@ export const doctorCommand = new Command("doctor")
|
|
|
1433
1449
|
requiresContainerRuntime("Docker Network Pool", () => checkDockerNetworkCapacity()),
|
|
1434
1450
|
() => checkDuplicateFliskInstalls(),
|
|
1435
1451
|
];
|
|
1436
|
-
const
|
|
1452
|
+
const containerProjectChecks = [
|
|
1437
1453
|
() => checkFliskVersion(),
|
|
1438
1454
|
checkMasterConfigs,
|
|
1439
1455
|
checkGeneratedProjectRuntimeAssets,
|
|
@@ -1494,8 +1510,31 @@ export const doctorCommand = new Command("doctor")
|
|
|
1494
1510
|
// When Tilt is up, surface red resources (Traefik/apps never started).
|
|
1495
1511
|
requiresContainerRuntime("Tilt Resources", checkTiltResourceHealth),
|
|
1496
1512
|
];
|
|
1513
|
+
const machineChecks = nativeResources
|
|
1514
|
+
? [
|
|
1515
|
+
() => checkNativeRuntime(nativeResources),
|
|
1516
|
+
() => checkNativeCommands(nativeResources),
|
|
1517
|
+
() => checkWslProjectLocation(findProjectRoot() ?? process.cwd(), options.strict),
|
|
1518
|
+
() => checkDuplicateFliskInstalls(),
|
|
1519
|
+
]
|
|
1520
|
+
: containerMachineChecks;
|
|
1521
|
+
const projectChecks = nativeResources
|
|
1522
|
+
? [
|
|
1523
|
+
() => checkFliskVersion(),
|
|
1524
|
+
() => checkDuplicateResourceNames(),
|
|
1525
|
+
() => checkDependsOnShape(),
|
|
1526
|
+
() => checkNativeDependsOn(nativeResources),
|
|
1527
|
+
() => checkCircularDependencies(),
|
|
1528
|
+
() => checkServicePorts(),
|
|
1529
|
+
() => checkSchemaVersions(undefined, options.strict),
|
|
1530
|
+
() => checkDuplicateResourcePorts(),
|
|
1531
|
+
]
|
|
1532
|
+
: containerProjectChecks;
|
|
1533
|
+
if (options.ping && nativeResources && projectRoot) {
|
|
1534
|
+
projectChecks.push(() => checkNativeServiceHealth(projectRoot, nativeResources, pingTimeout));
|
|
1535
|
+
}
|
|
1497
1536
|
// Runs last: needs routable services (and working Traefik) to mean anything.
|
|
1498
|
-
if (options.ping) {
|
|
1537
|
+
if (options.ping && !nativeResources) {
|
|
1499
1538
|
// Probe the port a running stack is actually on, not the one the next `flisk up` would pick.
|
|
1500
1539
|
const pingPort = projectRoot
|
|
1501
1540
|
? resolveRuntimeIngressPort(projectRoot, hostPortPlan?.ingressHttp)
|
|
@@ -8,8 +8,10 @@ import { pruneProjectNetworks, stopProjectTiltUp, waitForTiltUpExit, } from "../
|
|
|
8
8
|
import { errorFactories, handleTiltFailure, withTiltCheck } from "../utils/errors.js";
|
|
9
9
|
import { createJsonEmitter } from "../utils/json-output.js";
|
|
10
10
|
import { writeMachineError } from "../utils/machine-output.js";
|
|
11
|
+
import { readNativeRunState, stopNativeRun } from "../utils/native-runtime.js";
|
|
12
|
+
import { isNativeProject } from "../utils/native-service.js";
|
|
11
13
|
import { findProjectRoot } from "../utils/paths.js";
|
|
12
|
-
import { discoverResources, discoverStacks } from "../utils/services.js";
|
|
14
|
+
import { discoverResources, discoverResourcesFromRoot, discoverStacks } from "../utils/services.js";
|
|
13
15
|
import { buildTiltDownArgs, getTiltfilePath, runTilt } from "../utils/tilt.js";
|
|
14
16
|
function allStackNames() {
|
|
15
17
|
try {
|
|
@@ -20,6 +22,17 @@ function allStackNames() {
|
|
|
20
22
|
return undefined;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
25
|
+
/** True when `flisk down` stops local processes instead of Tilt: a native run is on record, or every service declares `command`. */
|
|
26
|
+
function isNativeRun(projectRoot) {
|
|
27
|
+
if (readNativeRunState(projectRoot))
|
|
28
|
+
return true;
|
|
29
|
+
try {
|
|
30
|
+
return isNativeProject(discoverResourcesFromRoot(projectRoot));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
23
36
|
function pruneNetworksOrWarn(json) {
|
|
24
37
|
const root = findProjectRoot();
|
|
25
38
|
if (!root)
|
|
@@ -64,6 +77,25 @@ export const downCommand = addYesOption(new Command("down"))
|
|
|
64
77
|
}
|
|
65
78
|
}
|
|
66
79
|
const emit = options.json ? createJsonEmitter("DOWN_FAILED", "flisk down") : undefined;
|
|
80
|
+
// A project of `command` services (or one with a native run on record) stops without Docker or Tilt.
|
|
81
|
+
const projectRoot = findProjectRoot();
|
|
82
|
+
if (isNativeRun(projectRoot)) {
|
|
83
|
+
if (emit && options.dryRun) {
|
|
84
|
+
emit({ ok: true, dryRun: true, runtime: "native" });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (handleDryRun(options, "not stopping local processes", "stop the local processes of this project")) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const stopped = await stopNativeRun(projectRoot);
|
|
91
|
+
if (!options.json) {
|
|
92
|
+
console.log(stopped.wasRunning
|
|
93
|
+
? chalk.blue(`Stopped local processes: ${stopped.services.join(", ")}`)
|
|
94
|
+
: chalk.gray("Nothing is running for this project."));
|
|
95
|
+
}
|
|
96
|
+
emit?.({ ok: true, runtime: "native", stopped: stopped.services });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
67
99
|
await withTiltCheck(async () => {
|
|
68
100
|
if (emit && options.dryRun) {
|
|
69
101
|
emit({ ok: true, dryRun: true });
|
|
@@ -4,10 +4,13 @@ import { Command } from "commander";
|
|
|
4
4
|
import { STANDARD_PORTS } from "../utils/constants.js";
|
|
5
5
|
import { errorFactories, FliskError, runCommand, showErrorAndExit } from "../utils/errors.js";
|
|
6
6
|
import { createMachineEnvelope } from "../utils/machine-output.js";
|
|
7
|
+
import { readNativeLogLines } from "../utils/native-runtime.js";
|
|
8
|
+
import { isNativeProject } from "../utils/native-service.js";
|
|
7
9
|
import { findProjectRoot } from "../utils/paths.js";
|
|
8
10
|
import { EnvUnreadableError, envSecretValues, redactSecrets, redactValue, } from "../utils/secret-redaction.js";
|
|
11
|
+
import { discoverResourcesFromRoot } from "../utils/services.js";
|
|
9
12
|
import { isTiltAvailable, runTilt } from "../utils/tilt.js";
|
|
10
|
-
import { DEFAULT_LOG_TAIL, isTiltConnectionFailure, isValidPort, isValidSince, isValidTail, MAX_LOG_TAIL, parseTiltLogLines, } from "../utils/tilt-logs.js";
|
|
13
|
+
import { DEFAULT_LOG_TAIL, isTiltConnectionFailure, isValidPort, isValidSince, isValidTail, MAX_LOG_TAIL, parseTiltLogLines, sinceMilliseconds, } from "../utils/tilt-logs.js";
|
|
11
14
|
import { tiltUnreachableMessage } from "../utils/tilt-unreachable-message.js";
|
|
12
15
|
/** Resource names Tilt knows about, or null when they cannot be listed (the logs call then reports the real error). */
|
|
13
16
|
async function tiltResourceNames(port) {
|
|
@@ -25,8 +28,20 @@ async function tiltResourceNames(port) {
|
|
|
25
28
|
return null;
|
|
26
29
|
}
|
|
27
30
|
}
|
|
31
|
+
/** The project's services when every one declares `command` (they run as local processes), else null. */
|
|
32
|
+
function nativeResources(projectRoot) {
|
|
33
|
+
try {
|
|
34
|
+
const resources = discoverResourcesFromRoot(projectRoot);
|
|
35
|
+
return isNativeProject(resources) ? resources : null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Discovery problems are reported by the commands that start the stack; logs still asks Tilt.
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
28
42
|
export const logsCommand = new Command("logs")
|
|
29
43
|
.description("Print a bounded snapshot of recent logs from the running stack")
|
|
44
|
+
.showHelpAfterError("\nService names are not positional. Use: flisk logs --service <name>")
|
|
30
45
|
.option("-s, --service <names...>", "Only these services (Tilt resource names)")
|
|
31
46
|
.option("--tail <n>", "Number of most recent lines to return", String(DEFAULT_LOG_TAIL))
|
|
32
47
|
.option("--since <duration>", "Only logs newer than this duration, for example 30s, 5m, 1h")
|
|
@@ -80,6 +95,29 @@ export const logsCommand = new Command("logs")
|
|
|
80
95
|
"Fix the read permission on .env, or move it out of the project",
|
|
81
96
|
]);
|
|
82
97
|
}
|
|
98
|
+
// A project of `command` services keeps its output in .flisk/native/logs, so no Tilt is involved.
|
|
99
|
+
const resources = nativeResources(projectRoot);
|
|
100
|
+
if (resources) {
|
|
101
|
+
const known = resources.map((resource) => resource.name);
|
|
102
|
+
const unknown = services.filter((name) => !known.includes(name));
|
|
103
|
+
if (unknown.length > 0) {
|
|
104
|
+
const error = errorFactories.unknownServices(unknown, known);
|
|
105
|
+
fail("UNKNOWN_SERVICE", error.message, error.exitCode, error.suggestions);
|
|
106
|
+
}
|
|
107
|
+
const lines = readNativeLogLines(projectRoot, services.length > 0 ? services : known, {
|
|
108
|
+
tail,
|
|
109
|
+
sinceMs: options.since === undefined ? undefined : sinceMilliseconds(options.since),
|
|
110
|
+
});
|
|
111
|
+
if (options.json) {
|
|
112
|
+
console.log(JSON.stringify(redactValue(createMachineEnvelope({ services, tail, since: options.since ?? null, lines }), secrets)));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const width = Math.max(0, ...lines.map((line) => line.resource.length));
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
console.log(redactSecrets(`${line.resource.padEnd(width)} | ${line.text}`, secrets));
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
83
121
|
if (!(await isTiltAvailable())) {
|
|
84
122
|
fail("TILT_MISSING", "Tilt is not installed. Run: flisk doctor");
|
|
85
123
|
}
|
|
@@ -213,7 +213,19 @@ const DEFAULT_PROJECT_JSON = {
|
|
|
213
213
|
},
|
|
214
214
|
overrides: {},
|
|
215
215
|
};
|
|
216
|
+
/**
|
|
217
|
+
* Writes .flisk/project.json with the defaults `flisk project --yes` uses, and nothing else: no generated Tiltfile, Compose file,
|
|
218
|
+
* .env or engine copy. `flisk up` uses it to adopt a directory of `command` services as a project, so `flisk down` and
|
|
219
|
+
* `flisk doctor` find it afterwards.
|
|
220
|
+
*/
|
|
221
|
+
export function writeDefaultProjectConfig(projectRoot) {
|
|
222
|
+
const projectConfig = JSON.parse(JSON.stringify(DEFAULT_PROJECT_JSON));
|
|
223
|
+
projectConfig.project.name = basename(projectRoot) || "my-project";
|
|
224
|
+
ensureDirectory(join(projectRoot, ".flisk"));
|
|
225
|
+
writeJsonFile(join(projectRoot, ".flisk", PROJECT_JSON), projectConfig);
|
|
226
|
+
}
|
|
216
227
|
export const projectCommand = addYesOption(new Command("project"))
|
|
228
|
+
.alias("init")
|
|
217
229
|
.description("Initialize or validate project-level master configuration")
|
|
218
230
|
.argument("[template]", `Clone a starter example instead of a blank project (${Object.keys(PROJECT_TEMPLATES).join(", ")})`)
|
|
219
231
|
.option("--path <dir>", "Directory to clone the template into (default: the template's repo name)")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) 2026 Flisk Landscape contributors
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
import { existsSync, mkdirSync } from "node:fs";
|
|
4
|
-
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { DEFAULT_AGENT_RUNTIME, resolveAgentDurability, resolveAgentRuntime, } from "../agent-runtimes/registry.js";
|
|
@@ -90,7 +90,7 @@ export function resolveResourcePort(resourceType, value, assignedPort, resources
|
|
|
90
90
|
}
|
|
91
91
|
return port;
|
|
92
92
|
}
|
|
93
|
-
export function createServiceJson(name, type, stack, port, extraFeatures = [], frameworkId, languageId, agent) {
|
|
93
|
+
export function createServiceJson(name, type, stack, port, extraFeatures = [], frameworkId, languageId, agent, basePath) {
|
|
94
94
|
const framework = resolveFrontendFramework(type, frameworkId);
|
|
95
95
|
// Only an explicit selection is persisted: a missing `language` has always meant Bun.
|
|
96
96
|
const language = languageId === undefined ? undefined : resolveBackendLanguage(type, languageId);
|
|
@@ -129,11 +129,15 @@ export function createServiceJson(name, type, stack, port, extraFeatures = [], f
|
|
|
129
129
|
stack,
|
|
130
130
|
port,
|
|
131
131
|
...(framework ? { framework: framework.id } : {}),
|
|
132
|
+
// A server framework (Next.js) is served under /<name>/ with a base path, so the engine's default /health probe finds
|
|
133
|
+
// nothing there. Probe the framework's own health route under the same prefix.
|
|
134
|
+
...(framework?.kind === "server" ? { healthCheckPath: `/${name}/health` } : {}),
|
|
132
135
|
...(backendFramework && type !== "mcp" && type !== "agent"
|
|
133
136
|
? { framework: backendFramework.id }
|
|
134
137
|
: {}),
|
|
135
138
|
...(language ? { language: language.id } : {}),
|
|
136
139
|
...(type === "agent" && agent ? { agent } : {}),
|
|
140
|
+
...(type === "frontend" && basePath ? { basePath } : {}),
|
|
137
141
|
};
|
|
138
142
|
}
|
|
139
143
|
export function createByoServiceJson(name, stack, port, options) {
|
|
@@ -173,20 +177,26 @@ export function createPackageJson(name, type, frameworkId, prismaEnabled = false
|
|
|
173
177
|
version: "0.0.1",
|
|
174
178
|
type: "module",
|
|
175
179
|
scripts: {
|
|
176
|
-
...(isFrontend
|
|
180
|
+
...(isFrontend && !framework?.scripts
|
|
177
181
|
? {
|
|
178
182
|
predev: requireGeneratedViteConfig(`${AUTOGENERATED_DIR}/vite.config.frontend.autogenerated.ts`),
|
|
179
183
|
prebuild: requireGeneratedViteConfig(`${AUTOGENERATED_DIR}/vite.config.build.autogenerated.ts`),
|
|
180
184
|
}
|
|
181
185
|
: {}),
|
|
182
186
|
dev: isFrontend
|
|
183
|
-
?
|
|
187
|
+
? (framework?.scripts?.dev ??
|
|
188
|
+
`vite --config ${AUTOGENERATED_DIR}/vite.config.frontend.autogenerated.ts`)
|
|
184
189
|
: "bun run --watch src/index.ts",
|
|
185
190
|
build: isFrontend
|
|
186
|
-
?
|
|
191
|
+
? (framework?.scripts?.build ??
|
|
192
|
+
`tsc && vite build --config ${AUTOGENERATED_DIR}/vite.config.build.autogenerated.ts`)
|
|
187
193
|
: "tsc",
|
|
188
|
-
// Backends and workers run `start` in their production image; doctor checks for it.
|
|
189
|
-
...(isFrontend
|
|
194
|
+
// Backends and workers run `start` in their production image; doctor checks for it. A server framework brings its own.
|
|
195
|
+
...(isFrontend
|
|
196
|
+
? framework?.scripts?.start
|
|
197
|
+
? { start: framework.scripts.start }
|
|
198
|
+
: {}
|
|
199
|
+
: { start: "bun run dist/index.js" }),
|
|
190
200
|
test: "vitest",
|
|
191
201
|
lint: "biome check .",
|
|
192
202
|
"lint:fix": "biome check . --write",
|
|
@@ -220,7 +230,7 @@ export function createPackageJson(name, type, frameworkId, prismaEnabled = false
|
|
|
220
230
|
"@biomejs/biome": "^2.5.13",
|
|
221
231
|
// vitest 5 peers on vite ^6.4.0 || ^7 || ^8; vite 5 makes `vitest run` fail at startup with
|
|
222
232
|
// ERR_PACKAGE_PATH_NOT_EXPORTED ('./module-runner'), in every resource once it is hoisted.
|
|
223
|
-
...(isFrontend ? { vite: "^6.4.1" } : {}),
|
|
233
|
+
...(isFrontend && !framework?.scripts ? { vite: "^6.4.1" } : {}),
|
|
224
234
|
...(drizzleEnabled ? { "drizzle-kit": DRIZZLE_KIT_RANGE, "@types/pg": "^8.11.0" } : {}),
|
|
225
235
|
...(framework?.devDependencies ?? {}),
|
|
226
236
|
...(backendFramework?.devDependencies ?? {}),
|
|
@@ -269,6 +279,9 @@ export default defineConfig({
|
|
|
269
279
|
`;
|
|
270
280
|
export function createResourceTsconfig(resourceType, frameworkId) {
|
|
271
281
|
const framework = resolveFrontendFramework(resourceType, frameworkId);
|
|
282
|
+
// A server framework (Next.js) owns its compiler settings: the SPA template's `rootDir`, `outDir` and declaration output do not apply.
|
|
283
|
+
if (framework?.tsconfig)
|
|
284
|
+
return framework.tsconfig;
|
|
272
285
|
const backendFramework = resolveBackendFramework(resourceType, frameworkId);
|
|
273
286
|
return {
|
|
274
287
|
...TSCONFIG_TEMPLATE,
|
|
@@ -380,7 +393,7 @@ export const resourceCommand = addYesOption(new Command("resource"))
|
|
|
380
393
|
.description("Create a new resource (service) from scratch, or register an existing one")
|
|
381
394
|
.argument("[name]", "Resource name (kebab-case)")
|
|
382
395
|
.option("-t, --type <type>", "Resource type: backend, frontend, worker, mcp, agent, bring-your-own, sdk", "backend")
|
|
383
|
-
.option("--framework <id>", "Framework: frontend react (default), vue, svelte, preact, lit, solid, qwik, vanilla, tanstack-router; backend hono (default), express, elysia, fastify, nestjs, koa, h3 (list them with --frameworks)")
|
|
396
|
+
.option("--framework <id>", "Framework: frontend react (default), vue, svelte, preact, lit, solid, qwik, vanilla, tanstack-router, next; backend hono (default), express, elysia, fastify, nestjs, koa, h3 (list them with --frameworks)")
|
|
384
397
|
.option("--frameworks", "List registered frameworks for the resource type and exit (--type frontend, --type backend)")
|
|
385
398
|
.option("--language <id>", "Backend language: bun (default), python, go, rust, node")
|
|
386
399
|
.option("-s, --stack <stack>", "Stack to assign resource to", "default")
|
|
@@ -394,6 +407,7 @@ export const resourceCommand = addYesOption(new Command("resource"))
|
|
|
394
407
|
.option("--restart <policy>", "Compose restart policy: no, on-failure, unless-stopped, always (bring-your-own only; use no for one-shot jobs)")
|
|
395
408
|
.option("--image <name>", "Docker image name instead of building from Dockerfile (for bring-your-own)")
|
|
396
409
|
.option("--port <port>", "Port for the resource, within its type's range (default: next free port in that range)")
|
|
410
|
+
.option("--base-path <path>", "Base path for frontend routing (e.g., /storefront). Default is /{stack}s. Frontend only.")
|
|
397
411
|
.option("--feature <feature...>", "Enable a resource feature (for example: prisma, drizzle)")
|
|
398
412
|
.option("--runtime <id>", "Agent runtime (for agent only): custom (default)")
|
|
399
413
|
.option("--durability <kind>", "Where agent sessions are checkpointed (for agent only): files (default, named volume) or postgres")
|
|
@@ -757,6 +771,10 @@ This file contains the resource configuration for Flisk.
|
|
|
757
771
|
}
|
|
758
772
|
if (resourceType === "frontend") {
|
|
759
773
|
mkdirSync(resolve(fullPath, "public"), { recursive: true });
|
|
774
|
+
// A framework can keep its files in folders of its own (Next.js: src/app).
|
|
775
|
+
for (const file of frontendFramework?.createFiles(resourceName) ?? []) {
|
|
776
|
+
mkdirSync(dirname(resolve(fullPath, file.filename)), { recursive: true });
|
|
777
|
+
}
|
|
760
778
|
}
|
|
761
779
|
if (dddEnabled) {
|
|
762
780
|
for (const layer of ["domain", "application", "infrastructure", "presentation"]) {
|
|
@@ -766,11 +784,19 @@ This file contains the resource configuration for Flisk.
|
|
|
766
784
|
// Prepare file generation tasks
|
|
767
785
|
const prismaEnabled = requestedFeatures.includes("prisma");
|
|
768
786
|
const drizzleEnabled = requestedFeatures.includes("drizzle");
|
|
769
|
-
const serviceJson = createServiceJson(resourceName, resourceType, stackName, assignedPort, [...(dddEnabled ? ["ddd"] : []), ...requestedFeatures], scaffoldFrameworkId, options.language === undefined ? undefined : backendLanguage?.id, agentConfig);
|
|
787
|
+
const serviceJson = createServiceJson(resourceName, resourceType, stackName, assignedPort, [...(dddEnabled ? ["ddd"] : []), ...requestedFeatures], scaffoldFrameworkId, options.language === undefined ? undefined : backendLanguage?.id, agentConfig, resourceType === "frontend" ? options.basePath : undefined);
|
|
770
788
|
const packageJson = createPackageJson(resourceName, resourceType, scaffoldFrameworkId, prismaEnabled, agentConfig, drizzleEnabled);
|
|
771
789
|
if (prismaEnabled && resourceType === "backend") {
|
|
772
790
|
serviceJson.dependsOn = [`${resourceName}-migrator`];
|
|
773
791
|
}
|
|
792
|
+
// A frontend is wired to the first backend already in its stack, so its starter can call that API out of the box.
|
|
793
|
+
const frontendBackendName = resourceType === "frontend"
|
|
794
|
+
? allResources.find((resource) => resource.stack === stackName && resource.type === "backend")?.name
|
|
795
|
+
: undefined;
|
|
796
|
+
if (frontendBackendName) {
|
|
797
|
+
serviceJson.backendName = frontendBackendName;
|
|
798
|
+
serviceJson.dependsOn = [frontendBackendName];
|
|
799
|
+
}
|
|
774
800
|
const tasks = [
|
|
775
801
|
{
|
|
776
802
|
type: "json",
|
|
@@ -829,7 +855,9 @@ This file contains the resource configuration for Flisk.
|
|
|
829
855
|
});
|
|
830
856
|
}
|
|
831
857
|
else if (resourceType === "frontend") {
|
|
832
|
-
tasks.push(...(frontendFramework
|
|
858
|
+
tasks.push(...(frontendFramework
|
|
859
|
+
?.createFiles(resourceName, { backendName: frontendBackendName })
|
|
860
|
+
.map((file) => ({
|
|
833
861
|
...file,
|
|
834
862
|
type: "text",
|
|
835
863
|
})) ?? []));
|
|
@@ -8,6 +8,8 @@ import { runCommand } from "../utils/errors.js";
|
|
|
8
8
|
import { formatCount, showDetail, showStep } from "../utils/formatting.js";
|
|
9
9
|
import { getHostPortPlan } from "../utils/host-port-config.js";
|
|
10
10
|
import { createMachineEnvelope, writeMachineError } from "../utils/machine-output.js";
|
|
11
|
+
import { nativeServiceStates } from "../utils/native-runtime.js";
|
|
12
|
+
import { isNativeProject } from "../utils/native-service.js";
|
|
11
13
|
import { findProjectRoot } from "../utils/paths.js";
|
|
12
14
|
import { deriveServiceStates } from "../utils/service-runtime-state.js";
|
|
13
15
|
import { groupSharedPostgres, readProjectName } from "../utils/shared-infra.js";
|
|
@@ -31,19 +33,30 @@ export const statusCommand = new Command("status")
|
|
|
31
33
|
const sharedInfraGroup = projectName
|
|
32
34
|
? groupSharedPostgres(projectName, discovery.stacks)
|
|
33
35
|
: null;
|
|
36
|
+
// A project of `command` services runs as local processes: its state comes from the run on record, not from Tilt.
|
|
37
|
+
const nativeStates = projectRoot && isNativeProject(discovery.resources)
|
|
38
|
+
? nativeServiceStates(projectRoot, discovery.resources.map((resource) => resource.name))
|
|
39
|
+
: null;
|
|
34
40
|
let tiltAvailable = false;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (!nativeStates) {
|
|
42
|
+
try {
|
|
43
|
+
tiltAvailable = await isTiltAvailable();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Tilt not available (spawn error)
|
|
47
|
+
tiltAvailable = false;
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
if (!options.json) {
|
|
43
51
|
showStep("Flisk Status\n");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
if (nativeStates) {
|
|
53
|
+
console.log(chalk.bold("Runtime:"), "local processes (no Docker, no Tilt)");
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(chalk.bold("Tilt:"), tiltAvailable ? chalk.green("available") : chalk.red("not found"));
|
|
57
|
+
if (!tiltAvailable) {
|
|
58
|
+
showDetail("Install Tilt: https://docs.tilt.dev/install.html");
|
|
59
|
+
}
|
|
47
60
|
}
|
|
48
61
|
console.log();
|
|
49
62
|
}
|
|
@@ -53,8 +66,17 @@ export const statusCommand = new Command("status")
|
|
|
53
66
|
// Tilt answers or its output cannot be read.
|
|
54
67
|
let readiness = null;
|
|
55
68
|
// The same look at Tilt feeds readiness and each service's state, so `flisk status` and `flisk ui` cannot disagree.
|
|
56
|
-
let serviceStates =
|
|
69
|
+
let serviceStates = nativeStates;
|
|
57
70
|
const tiltPort = getTiltPollingPort(process.env.TILT_PORT);
|
|
71
|
+
// Port plan is best effort; service URLs are shown in both JSON and terminal output.
|
|
72
|
+
let portPlan = null;
|
|
73
|
+
try {
|
|
74
|
+
const root = findProjectRoot();
|
|
75
|
+
portPlan = root ? await getHostPortPlan(root, { inspectDocker: false }) : null;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Port planning failed; service URLs will be omitted from terminal output.
|
|
79
|
+
}
|
|
58
80
|
if (tiltAvailable) {
|
|
59
81
|
const text = await tiltGetUiResources(tiltPort);
|
|
60
82
|
// `tilt get` has no -f flag; resources come from the running Tilt's API on its port, the same source as readiness.
|
|
@@ -89,16 +111,24 @@ export const statusCommand = new Command("status")
|
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
if (options.json) {
|
|
92
|
-
let portPlan = null;
|
|
93
|
-
try {
|
|
94
|
-
const root = findProjectRoot();
|
|
95
|
-
portPlan = root ? await getHostPortPlan(root, { inspectDocker: false }) : null;
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
// Port planning is best effort; stack ports then list only the Tilt UI.
|
|
99
|
-
}
|
|
100
114
|
const errors = queryError ? [{ code: "TILT_STATUS_UNAVAILABLE", message: queryError }] : [];
|
|
115
|
+
// A native run answers the readiness question agents poll (data.tilt.readiness.ready) from its own run state.
|
|
116
|
+
if (nativeStates) {
|
|
117
|
+
const states = Object.entries(nativeStates);
|
|
118
|
+
const isRunning = states.some(([, state]) => state.status !== "unknown");
|
|
119
|
+
readiness = isRunning
|
|
120
|
+
? {
|
|
121
|
+
ready: states.every(([, state]) => state.status === "ready"),
|
|
122
|
+
failures: [],
|
|
123
|
+
pending: states.filter(([, state]) => state.status !== "ready").length,
|
|
124
|
+
timedOut: false,
|
|
125
|
+
enabled: states.map(([name]) => name),
|
|
126
|
+
}
|
|
127
|
+
: null;
|
|
128
|
+
}
|
|
101
129
|
const data = {
|
|
130
|
+
// Only a project of local processes says so; a container project's report keeps its shape.
|
|
131
|
+
...(nativeStates ? { runtime: "native" } : {}),
|
|
102
132
|
tilt: {
|
|
103
133
|
available: tiltAvailable,
|
|
104
134
|
resourcesQueried: options.tilt && tiltAvailable,
|
|
@@ -178,9 +208,17 @@ export const statusCommand = new Command("status")
|
|
|
178
208
|
: state.status === "error"
|
|
179
209
|
? chalk.red("✗")
|
|
180
210
|
: chalk.yellow("…");
|
|
181
|
-
|
|
211
|
+
const ports = buildServicePorts(resource, portPlan?.ingressHttp);
|
|
212
|
+
const urlPart = ports.url ? ` → ${ports.url}` : "";
|
|
213
|
+
showDetail(`${mark} ${resource.name}${urlPart} ${state.status}${state.reason ? ` (${state.reason})` : ""}`);
|
|
182
214
|
}
|
|
183
215
|
}
|
|
216
|
+
else if (discovery.resources.length > 0) {
|
|
217
|
+
// Without a running Tilt, no service state can be read. Say so instead of printing nothing.
|
|
218
|
+
console.log();
|
|
219
|
+
console.log(chalk.bold("Services:"));
|
|
220
|
+
showDetail(`unknown: no Tilt answers on port ${tiltPort}, so nothing is confirmed running. Start with: flisk up`);
|
|
221
|
+
}
|
|
184
222
|
if (options.tilt && tiltAvailable) {
|
|
185
223
|
console.log();
|
|
186
224
|
showStep("Tilt Resources:");
|