{"_id":"@18ways/monorunner","_rev":"2-79fb47b11c469761969e3e1e62e5e49a","name":"@18ways/monorunner","dist-tags":{"alpha":"0.1.0-alpha.9ead1c973502","latest":"0.1.0"},"versions":{"0.1.0-alpha.9ead1c973502":{"name":"@18ways/monorunner","version":"0.1.0-alpha.9ead1c973502","keywords":["monorepo","developer-tools","local-development","process-manager","cli","terminal"],"author":{"name":"18ways"},"license":"MIT","_id":"@18ways/monorunner@0.1.0-alpha.9ead1c973502","maintainers":[{"name":"stephencookdev","email":"stephen@stephencookdev.co.uk"}],"homepage":"https://github.com/ways-labs/18ways/tree/main/packages/monorunner#readme","bugs":{"url":"https://github.com/ways-labs/18ways/issues"},"bin":{"monorunner":"dist/cli.js"},"dist":{"shasum":"b417a7d8bec7e29e65b3b53e42cd780a3086d0f0","tarball":"https://registry.npmjs.org/@18ways/monorunner/-/monorunner-0.1.0-alpha.9ead1c973502.tgz","fileCount":8,"integrity":"sha512-XAVCuOdRM9mMTg1QtNum1jQ3qJx2cRCT8p5Qt93dUxU44gO0BUgEb2QzJrLtLgKPgd2cGk5XzCIQRsAur9MDmQ==","signatures":[{"sig":"MEUCIBmD81Nezgc+4ITJmixLWeqbprnoEw6zzw3zUtsc2+XTAiEAqhvc8JnUehqU7XpQOx4PUdBaQU1xYmpMXH4XUqxTiPI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":140693},"type":"module","engines":{"node":">=20"},"exports":{"./plugin":{"types":"./dist/plugin.d.ts","import":"./dist/plugin.js","default":"./dist/plugin.js"}},"scripts":{"dev":"bun src/cli.ts","test":"bun run build && node dist/cli.js --help && node dist/cli.js --version","build":"bun build src/cli.ts --target=node --packages=external --outfile=dist/cli.js && bun build src/plugin.ts --target=node --format=esm --outfile=dist/plugin.js && tsc -p tsconfig.build.json && bun -e \"const p='dist/cli.js'; let s=await Bun.file(p).text(); s=s.replace(/^#!.*\\n\\/\\/ @bun\\n\\n/, '#!/usr/bin/env node\\n'); await Bun.write(p,s); require('node:fs').chmodSync(p, 0o755);\"","prepack":"bun run build"},"_npmUser":{"name":"stephencookdev","email":"stephen@stephencookdev.co.uk"},"repository":{"url":"git+https://github.com/ways-labs/18ways.git","type":"git","directory":"packages/monorunner"},"_npmVersion":"11.13.0","description":"Run and monitor local monorepo services from one terminal","directories":{},"_nodeVersion":"26.1.0","dependencies":{"ink":"5.2.1","pm2":"^6.0.10","execa":"^8.0.1","react":"18.3.1","pid-port":"^1.0.2","ink-text-input":"^6.0.0","get-port-please":"^3.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"bun@1.3.8","_npmOperationalInternal":{"tmp":"tmp/monorunner_0.1.0-alpha.9ead1c973502_1788543137055_0.4366438096416969","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@18ways/monorunner","version":"0.1.0","description":"Run and monitor local monorepo services from one terminal","type":"module","exports":{"./plugin":{"types":"./dist/plugin.d.ts","import":"./dist/plugin.js","default":"./dist/plugin.js"}},"bin":{"monorunner":"dist/cli.js"},"scripts":{"build":"bun build src/cli.ts --target=node --packages=external --outfile=dist/cli.js && bun build src/plugin.ts --target=node --format=esm --outfile=dist/plugin.js && tsc -p tsconfig.build.json && bun -e \"const p='dist/cli.js'; let s=await Bun.file(p).text(); s=s.replace(/^#!.*\\n\\/\\/ @bun\\n\\n/, '#!/usr/bin/env node\\n'); await Bun.write(p,s); require('node:fs').chmodSync(p, 0o755);\"","dev":"bun src/cli.ts","test":"bun run build && node dist/cli.js --help && node dist/cli.js --version","prepack":"bun run build"},"dependencies":{"execa":"^8.0.1","get-port-please":"^3.2.0","ink":"5.2.1","ink-text-input":"^6.0.0","pid-port":"^1.0.2","pm2":"^6.0.10","react":"18.3.1"},"keywords":["monorepo","developer-tools","local-development","process-manager","cli","terminal"],"author":{"name":"18ways"},"repository":{"type":"git","url":"git+https://github.com/ways-labs/18ways.git","directory":"packages/monorunner"},"homepage":"https://github.com/ways-labs/18ways/tree/main/packages/monorunner#readme","bugs":{"url":"https://github.com/ways-labs/18ways/issues"},"license":"MIT","engines":{"node":">=20"},"packageManager":"bun@1.3.8","publishConfig":{"access":"public"},"_id":"@18ways/monorunner@0.1.0","_nodeVersion":"26.1.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-SJtLzcR7XojOnJfrIgiAK6KUE/8CKFiVlr1px/ZgbPbYhRvWDK1YTXfdb6YnV1GfjxPNvLj5BMTgQI51YIZ3Rg==","shasum":"be75d5dcdaa13e263cbb87919ab397bcd70aa679","tarball":"https://registry.npmjs.org/@18ways/monorunner/-/monorunner-0.1.0.tgz","fileCount":8,"unpackedSize":140674,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAJyoUKjnP5LLpo/2IoGml2JcOPqdgNvrig9J73YQ8MRAiEAk+EqjS/irWmQhR8xSgQFTyiEJB8Kg1p7fuQGZAAVm4c="}]},"_npmUser":{"name":"stephencookdev","email":"stephen@stephencookdev.co.uk"},"directories":{},"maintainers":[{"name":"stephencookdev","email":"stephen@stephencookdev.co.uk"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/monorunner_0.1.0_1788543188146_0.8047416118344419"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-04T17:32:16.736Z","modified":"2026-09-04T17:33:08.535Z","0.1.0-alpha.9ead1c973502":"2026-09-04T17:32:17.272Z","0.1.0":"2026-09-04T17:33:08.304Z"},"bugs":{"url":"https://github.com/ways-labs/18ways/issues"},"author":{"name":"18ways"},"license":"MIT","homepage":"https://github.com/ways-labs/18ways/tree/main/packages/monorunner#readme","keywords":["monorepo","developer-tools","local-development","process-manager","cli","terminal"],"repository":{"type":"git","url":"git+https://github.com/ways-labs/18ways.git","directory":"packages/monorunner"},"description":"Run and monitor local monorepo services from one terminal","maintainers":[{"name":"stephencookdev","email":"stephen@stephencookdev.co.uk"}],"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ways-labs/18ways/main/packages/monorunner/assets/monorunner-banner-18ways.webp\" alt=\"monorunner\" width=\"1024\" />\n</p>\n\n<p align=\"center\">\n  Run, inspect, and stop the local services in a monorepo from one terminal.\n</p>\n\n<p align=\"center\">\n  <a href=\"#quick-start\">Quick start</a> · <a href=\"#configuration\">Configuration</a> · <a href=\"#tests\">Tests</a> · <a href=\"#plugins\">Plugins</a>\n</p>\n\n`monorunner` is an interactive local development runner for repositories with several services. Define the commands you already use in `dev.json`; Monorunner starts a named group, assigns ports where needed, shows their state and logs, and shuts the group down cleanly.\n\nIt runs on Node.js. Your services can use npm, pnpm, Yarn, Bun, or any other command available on your `PATH`.\n\n## Quick Start\n\nInstall it in the repository that owns your services:\n\n```bash\nnpm install --save-dev @18ways/monorunner\n```\n\n```bash\npnpm add -D @18ways/monorunner\n# or\nbun add -d @18ways/monorunner\n```\n\nCreate `dev.json` in that repository's root:\n\n```json\n{\n  \"defaultMode\": \"web\",\n  \"modes\": {\n    \"web\": { \"apps\": [\"frontend\", \"api\"] },\n    \"all\": { \"apps\": [\"frontend\", \"api\", \"worker\"] }\n  },\n  \"apps\": [\n    {\n      \"id\": \"frontend\",\n      \"name\": \"Frontend\",\n      \"cwd\": \"apps/frontend\",\n      \"command\": \"npm\",\n      \"args\": [\"run\", \"dev\"],\n      \"preferredPort\": 3000\n    },\n    {\n      \"id\": \"api\",\n      \"name\": \"API\",\n      \"cwd\": \"apps/api\",\n      \"command\": \"npm\",\n      \"args\": [\"run\", \"dev\"],\n      \"preferredPort\": 3001\n    },\n    {\n      \"id\": \"worker\",\n      \"name\": \"Worker\",\n      \"cwd\": \"apps/worker\",\n      \"command\": \"npm\",\n      \"args\": [\"run\", \"dev\"],\n      \"exposesPort\": false\n    }\n  ]\n}\n```\n\nAdd a script:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"monorunner\"\n  }\n}\n```\n\nThen run `npm run dev`. Monorunner starts the `web` mode and opens its terminal monitor. Run `npx @18ways/monorunner all` to start a different mode.\n\n## What It Gives You\n\n- One place to start the services that make up a local development stack.\n- Automatic, stable port selection for services that expose a port.\n- A terminal monitor for status, resource use, logs, restarts, test runs, and clean shutdown.\n- A small plugin API for project-specific environment setup and monitor actions.\n\nMonorunner is deliberately focused on the local developer loop. It does not replace your package manager, task graph, CI, or deployment system.\n\n## Commands\n\n| Command | Description |\n| --- | --- |\n| `monorunner` | Start the configured `defaultMode` and open the monitor. |\n| `monorunner <mode>` | Start a named mode from `dev.json`. |\n| `monorunner --help` | Show usage without requiring a `dev.json`. |\n| `monorunner --version` | Print the installed package version. |\n\n`all` is only a conventional name. Define any modes that make sense for your repository.\n\n## Configuration\n\n`dev.json` has three required top-level fields:\n\n| Field | Purpose |\n| --- | --- |\n| `defaultMode` | Mode to start when no mode is passed. |\n| `modes` | Named groups of app IDs. Every mode must contain at least one app. |\n| `apps` | The service definitions. |\n| `plugins` | Optional configuration for core and external plugins. |\n\nEach app supports the following fields:\n\n| Field | Required | Description |\n| --- | --- | --- |\n| `id` | Yes | Stable ID used in modes and monitor rows. |\n| `name` | Yes | Display name in the monitor. |\n| `cwd` | Yes | Working directory, relative to the repository root. |\n| `command` | Yes | Executable to run, such as `npm`, `pnpm`, `bun`, or `node`. |\n| `args` | Yes | Arguments for `command`. |\n| `preferredPort` | No | First port to try for this service. |\n| `exposesPort` | No | Set to `false` for workers, watchers, and other non-listening processes. |\n| `injectPort` | No | Controls how a selected port is provided to the command. |\n| `env` | No | Environment variables to add for this app. |\n| `plugins` | No | App-specific settings consumed by plugins. |\n\n## Ports\n\nGive a listening service a `preferredPort` and Monorunner will reserve it when free, or scan upward when it is already in use. The selected value remains stable while the service is running.\n\nBy default, Monorunner sets `PORT` and appends `-- --port <port>` to the command. This is useful for Next.js-style scripts:\n\n```json\n{\n  \"preferredPort\": 3000\n}\n```\n\nOverride the convention when a service uses another interface:\n\n```json\n{\n  \"preferredPort\": 5173,\n  \"injectPort\": {\n    \"env\": \"PORT\",\n    \"args\": [\"--port\", \"{port}\"]\n  }\n}\n```\n\nYou can set only an environment variable, use another name, or keep the port only for the monitor:\n\n```json\n{\n  \"preferredPort\": 8080,\n  \"injectPort\": {\n    \"env\": \"APP_PORT\",\n    \"args\": false\n  }\n}\n```\n\n```json\n{\n  \"preferredPort\": 4000,\n  \"injectPort\": false\n}\n```\n\nThe chosen value is always retained internally as `MONORUNNER_PORT` for display and managed shutdown.\n\n## Monitor\n\n| Key | Action |\n| --- | --- |\n| Up/down | Select a service. |\n| `/` | Search installed action plugins. |\n| `s` | Start the selected service. |\n| `r` | Restart the selected service. |\n| `k` | Stop the selected service. |\n| `l` | Open full logs for the selected service. |\n| `t` | Run configured checks for services that are currently running. |\n| `q` | Shut down managed services and exit. |\n\n## Tests\n\nThe core tests plugin runs checks only for services that are currently online. Press `t` in the monitor to run it. Targets and tasks run in parallel.\n\nWith no configuration, Monorunner runs the `test` package script in every running service that defines one. Configure other package scripts with `plugins.tests`:\n\n```json\n{\n  \"plugins\": {\n    \"tests\": {\n      \"tasks\": [\"lint\", \"typecheck\", \"test\"]\n    }\n  }\n}\n```\n\nString tasks are package-script names and are skipped when a target does not define them. For custom commands, use an object with `id`, `command`, `args`, and optional `cwd`; `{targetId}` and `{targetCwd}` are available inside arguments.\n\nThe status bar shows progress while checks run. A successful run remains visible as `✓ Tests passed` until the next interaction. A failed run takes over the monitor, identifies affected services, and lets you continue, inspect the failing logs, or copy them.\n\n## Plugins\n\nPlugins are ordinary packages. Add one by its package name in `dev.json`:\n\n```json\n{\n  \"plugins\": {\n    \"@acme/monorunner-plugin-example\": true\n  }\n}\n```\n\nPlugin packages can export `monorunnerPlugin`, `plugin`, or a default export. The supported authoring API is available from `@18ways/monorunner/plugin`:\n\n```ts\nimport type { DevPlugin } from '@18ways/monorunner/plugin';\n\nexport const monorunnerPlugin: DevPlugin = {\n  id: 'example',\n  title: 'Example',\n  aliases: ['ex'],\n  description: 'Adds project-specific environment variables.',\n  getRuntimeEnv(context) {\n    return {\n      EXAMPLE_SERVICE: context.app.id,\n    };\n  },\n};\n```\n\nPlugins can prepare local state, add environment variables, wrap service commands, add monitor keybindings, render a status message, and take over the monitor for focused flows. The plugin API is pre-1.0, so pin a compatible Monorunner version in published plugins rather than using an unrestricted peer range.\n\n## Runtime State\n\nMonorunner writes local runtime state under `.cache/monorunner/` by default. It contains generated runtime configuration, plugin state, and shutdown port maps. Override it with Monorunner-owned environment variables:\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `MONORUNNER_STATE_DIR` | `.cache/monorunner` | State directory, relative to the repository root unless absolute. |\n| `MONORUNNER_PROCESS_HOME` | `<state-dir>/home` | Internal process-manager state directory. |\n| `MONORUNNER_PROCESS_TIMEOUT_MS` | `10000` | Timeout for process commands. |\n| `MONORUNNER_QUERY_TIMEOUT_MS` | `1000` | Timeout for lightweight process queries. |\n\n## Requirements\n\n- Node.js 20 or newer to run the published CLI.\n- The executables named in your app definitions must be available on `PATH`.\n- Bun is only needed when developing Monorunner from this repository.\n\n## Development\n\nFrom this monorepo, run the source version directly:\n\n```bash\nbun packages/monorunner/src/cli.ts\n```\n\nBuild and smoke-test the Node distribution:\n\n```bash\nbun run --cwd packages/monorunner test\n```\n\n## Licence\n\n[MIT](LICENSE)\n","readmeFilename":"README.md"}