Replace the Python CLI with a Node CLI, add a systemd service command

The app is already 100% Node, so the Python launcher was pure overhead - it
existed mainly to bootstrap Node, which is circular. The CLI is now merged
into app/ (the single published npm package): `triggershell start` validates
the config and imports server.ts directly in-process, so server.ts's own
SIGTERM/SIGINT handling just works with no signal-relay/child-process layer
needed. `dev` is dropped from the public CLI (contributors use `pnpm --dir
app dev` directly); there's no `build` command either, since the package
ships a prebuilt `.next` via a `prepack` hook. Adds `triggershell service
install|uninstall|status` for running as a per-user or system systemd unit.

Also fixes two bugs found while wiring this up: server.ts resolved `.next`
relative to `process.cwd()`, which broke once the CLI could run from a
directory other than the app itself; and an explicitly-`files`-listed
package directory bypasses .npmignore for its subpaths, so `.next/cache`
was inflating the npm tarball to ~670MB (now stripped in `prepack`, ~7MB).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 11:03:25 +02:00
co-authored by Claude Sonnet 5
parent e2b6c6102c
commit 30350d80f4
40 changed files with 1154 additions and 1071 deletions
+304 -3
View File
@@ -14,6 +14,9 @@ importers:
'@hookform/resolvers':
specifier: ^5.8.0
version: 5.8.0(ajv-formats@2.1.1(ajv@8.20.0))(ajv@8.20.0)(react-hook-form@7.85.0(react@19.2.8))(zod@4.4.3)
'@inquirer/prompts':
specifier: ^8.5.2
version: 8.5.2(@types/node@20.19.43)
'@xterm/addon-fit':
specifier: ^0.11.0
version: 0.11.0
@@ -35,6 +38,9 @@ importers:
cmdk:
specifier: ^1.1.1
version: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
commander:
specifier: ^15.0.0
version: 15.0.0
drizzle-orm:
specifier: ^0.45.2
version: 0.45.2(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)
@@ -77,6 +83,9 @@ importers:
tailwind-merge:
specifier: ^3.6.0
version: 3.6.0
tsx:
specifier: ^4.23.12
version: 4.23.12
tw-animate-css:
specifier: ^1.4.0
version: 1.4.0
@@ -132,9 +141,6 @@ importers:
tailwindcss:
specifier: ^4
version: 4.3.3
tsx:
specifier: ^4.23.12
version: 4.23.12
typescript:
specifier: ^5
version: 5.9.3
@@ -1107,6 +1113,140 @@ packages:
cpu: [x64]
os: [win32]
'@inquirer/ansi@2.0.7':
resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
'@inquirer/checkbox@5.2.1':
resolution: {integrity: sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/confirm@6.1.1':
resolution: {integrity: sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/core@11.2.1':
resolution: {integrity: sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/editor@5.2.2':
resolution: {integrity: sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/expand@5.1.1':
resolution: {integrity: sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/external-editor@3.0.3':
resolution: {integrity: sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/figures@2.0.7':
resolution: {integrity: sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
'@inquirer/input@5.1.2':
resolution: {integrity: sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/number@4.1.1':
resolution: {integrity: sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/password@5.1.1':
resolution: {integrity: sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/prompts@8.5.2':
resolution: {integrity: sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/rawlist@5.3.1':
resolution: {integrity: sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/search@4.2.1':
resolution: {integrity: sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/select@5.2.1':
resolution: {integrity: sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@inquirer/type@4.0.7':
resolution: {integrity: sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==}
engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -1955,6 +2095,9 @@ packages:
character-reference-invalid@2.0.1:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
chardet@2.2.0:
resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==}
class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
@@ -1966,6 +2109,10 @@ packages:
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
cli-width@4.1.0:
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
engines: {node: '>= 12'}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
@@ -2000,6 +2147,10 @@ packages:
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
engines: {node: '>=20'}
commander@15.0.0:
resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==}
engines: {node: '>=22.12.0'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -2551,9 +2702,18 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
fast-string-truncated-width@3.0.3:
resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==}
fast-string-width@3.0.2:
resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==}
fast-uri@3.1.5:
resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==}
fast-wrap-ansi@0.2.2:
resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==}
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@@ -3381,6 +3541,10 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mute-stream@3.0.0:
resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==}
engines: {node: ^20.17.0 || >=22.9.0}
nanoid@3.3.18:
resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -5067,6 +5231,125 @@ snapshots:
'@img/sharp-win32-x64@0.35.3':
optional: true
'@inquirer/ansi@2.0.7': {}
'@inquirer/checkbox@5.2.1(@types/node@20.19.43)':
dependencies:
'@inquirer/ansi': 2.0.7
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/figures': 2.0.7
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/confirm@6.1.1(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/core@11.2.1(@types/node@20.19.43)':
dependencies:
'@inquirer/ansi': 2.0.7
'@inquirer/figures': 2.0.7
'@inquirer/type': 4.0.7(@types/node@20.19.43)
cli-width: 4.1.0
fast-wrap-ansi: 0.2.2
mute-stream: 3.0.0
signal-exit: 4.1.0
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/editor@5.2.2(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/external-editor': 3.0.3(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/expand@5.1.1(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/external-editor@3.0.3(@types/node@20.19.43)':
dependencies:
chardet: 2.2.0
iconv-lite: 0.7.3
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/figures@2.0.7': {}
'@inquirer/input@5.1.2(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/number@4.1.1(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/password@5.1.1(@types/node@20.19.43)':
dependencies:
'@inquirer/ansi': 2.0.7
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/prompts@8.5.2(@types/node@20.19.43)':
dependencies:
'@inquirer/checkbox': 5.2.1(@types/node@20.19.43)
'@inquirer/confirm': 6.1.1(@types/node@20.19.43)
'@inquirer/editor': 5.2.2(@types/node@20.19.43)
'@inquirer/expand': 5.1.1(@types/node@20.19.43)
'@inquirer/input': 5.1.2(@types/node@20.19.43)
'@inquirer/number': 4.1.1(@types/node@20.19.43)
'@inquirer/password': 5.1.1(@types/node@20.19.43)
'@inquirer/rawlist': 5.3.1(@types/node@20.19.43)
'@inquirer/search': 4.2.1(@types/node@20.19.43)
'@inquirer/select': 5.2.1(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/rawlist@5.3.1(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/search@4.2.1(@types/node@20.19.43)':
dependencies:
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/figures': 2.0.7
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/select@5.2.1(@types/node@20.19.43)':
dependencies:
'@inquirer/ansi': 2.0.7
'@inquirer/core': 11.2.1(@types/node@20.19.43)
'@inquirer/figures': 2.0.7
'@inquirer/type': 4.0.7(@types/node@20.19.43)
optionalDependencies:
'@types/node': 20.19.43
'@inquirer/type@4.0.7(@types/node@20.19.43)':
optionalDependencies:
'@types/node': 20.19.43
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -5851,6 +6134,8 @@ snapshots:
character-reference-invalid@2.0.1: {}
chardet@2.2.0: {}
class-variance-authority@0.7.1:
dependencies:
clsx: 2.1.1
@@ -5861,6 +6146,8 @@ snapshots:
cli-spinners@2.9.2: {}
cli-width@4.1.0: {}
client-only@0.0.1: {}
clsx@2.1.1: {}
@@ -5891,6 +6178,8 @@ snapshots:
commander@14.0.3: {}
commander@15.0.0: {}
concat-map@0.0.1: {}
conf@10.2.0:
@@ -6610,8 +6899,18 @@ snapshots:
fast-levenshtein@2.0.6: {}
fast-string-truncated-width@3.0.3: {}
fast-string-width@3.0.2:
dependencies:
fast-string-truncated-width: 3.0.3
fast-uri@3.1.5: {}
fast-wrap-ansi@0.2.2:
dependencies:
fast-string-width: 3.0.2
fastq@1.20.1:
dependencies:
reusify: 1.1.0
@@ -7581,6 +7880,8 @@ snapshots:
ms@2.1.3: {}
mute-stream@3.0.0: {}
nanoid@3.3.18: {}
napi-postinstall@0.3.4: {}