{"_id":"@cvhome-saas/lcl","name":"@cvhome-saas/lcl","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@cvhome-saas/lcl","version":"0.1.0","description":"Run, supervise, inspect, and port-shift complex local microservice stacks from one lcl.yml.","keywords":["microservices","local-development","process-supervisor","docker-compose","dev-tools"],"license":"Apache-2.0","author":{"name":"cvhome-saas contributors"},"type":"module","bin":{"lcl":"bin/lcl.js"},"repository":{"type":"git","url":"git+https://github.com/cvhome-saas/lcl.git"},"bugs":{"url":"https://github.com/cvhome-saas/lcl/issues"},"homepage":"https://github.com/cvhome-saas/lcl#readme","engines":{"node":">=22"},"scripts":{"clean":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"","build":"tsc -p tsconfig.json","check":"tsc --noEmit -p tsconfig.json","test":"npm run build && node --test dist/test/*.test.js","prepack":"npm run clean && npm run build && npm test"},"dependencies":{"ajv":"8.20.0","yaml":"2.9.0"},"devDependencies":{"@types/node":"22.20.1","typescript":"7.0.2"},"publishConfig":{"access":"public"},"_id":"@cvhome-saas/lcl@0.1.0","gitHead":"d4079d405be57df4695eef4042117c5b2cb5e5ab","_nodeVersion":"23.11.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-c1jOxTqKXCr1mdr+CNUMCQR34UWaI1gvtVFQOF1Rnf2GRpmouk5C3FnDp50BoxAATfxB8+WRXV5UJA3dPTZmuQ==","shasum":"843d13dbd08c99d00d00a7e8e5ce9cab98761a97","tarball":"https://registry.npmjs.org/@cvhome-saas/lcl/-/lcl-0.1.0.tgz","fileCount":90,"unpackedSize":312512,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDxQQtl8a54WDahn0ToCH0wMANpRFrl13ufaH/GYYvhLQIhAP/P3po3CdneGjGK5DYeJ8v1AMhVw0J45mYRmaSDJcEq"}]},"_npmUser":{"name":"asrevo","email":"me@asrevo.com"},"directories":{},"maintainers":[{"name":"asrevo","email":"me@asrevo.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lcl_0.1.0_1787681282169_0.7918478052178943"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-25T18:08:02.045Z","0.1.0":"2026-08-25T18:08:02.322Z","modified":"2026-08-25T18:08:02.532Z"},"maintainers":[{"name":"asrevo","email":"me@asrevo.com"}],"description":"Run, supervise, inspect, and port-shift complex local microservice stacks from one lcl.yml.","homepage":"https://github.com/cvhome-saas/lcl#readme","keywords":["microservices","local-development","process-supervisor","docker-compose","dev-tools"],"repository":{"type":"git","url":"git+https://github.com/cvhome-saas/lcl.git"},"author":{"name":"cvhome-saas contributors"},"bugs":{"url":"https://github.com/cvhome-saas/lcl/issues"},"license":"Apache-2.0","readme":"# lcl\n\n`lcl` runs a complex local stack from one `lcl.yml`. It allocates a stable set of ports, starts dependencies in\nreadiness order, supervises foreground processes, manages optional Docker Compose infrastructure, and keeps logs and\nstate for several named stacks at once.\n\nThe runner is language-neutral. If a service can be launched as a foreground command, `lcl` can supervise it.\n\n## Install\n\nNode.js 22 or newer is required. macOS, Linux, and WSL2 are supported.\n\n```bash\nnpm install -g @cvhome-saas/lcl\nlcl --version\n```\n\nCreate a starter configuration:\n\n```bash\nlcl init --template empty\n# also available: node, python, java, compose\nlcl validate\n```\n\n`lcl init` adds `.lcl/` to `.gitignore`. The only project configuration owned by the CLI is `lcl.yml`; runtime\nstate stays under `.lcl/<stack>/`.\n\n## A small stack\n\n```yaml\nversion: 1\nname: shop\n\nports:\n  step: 1000\n\ncompose:\n  files: [compose.yml]\n  default: [postgres]\n\nservices:\n  catalog:\n    cwd: services/catalog\n    command: [python, -m, uvicorn, app:app, --port, \"${port.catalog.http}\"]\n    depends-on: [postgres]\n    ports:\n      http: 8080\n    health:\n      type: http\n      port: http\n      path: /health\n\n  storefront:\n    cwd: apps/storefront\n    prepare:\n      - [npm, run, build:libs]\n    command: [npm, run, dev, \"--\", --port, \"${port.storefront.http}\"]\n    depends-on: [catalog]\n    ports:\n      http: 3000\n    environment:\n      CATALOG_URL: \"http://localhost:${port.catalog.http}\"\n    health:\n      type: http\n      port: http\n      path: /\n\nurls:\n  - { label: storefront, url: \"http://localhost:${port.storefront.http}\" }\n```\n\n```bash\nlcl start -d                         # start everything and return when ready\nlcl start storefront -d              # also starts catalog and postgres\nlcl status\nlcl urls\nlcl logs catalog -f\nlcl why catalog\nlcl restart catalog\nlcl stop\n```\n\n## Generic service contract\n\nEach entry in `services` is a foreground process:\n\n| Key | Meaning |\n|---|---|\n| `command` | Argument array executed without a shell. Preferred because quoting is unambiguous. |\n| `shell` | Explicit POSIX shell command for pipelines or shell expansion. Mutually exclusive with `command`. |\n| `cwd` | Working directory relative to `lcl.yml`. Defaults to the configuration directory. |\n| `prepare` | Commands run to completion before each service start. Entries may be argv arrays or command objects. |\n| `depends-on` | Source or Compose services that must be ready first. Transitive dependencies start automatically. |\n| `ports` | Any number of named TCP ports. All are shifted together when the configured sequence is occupied. |\n| `environment` | Environment values, with variable interpolation. |\n| `health` | `http`, `tcp`, `log`, or `process`; defaults to TCP for a service with ports and process-alive otherwise. |\n\nExamples for common ecosystems use the same fields:\n\n```yaml\nservices:\n  spring:\n    command: [./gradlew, :api:bootRun, \"--args=--server.port=${port.spring.http}\"]\n    ports: { http: 8080 }\n\n  maven:\n    command: [./mvnw, -pl, billing, spring-boot:run, \"-Dspring-boot.run.arguments=--server.port=${port.maven.http}\"]\n    ports: { http: 8081 }\n\n  go:\n    command: [go, run, ./cmd/api]\n    environment: { PORT: \"${port.go.http}\" }\n    ports: { http: 8082 }\n\n  rust:\n    command: [cargo, run, --bin, worker]\n    environment: { PORT: \"${port.rust.http}\" }\n    ports: { http: 8083 }\n\n  worker:\n    command: [python, worker.py]\n    health: { type: log, ready-log: \"worker ready\", timeout: 30 }\n```\n\nPortless workers, file watchers, tunnels, webhook listeners, and similar tools are supervised like servers. They\ncan reference the complete allocated port map, but should not declare a port unless they actually listen on it. See\nthe runnable [`examples/long-running-tools`](examples/long-running-tools) example for log readiness, dependency\nordering, cross-service forwarding, and automatic `.env` injection.\n\nThe complete configuration contract is [`schema/lcl.schema.json`](schema/lcl.schema.json). Unknown keys and invalid\ncombinations fail during `lcl validate`, before any process or container is started.\n\n## Named stacks and ports\n\nThe configured ports are used when available. If one is occupied, the whole stack moves by `ports.step` until every\ndeclared source port and selected Compose port is free.\n\n```bash\nlcl start -d\nlcl start -d --stack feature-x\nlcl ports --stack feature-x\nlcl urls --stack feature-x\nlcl stop --stack feature-x\n```\n\nUseful policies:\n\n- `--ports configured`: require the configured ports and fail on a collision.\n- `--ports shift`: always start at the first shifted sequence.\n- `--ports offset=2`: force `2 × ports.step`.\n- `ports.skip-configured: true`: make shifted ports the project default.\n\nVariables available in commands, environment, hooks, generated files, and URLs include:\n\n- `${stack}`, `${stack.dir}`, `${root}`, `${project}`, `${offset}`, `${service}`, `${port}`\n- `${port.<service>.<name>}` for source services\n- `${port.<compose-service>.<container-port>}` for Compose services\n- `${env.NAME}` for an environment value supplied to the `lcl` process\n\nEvery assigned port is also exported as an uppercase `LCL_PORT_*` environment variable. `lcl ports --env` prints the\nexact variables and resolved URLs for shell use.\n\n### Project `.env`\n\nIf a `.env` file exists beside `lcl.yml`, LCL parses it with Node's dotenv rules and injects its values as defaults\ninto source services, `prepare` commands, the optional build command, and hooks. This supports programs that do not\nload dotenv files themselves. No configuration field is required.\n\nExisting host variables override `.env`; generated `LCL_*` variables and explicit global or service `environment`\nvalues override both. `${env.NAME}` remains an explicit lookup of the environment supplied to the `lcl` process.\nLCL does not expand variable references inside `.env`, and Compose environment remains controlled by Compose and\n`compose.environment`. A running supervisor keeps the values loaded at stack start, so stop and start the stack to\nreload changes. Because `lcl why` shows resolved diagnostics, do not treat `.env` values as hidden output.\n\n## Docker Compose\n\nCompose is optional. When configured, `lcl` asks `docker compose config` for the canonical service and port model,\ncreates a per-stack port override, and uses an isolated project name. Containers with health checks wait for\n`healthy`; other containers wait for their published ports.\n\n```yaml\ncompose:\n  files: [compose.yml, compose.local.yml]\n  default: [postgres, redis]\n  environment:\n    POSTGRES_TAG: 17-alpine\n```\n\nUse `--infra all`, `--infra postgres,redis`, or `--no-infra` to override the default. `lcl stop --hard` also removes\nvolumes belonging to that exact Compose project.\n\n## Commands\n\n```text\nlcl start [service...] [-d] [--build] [--parallel N] [--fail-fast]\nlcl stop [service...] [--hard]\nlcl restart [service...]\nlcl status [--json]\nlcl urls\nlcl ports [--json|--env]\nlcl logs [service...] [-f] [-n N] [--since 10m] [--grep REGEX] [--errors]\nlcl events [-f] [--since 1h] [--service NAME] [--json]\nlcl why SERVICE\nlcl doctor\nlcl validate [--json]\nlcl list\nlcl clean [--all]\n```\n\n`lcl` only signals process groups it launched and can identify. A stale recorded port owned by another process is\nreported, never killed. Foreground programs should not daemonize themselves.\n\n## Development\n\n```bash\nnpm install\nnpm run check\nnpm test\nnpm pack --dry-run\n```\n\nCI tests Node.js 22 and 24 on Ubuntu and macOS. Docker-backed Compose tests run on Ubuntu. See\n[`CONTRIBUTING.md`](CONTRIBUTING.md) for the release workflow.\n\n## License\n\nApache License 2.0.\n","readmeFilename":"README.md","_rev":"1-1f186630070a6c2d22e309653eb241c6"}