From 3f379ca2acdc78968b565811ec378fb51bca21b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Sun, 16 Aug 2026 11:14:01 +0200 Subject: [PATCH] Flatten the repo: move everything out of app/ to the root Now that the CLI and the Next.js app are one package, nesting it inside app/ served no purpose - the repo root itself becomes the published npm package. Merges app/.gitignore and app/README.md into the root versions, drops the now-duplicate app/LICENSE, and updates path references (README, docs/ARCHITECTURE.md, docs/CONFIG_REFERENCE.md, package.json's repository.directory) that assumed the app/ nesting. Also fixes a real bug this surfaced: the in-app docs viewer resolved docs/ relative to process.cwd(), which only worked by accident when the CLI happened to be invoked from app/'s parent directory. A first attempt at fixing it with import.meta.dirname broke instead, for the same cross-module-graph reason config-path resolution already documented - Next compiles Route Handlers through a separate module graph that doesn't preserve source-relative import.meta paths. Fixed by exposing the app root via TRIGGERSHELL_APP_ROOT (set once in server.ts, where import.meta *does* resolve correctly), the same pattern already used for TRIGGERSHELL_CONFIG_PATH. Co-Authored-By: Claude Sonnet 5 --- .gitignore | 34 +++++++++++++++ app/AGENTS.md => AGENTS.md | 0 app/CLAUDE.md => CLAUDE.md | 0 README.md | 22 +++++----- app/.gitignore | 41 ------------------- app/LICENSE | 21 ---------- app/README.md | 21 ---------- {app/bin => bin}/triggershell.js | 0 app/components.json => components.json | 0 docs/ARCHITECTURE.md | 8 ++-- docs/CONFIG_REFERENCE.md | 2 +- app/drizzle.config.ts => drizzle.config.ts | 0 .../drizzle => drizzle}/0000_thick_reaper.sql | 0 .../meta/0000_snapshot.json | 0 {app/drizzle => drizzle}/meta/_journal.json | 0 app/eslint.config.mjs => eslint.config.mjs | 0 app/next.config.ts => next.config.ts | 0 app/package.json => package.json | 4 +- app/pnpm-lock.yaml => pnpm-lock.yaml | 0 ...pnpm-workspace.yaml => pnpm-workspace.yaml | 0 app/postcss.config.mjs => postcss.config.mjs | 0 app/server.ts => server.ts | 4 ++ .../app/(app)/docs/[slug]/page.tsx | 0 {app/src => src}/app/(app)/docs/page.tsx | 0 {app/src => src}/app/(app)/layout.tsx | 0 {app/src => src}/app/(app)/page.tsx | 0 .../app/(app)/runs/[runId]/page.tsx | 0 {app/src => src}/app/(app)/runs/page.tsx | 0 .../app/(app)/scripts/[scriptId]/page.tsx | 0 {app/src => src}/app/api/auth/login/route.ts | 0 {app/src => src}/app/api/auth/logout/route.ts | 0 .../src => src}/app/api/auth/session/route.ts | 0 {app/src => src}/app/api/healthz/route.ts | 0 .../app/api/runs/[runId]/cancel/route.ts | 0 .../app/api/runs/[runId]/logs/route.ts | 0 .../src => src}/app/api/runs/[runId]/route.ts | 0 {app/src => src}/app/api/runs/route.ts | 0 .../app/api/scripts/[scriptId]/route.ts | 0 .../app/api/scripts/[scriptId]/runs/route.ts | 0 {app/src => src}/app/api/scripts/route.ts | 0 {app/src => src}/app/globals.css | 0 {app/src => src}/app/icon.svg | 0 {app/src => src}/app/layout.tsx | 0 {app/src => src}/app/login/login-form.tsx | 0 {app/src => src}/app/login/page.tsx | 0 .../bootstrap/async-local-storage-polyfill.ts | 0 {app/src => src}/cli/commands/doctor.ts | 0 {app/src => src}/cli/commands/init.ts | 0 {app/src => src}/cli/commands/service.ts | 0 {app/src => src}/cli/commands/start.ts | 0 {app/src => src}/cli/commands/users.ts | 0 {app/src => src}/cli/commands/validate.ts | 0 {app/src => src}/cli/index.ts | 0 {app/src => src}/cli/lib/env-file.test.ts | 0 {app/src => src}/cli/lib/env-file.ts | 0 {app/src => src}/cli/lib/network.ts | 0 {app/src => src}/cli/lib/paths.ts | 0 {app/src => src}/cli/lib/slug.test.ts | 0 {app/src => src}/cli/lib/slug.ts | 0 {app/src => src}/cli/lib/systemd.test.ts | 0 {app/src => src}/cli/lib/systemd.ts | 0 {app/src => src}/cli/version.ts | 0 .../components/docs/markdown-viewer.tsx | 0 .../forms/controls/multi-select.tsx | 0 .../components/forms/dynamic-form.tsx | 0 .../components/forms/field-renderer.tsx | 0 {app/src => src}/components/layout/footer.tsx | 0 {app/src => src}/components/layout/nav.tsx | 0 .../components/layout/theme-toggle.tsx | 0 .../components/runs/run-status-badge.tsx | 0 .../components/runs/run-terminal.tsx | 0 .../components/runs/runs-toolbar.tsx | 0 .../components/runs/xterm-view.tsx | 0 {app/src => src}/components/ui/alert.tsx | 0 {app/src => src}/components/ui/badge.tsx | 0 {app/src => src}/components/ui/button.tsx | 0 {app/src => src}/components/ui/card.tsx | 0 {app/src => src}/components/ui/checkbox.tsx | 0 {app/src => src}/components/ui/command.tsx | 0 {app/src => src}/components/ui/dialog.tsx | 0 .../components/ui/dropdown-menu.tsx | 0 {app/src => src}/components/ui/form.tsx | 0 .../src => src}/components/ui/input-group.tsx | 0 {app/src => src}/components/ui/input.tsx | 0 {app/src => src}/components/ui/label.tsx | 0 {app/src => src}/components/ui/popover.tsx | 0 .../src => src}/components/ui/radio-group.tsx | 0 .../src => src}/components/ui/scroll-area.tsx | 0 {app/src => src}/components/ui/select.tsx | 0 {app/src => src}/components/ui/separator.tsx | 0 {app/src => src}/components/ui/skeleton.tsx | 0 {app/src => src}/components/ui/slider.tsx | 0 {app/src => src}/components/ui/sonner.tsx | 0 {app/src => src}/components/ui/switch.tsx | 0 {app/src => src}/components/ui/table.tsx | 0 {app/src => src}/components/ui/textarea.tsx | 0 {app/src => src}/components/ui/tooltip.tsx | 0 {app/src => src}/hooks/use-run-socket.ts | 0 {app/src => src}/lib/auth/guard.ts | 0 {app/src => src}/lib/auth/password.ts | 0 {app/src => src}/lib/auth/rate-limit.ts | 0 {app/src => src}/lib/auth/session.ts | 0 {app/src => src}/lib/auth/sync.ts | 0 {app/src => src}/lib/auth/tokens.ts | 0 {app/src => src}/lib/config/load.ts | 0 {app/src => src}/lib/config/schema.ts | 0 {app/src => src}/lib/config/serialize.ts | 0 {app/src => src}/lib/config/ui-control-map.ts | 0 {app/src => src}/lib/db/client.ts | 0 {app/src => src}/lib/db/schema.ts | 0 {app/src => src}/lib/docs.ts | 12 ++++-- {app/src => src}/lib/runner/build-args.ts | 0 {app/src => src}/lib/runner/engine.ts | 0 {app/src => src}/lib/runner/events.ts | 0 {app/src => src}/lib/runner/log-file.ts | 0 {app/src => src}/lib/runner/registry.ts | 0 {app/src => src}/lib/utils.ts | 0 .../lib/validation/variable-schema.ts | 0 {app/src => src}/lib/ws/protocol.ts | 0 {app/src => src}/lib/ws/server.ts | 0 {app/src => src}/proxy.ts | 0 {app/templates => templates}/triggershell.yml | 0 app/tsconfig.json => tsconfig.json | 0 123 files changed, 65 insertions(+), 104 deletions(-) rename app/AGENTS.md => AGENTS.md (100%) rename app/CLAUDE.md => CLAUDE.md (100%) delete mode 100644 app/.gitignore delete mode 100644 app/LICENSE delete mode 100644 app/README.md rename {app/bin => bin}/triggershell.js (100%) rename app/components.json => components.json (100%) rename app/drizzle.config.ts => drizzle.config.ts (100%) rename {app/drizzle => drizzle}/0000_thick_reaper.sql (100%) rename {app/drizzle => drizzle}/meta/0000_snapshot.json (100%) rename {app/drizzle => drizzle}/meta/_journal.json (100%) rename app/eslint.config.mjs => eslint.config.mjs (100%) rename app/next.config.ts => next.config.ts (100%) rename app/package.json => package.json (96%) rename app/pnpm-lock.yaml => pnpm-lock.yaml (100%) rename app/pnpm-workspace.yaml => pnpm-workspace.yaml (100%) rename app/postcss.config.mjs => postcss.config.mjs (100%) rename app/server.ts => server.ts (88%) rename {app/src => src}/app/(app)/docs/[slug]/page.tsx (100%) rename {app/src => src}/app/(app)/docs/page.tsx (100%) rename {app/src => src}/app/(app)/layout.tsx (100%) rename {app/src => src}/app/(app)/page.tsx (100%) rename {app/src => src}/app/(app)/runs/[runId]/page.tsx (100%) rename {app/src => src}/app/(app)/runs/page.tsx (100%) rename {app/src => src}/app/(app)/scripts/[scriptId]/page.tsx (100%) rename {app/src => src}/app/api/auth/login/route.ts (100%) rename {app/src => src}/app/api/auth/logout/route.ts (100%) rename {app/src => src}/app/api/auth/session/route.ts (100%) rename {app/src => src}/app/api/healthz/route.ts (100%) rename {app/src => src}/app/api/runs/[runId]/cancel/route.ts (100%) rename {app/src => src}/app/api/runs/[runId]/logs/route.ts (100%) rename {app/src => src}/app/api/runs/[runId]/route.ts (100%) rename {app/src => src}/app/api/runs/route.ts (100%) rename {app/src => src}/app/api/scripts/[scriptId]/route.ts (100%) rename {app/src => src}/app/api/scripts/[scriptId]/runs/route.ts (100%) rename {app/src => src}/app/api/scripts/route.ts (100%) rename {app/src => src}/app/globals.css (100%) rename {app/src => src}/app/icon.svg (100%) rename {app/src => src}/app/layout.tsx (100%) rename {app/src => src}/app/login/login-form.tsx (100%) rename {app/src => src}/app/login/page.tsx (100%) rename {app/src => src}/bootstrap/async-local-storage-polyfill.ts (100%) rename {app/src => src}/cli/commands/doctor.ts (100%) rename {app/src => src}/cli/commands/init.ts (100%) rename {app/src => src}/cli/commands/service.ts (100%) rename {app/src => src}/cli/commands/start.ts (100%) rename {app/src => src}/cli/commands/users.ts (100%) rename {app/src => src}/cli/commands/validate.ts (100%) rename {app/src => src}/cli/index.ts (100%) rename {app/src => src}/cli/lib/env-file.test.ts (100%) rename {app/src => src}/cli/lib/env-file.ts (100%) rename {app/src => src}/cli/lib/network.ts (100%) rename {app/src => src}/cli/lib/paths.ts (100%) rename {app/src => src}/cli/lib/slug.test.ts (100%) rename {app/src => src}/cli/lib/slug.ts (100%) rename {app/src => src}/cli/lib/systemd.test.ts (100%) rename {app/src => src}/cli/lib/systemd.ts (100%) rename {app/src => src}/cli/version.ts (100%) rename {app/src => src}/components/docs/markdown-viewer.tsx (100%) rename {app/src => src}/components/forms/controls/multi-select.tsx (100%) rename {app/src => src}/components/forms/dynamic-form.tsx (100%) rename {app/src => src}/components/forms/field-renderer.tsx (100%) rename {app/src => src}/components/layout/footer.tsx (100%) rename {app/src => src}/components/layout/nav.tsx (100%) rename {app/src => src}/components/layout/theme-toggle.tsx (100%) rename {app/src => src}/components/runs/run-status-badge.tsx (100%) rename {app/src => src}/components/runs/run-terminal.tsx (100%) rename {app/src => src}/components/runs/runs-toolbar.tsx (100%) rename {app/src => src}/components/runs/xterm-view.tsx (100%) rename {app/src => src}/components/ui/alert.tsx (100%) rename {app/src => src}/components/ui/badge.tsx (100%) rename {app/src => src}/components/ui/button.tsx (100%) rename {app/src => src}/components/ui/card.tsx (100%) rename {app/src => src}/components/ui/checkbox.tsx (100%) rename {app/src => src}/components/ui/command.tsx (100%) rename {app/src => src}/components/ui/dialog.tsx (100%) rename {app/src => src}/components/ui/dropdown-menu.tsx (100%) rename {app/src => src}/components/ui/form.tsx (100%) rename {app/src => src}/components/ui/input-group.tsx (100%) rename {app/src => src}/components/ui/input.tsx (100%) rename {app/src => src}/components/ui/label.tsx (100%) rename {app/src => src}/components/ui/popover.tsx (100%) rename {app/src => src}/components/ui/radio-group.tsx (100%) rename {app/src => src}/components/ui/scroll-area.tsx (100%) rename {app/src => src}/components/ui/select.tsx (100%) rename {app/src => src}/components/ui/separator.tsx (100%) rename {app/src => src}/components/ui/skeleton.tsx (100%) rename {app/src => src}/components/ui/slider.tsx (100%) rename {app/src => src}/components/ui/sonner.tsx (100%) rename {app/src => src}/components/ui/switch.tsx (100%) rename {app/src => src}/components/ui/table.tsx (100%) rename {app/src => src}/components/ui/textarea.tsx (100%) rename {app/src => src}/components/ui/tooltip.tsx (100%) rename {app/src => src}/hooks/use-run-socket.ts (100%) rename {app/src => src}/lib/auth/guard.ts (100%) rename {app/src => src}/lib/auth/password.ts (100%) rename {app/src => src}/lib/auth/rate-limit.ts (100%) rename {app/src => src}/lib/auth/session.ts (100%) rename {app/src => src}/lib/auth/sync.ts (100%) rename {app/src => src}/lib/auth/tokens.ts (100%) rename {app/src => src}/lib/config/load.ts (100%) rename {app/src => src}/lib/config/schema.ts (100%) rename {app/src => src}/lib/config/serialize.ts (100%) rename {app/src => src}/lib/config/ui-control-map.ts (100%) rename {app/src => src}/lib/db/client.ts (100%) rename {app/src => src}/lib/db/schema.ts (100%) rename {app/src => src}/lib/docs.ts (60%) rename {app/src => src}/lib/runner/build-args.ts (100%) rename {app/src => src}/lib/runner/engine.ts (100%) rename {app/src => src}/lib/runner/events.ts (100%) rename {app/src => src}/lib/runner/log-file.ts (100%) rename {app/src => src}/lib/runner/registry.ts (100%) rename {app/src => src}/lib/utils.ts (100%) rename {app/src => src}/lib/validation/variable-schema.ts (100%) rename {app/src => src}/lib/ws/protocol.ts (100%) rename {app/src => src}/lib/ws/server.ts (100%) rename {app/src => src}/proxy.ts (100%) rename {app/templates => templates}/triggershell.yml (100%) rename app/tsconfig.json => tsconfig.json (100%) diff --git a/.gitignore b/.gitignore index 333f864..d3b7ae1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,36 @@ +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# typescript +*.tsbuildinfo +next-env.d.ts + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# vercel +.vercel + # Runtime data (created by `triggershell start` in whatever directory the config lives in) .triggershell/ @@ -11,5 +44,6 @@ # Editors / OS .DS_Store +*.pem .idea/ .vscode/ diff --git a/app/AGENTS.md b/AGENTS.md similarity index 100% rename from app/AGENTS.md rename to AGENTS.md diff --git a/app/CLAUDE.md b/CLAUDE.md similarity index 100% rename from app/CLAUDE.md rename to CLAUDE.md diff --git a/README.md b/README.md index a2bbc9f..4fd322c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Edit `triggershell.yml` to add your own scripts (see [Configuration](#configurat re-run `triggershell start`. > The `triggershell` package isn't published to npm yet. Until it is, build and link a local copy -> instead: `pnpm --dir app install && pnpm --dir app build && pnpm --dir app link --global`. +> instead: `pnpm install && pnpm build && pnpm link --global`. ## Requirements @@ -150,21 +150,23 @@ Full reference with request/response shapes and curl examples: [`docs/API.md`](d ## Development This is the workflow for working on TriggerShell itself, not for installing/running it — it -bypasses the CLI entirely and talks to `app/`'s own scripts directly, with hot reload: +bypasses the CLI entirely and talks to the app's own scripts directly, with hot reload. The app is +still not meant to be run standalone with `next dev`/`next start`, since it needs the custom server +(`server.ts`) for the WebSocket endpoint — `pnpm dev`/`pnpm start` below cover that: ```bash -pnpm --dir app install -pnpm --dir app dev # tsx watch server.ts - reads TRIGGERSHELL_CONFIG_PATH from the environment -pnpm --dir app lint -pnpm --dir app typecheck -pnpm --dir app test # CLI unit tests (src/cli/**/*.test.ts) -pnpm --dir app db:studio # browse the SQLite DB +pnpm install +pnpm dev # tsx watch server.ts - reads TRIGGERSHELL_CONFIG_PATH from the environment +pnpm lint +pnpm typecheck +pnpm test # CLI unit tests (src/cli/**/*.test.ts) +pnpm db:studio # browse the SQLite DB ``` -Repo layout: +Repo layout — the repo root itself is the published npm package (Next.js app + the `triggershell` +CLI in `bin/`/`src/cli/`), alongside: ``` -app/ The published npm package: Next.js app + the `triggershell` CLI (bin/, src/cli/) in one examples/ A runnable example config + scripts docs/ Config/architecture/API reference docs ``` diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 5ef6a52..0000000 --- a/app/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/app/LICENSE b/app/LICENSE deleted file mode 100644 index 87a0f8f..0000000 --- a/app/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 TriggerShell contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/app/README.md b/app/README.md deleted file mode 100644 index 6006832..0000000 --- a/app/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# TriggerShell web app - -This directory is both the Next.js app and the home of the `triggershell` CLI (`bin/triggershell.js` -→ `src/cli`) that launches it — together they're published as one npm package. The app is still not -meant to be run standalone with `next dev`/`next start`, since it needs a custom server (`server.ts`) -for the WebSocket endpoint; use the CLI (`triggershell start`) or the `pnpm` scripts below instead. - -See the [repo root README](../README.md) for how to run TriggerShell end-to-end, and -[`../docs/ARCHITECTURE.md`](../docs/ARCHITECTURE.md) for how this app is put together. - -```bash -pnpm install -pnpm dev # tsx watch server.ts - reads TRIGGERSHELL_CONFIG_PATH from the environment -pnpm lint -pnpm typecheck -pnpm test # CLI unit tests (src/cli/**/*.test.ts) -pnpm db:studio # browse the SQLite database -``` - -Note: this is the contributor workflow for developing TriggerShell itself. End users install and -run the published `triggershell` CLI instead (see the root README). diff --git a/app/bin/triggershell.js b/bin/triggershell.js similarity index 100% rename from app/bin/triggershell.js rename to bin/triggershell.js diff --git a/app/components.json b/components.json similarity index 100% rename from app/components.json rename to components.json diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f938f22..eec7f53 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,8 +1,8 @@ # Architecture ``` - triggershell (Node CLI, src/cli) app/ (Next.js, all server logic) - ─────────────────────────────── ────────────────────────────── + triggershell (Node CLI, src/cli) server.ts + src/ (Next.js, all server logic) + ─────────────────────────────── ───────────────────────────────────────── triggershell start server.ts (custom Node server) 1. resolve + validate the config (loadConfig) ├─ Next.js request handler (pages, API routes) 2. check the port is free ├─ ws.WebSocketServer on /ws/runs @@ -24,7 +24,7 @@ ## Why a custom Node server -Next.js Route Handlers can't host a persistent WebSocket server, so `app/server.ts` wraps Next's +Next.js Route Handlers can't host a persistent WebSocket server, so `server.ts` wraps Next's request handler in a plain `http.createServer` and attaches a `ws.WebSocketServer` via the `upgrade` event, scoped to `/ws/runs` with its own auth check (Route Handlers get auth via `next/headers`'s `cookies()`, which isn't available on a raw `http.IncomingMessage`). @@ -100,4 +100,4 @@ Every server file that reads the config/DB at request time (`getConfig()`, `getD `requireAuth()`) sets `export const dynamic = "force-dynamic"`. Without it, `next build` tries to statically prerender pages like `/` at build time, which fails because there's no config file to read yet (the config only exists at `triggershell start` runtime, in the user's own project -directory, not `app/`'s). +directory, not the package's). diff --git a/docs/CONFIG_REFERENCE.md b/docs/CONFIG_REFERENCE.md index b15ea7a..dd048ec 100644 --- a/docs/CONFIG_REFERENCE.md +++ b/docs/CONFIG_REFERENCE.md @@ -10,7 +10,7 @@ present) into its environment - without overriding any variable already set in t secrets referenced via `${VAR}` don't have to be committed alongside the config. `triggershell init` scaffolds both files together. -The canonical schema is the Zod schema at `app/src/lib/config/schema.ts` — this document mirrors +The canonical schema is the Zod schema at `src/lib/config/schema.ts` — this document mirrors it. `triggershell validate` loads and validates the config directly against the schema below (no separate pre-flight step). diff --git a/app/drizzle.config.ts b/drizzle.config.ts similarity index 100% rename from app/drizzle.config.ts rename to drizzle.config.ts diff --git a/app/drizzle/0000_thick_reaper.sql b/drizzle/0000_thick_reaper.sql similarity index 100% rename from app/drizzle/0000_thick_reaper.sql rename to drizzle/0000_thick_reaper.sql diff --git a/app/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json similarity index 100% rename from app/drizzle/meta/0000_snapshot.json rename to drizzle/meta/0000_snapshot.json diff --git a/app/drizzle/meta/_journal.json b/drizzle/meta/_journal.json similarity index 100% rename from app/drizzle/meta/_journal.json rename to drizzle/meta/_journal.json diff --git a/app/eslint.config.mjs b/eslint.config.mjs similarity index 100% rename from app/eslint.config.mjs rename to eslint.config.mjs diff --git a/app/next.config.ts b/next.config.ts similarity index 100% rename from app/next.config.ts rename to next.config.ts diff --git a/app/package.json b/package.json similarity index 96% rename from app/package.json rename to package.json index 854b524..068e15f 100644 --- a/app/package.json +++ b/package.json @@ -5,8 +5,7 @@ "type": "module", "repository": { "type": "git", - "url": "https://dev.pivoine.art/valknar/triggershell.git", - "directory": "app" + "url": "https://dev.pivoine.art/valknar/triggershell.git" }, "bin": { "triggershell": "bin/triggershell.js" @@ -19,6 +18,7 @@ "src", "templates", "drizzle", + "docs", ".next", "server.ts", "next.config.ts", diff --git a/app/pnpm-lock.yaml b/pnpm-lock.yaml similarity index 100% rename from app/pnpm-lock.yaml rename to pnpm-lock.yaml diff --git a/app/pnpm-workspace.yaml b/pnpm-workspace.yaml similarity index 100% rename from app/pnpm-workspace.yaml rename to pnpm-workspace.yaml diff --git a/app/postcss.config.mjs b/postcss.config.mjs similarity index 100% rename from app/postcss.config.mjs rename to postcss.config.mjs diff --git a/app/server.ts b/server.ts similarity index 88% rename from app/server.ts rename to server.ts index 6d59acc..1dffe4d 100644 --- a/app/server.ts +++ b/server.ts @@ -24,6 +24,10 @@ reconcileOrphanedRuns(); // `dir` must be this file's own directory, not `process.cwd()` - when launched by the installed // `triggershell` CLI, the working directory is wherever the user's config lives, not the package. const dir = path.dirname(fileURLToPath(import.meta.url)); +// Exposed via `process.env` (not just the local `dir` const) so Route Handlers/Server Components - +// compiled through Next's own module graph, separate from this file's - can find it too. See +// `docs.ts`'s use of this and the `globalThis` comment in `runner/events.ts` for the same reasoning. +process.env.TRIGGERSHELL_APP_ROOT = dir; const app = next({ dev, dir, hostname, port }); const handle = app.getRequestHandler(); diff --git a/app/src/app/(app)/docs/[slug]/page.tsx b/src/app/(app)/docs/[slug]/page.tsx similarity index 100% rename from app/src/app/(app)/docs/[slug]/page.tsx rename to src/app/(app)/docs/[slug]/page.tsx diff --git a/app/src/app/(app)/docs/page.tsx b/src/app/(app)/docs/page.tsx similarity index 100% rename from app/src/app/(app)/docs/page.tsx rename to src/app/(app)/docs/page.tsx diff --git a/app/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx similarity index 100% rename from app/src/app/(app)/layout.tsx rename to src/app/(app)/layout.tsx diff --git a/app/src/app/(app)/page.tsx b/src/app/(app)/page.tsx similarity index 100% rename from app/src/app/(app)/page.tsx rename to src/app/(app)/page.tsx diff --git a/app/src/app/(app)/runs/[runId]/page.tsx b/src/app/(app)/runs/[runId]/page.tsx similarity index 100% rename from app/src/app/(app)/runs/[runId]/page.tsx rename to src/app/(app)/runs/[runId]/page.tsx diff --git a/app/src/app/(app)/runs/page.tsx b/src/app/(app)/runs/page.tsx similarity index 100% rename from app/src/app/(app)/runs/page.tsx rename to src/app/(app)/runs/page.tsx diff --git a/app/src/app/(app)/scripts/[scriptId]/page.tsx b/src/app/(app)/scripts/[scriptId]/page.tsx similarity index 100% rename from app/src/app/(app)/scripts/[scriptId]/page.tsx rename to src/app/(app)/scripts/[scriptId]/page.tsx diff --git a/app/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts similarity index 100% rename from app/src/app/api/auth/login/route.ts rename to src/app/api/auth/login/route.ts diff --git a/app/src/app/api/auth/logout/route.ts b/src/app/api/auth/logout/route.ts similarity index 100% rename from app/src/app/api/auth/logout/route.ts rename to src/app/api/auth/logout/route.ts diff --git a/app/src/app/api/auth/session/route.ts b/src/app/api/auth/session/route.ts similarity index 100% rename from app/src/app/api/auth/session/route.ts rename to src/app/api/auth/session/route.ts diff --git a/app/src/app/api/healthz/route.ts b/src/app/api/healthz/route.ts similarity index 100% rename from app/src/app/api/healthz/route.ts rename to src/app/api/healthz/route.ts diff --git a/app/src/app/api/runs/[runId]/cancel/route.ts b/src/app/api/runs/[runId]/cancel/route.ts similarity index 100% rename from app/src/app/api/runs/[runId]/cancel/route.ts rename to src/app/api/runs/[runId]/cancel/route.ts diff --git a/app/src/app/api/runs/[runId]/logs/route.ts b/src/app/api/runs/[runId]/logs/route.ts similarity index 100% rename from app/src/app/api/runs/[runId]/logs/route.ts rename to src/app/api/runs/[runId]/logs/route.ts diff --git a/app/src/app/api/runs/[runId]/route.ts b/src/app/api/runs/[runId]/route.ts similarity index 100% rename from app/src/app/api/runs/[runId]/route.ts rename to src/app/api/runs/[runId]/route.ts diff --git a/app/src/app/api/runs/route.ts b/src/app/api/runs/route.ts similarity index 100% rename from app/src/app/api/runs/route.ts rename to src/app/api/runs/route.ts diff --git a/app/src/app/api/scripts/[scriptId]/route.ts b/src/app/api/scripts/[scriptId]/route.ts similarity index 100% rename from app/src/app/api/scripts/[scriptId]/route.ts rename to src/app/api/scripts/[scriptId]/route.ts diff --git a/app/src/app/api/scripts/[scriptId]/runs/route.ts b/src/app/api/scripts/[scriptId]/runs/route.ts similarity index 100% rename from app/src/app/api/scripts/[scriptId]/runs/route.ts rename to src/app/api/scripts/[scriptId]/runs/route.ts diff --git a/app/src/app/api/scripts/route.ts b/src/app/api/scripts/route.ts similarity index 100% rename from app/src/app/api/scripts/route.ts rename to src/app/api/scripts/route.ts diff --git a/app/src/app/globals.css b/src/app/globals.css similarity index 100% rename from app/src/app/globals.css rename to src/app/globals.css diff --git a/app/src/app/icon.svg b/src/app/icon.svg similarity index 100% rename from app/src/app/icon.svg rename to src/app/icon.svg diff --git a/app/src/app/layout.tsx b/src/app/layout.tsx similarity index 100% rename from app/src/app/layout.tsx rename to src/app/layout.tsx diff --git a/app/src/app/login/login-form.tsx b/src/app/login/login-form.tsx similarity index 100% rename from app/src/app/login/login-form.tsx rename to src/app/login/login-form.tsx diff --git a/app/src/app/login/page.tsx b/src/app/login/page.tsx similarity index 100% rename from app/src/app/login/page.tsx rename to src/app/login/page.tsx diff --git a/app/src/bootstrap/async-local-storage-polyfill.ts b/src/bootstrap/async-local-storage-polyfill.ts similarity index 100% rename from app/src/bootstrap/async-local-storage-polyfill.ts rename to src/bootstrap/async-local-storage-polyfill.ts diff --git a/app/src/cli/commands/doctor.ts b/src/cli/commands/doctor.ts similarity index 100% rename from app/src/cli/commands/doctor.ts rename to src/cli/commands/doctor.ts diff --git a/app/src/cli/commands/init.ts b/src/cli/commands/init.ts similarity index 100% rename from app/src/cli/commands/init.ts rename to src/cli/commands/init.ts diff --git a/app/src/cli/commands/service.ts b/src/cli/commands/service.ts similarity index 100% rename from app/src/cli/commands/service.ts rename to src/cli/commands/service.ts diff --git a/app/src/cli/commands/start.ts b/src/cli/commands/start.ts similarity index 100% rename from app/src/cli/commands/start.ts rename to src/cli/commands/start.ts diff --git a/app/src/cli/commands/users.ts b/src/cli/commands/users.ts similarity index 100% rename from app/src/cli/commands/users.ts rename to src/cli/commands/users.ts diff --git a/app/src/cli/commands/validate.ts b/src/cli/commands/validate.ts similarity index 100% rename from app/src/cli/commands/validate.ts rename to src/cli/commands/validate.ts diff --git a/app/src/cli/index.ts b/src/cli/index.ts similarity index 100% rename from app/src/cli/index.ts rename to src/cli/index.ts diff --git a/app/src/cli/lib/env-file.test.ts b/src/cli/lib/env-file.test.ts similarity index 100% rename from app/src/cli/lib/env-file.test.ts rename to src/cli/lib/env-file.test.ts diff --git a/app/src/cli/lib/env-file.ts b/src/cli/lib/env-file.ts similarity index 100% rename from app/src/cli/lib/env-file.ts rename to src/cli/lib/env-file.ts diff --git a/app/src/cli/lib/network.ts b/src/cli/lib/network.ts similarity index 100% rename from app/src/cli/lib/network.ts rename to src/cli/lib/network.ts diff --git a/app/src/cli/lib/paths.ts b/src/cli/lib/paths.ts similarity index 100% rename from app/src/cli/lib/paths.ts rename to src/cli/lib/paths.ts diff --git a/app/src/cli/lib/slug.test.ts b/src/cli/lib/slug.test.ts similarity index 100% rename from app/src/cli/lib/slug.test.ts rename to src/cli/lib/slug.test.ts diff --git a/app/src/cli/lib/slug.ts b/src/cli/lib/slug.ts similarity index 100% rename from app/src/cli/lib/slug.ts rename to src/cli/lib/slug.ts diff --git a/app/src/cli/lib/systemd.test.ts b/src/cli/lib/systemd.test.ts similarity index 100% rename from app/src/cli/lib/systemd.test.ts rename to src/cli/lib/systemd.test.ts diff --git a/app/src/cli/lib/systemd.ts b/src/cli/lib/systemd.ts similarity index 100% rename from app/src/cli/lib/systemd.ts rename to src/cli/lib/systemd.ts diff --git a/app/src/cli/version.ts b/src/cli/version.ts similarity index 100% rename from app/src/cli/version.ts rename to src/cli/version.ts diff --git a/app/src/components/docs/markdown-viewer.tsx b/src/components/docs/markdown-viewer.tsx similarity index 100% rename from app/src/components/docs/markdown-viewer.tsx rename to src/components/docs/markdown-viewer.tsx diff --git a/app/src/components/forms/controls/multi-select.tsx b/src/components/forms/controls/multi-select.tsx similarity index 100% rename from app/src/components/forms/controls/multi-select.tsx rename to src/components/forms/controls/multi-select.tsx diff --git a/app/src/components/forms/dynamic-form.tsx b/src/components/forms/dynamic-form.tsx similarity index 100% rename from app/src/components/forms/dynamic-form.tsx rename to src/components/forms/dynamic-form.tsx diff --git a/app/src/components/forms/field-renderer.tsx b/src/components/forms/field-renderer.tsx similarity index 100% rename from app/src/components/forms/field-renderer.tsx rename to src/components/forms/field-renderer.tsx diff --git a/app/src/components/layout/footer.tsx b/src/components/layout/footer.tsx similarity index 100% rename from app/src/components/layout/footer.tsx rename to src/components/layout/footer.tsx diff --git a/app/src/components/layout/nav.tsx b/src/components/layout/nav.tsx similarity index 100% rename from app/src/components/layout/nav.tsx rename to src/components/layout/nav.tsx diff --git a/app/src/components/layout/theme-toggle.tsx b/src/components/layout/theme-toggle.tsx similarity index 100% rename from app/src/components/layout/theme-toggle.tsx rename to src/components/layout/theme-toggle.tsx diff --git a/app/src/components/runs/run-status-badge.tsx b/src/components/runs/run-status-badge.tsx similarity index 100% rename from app/src/components/runs/run-status-badge.tsx rename to src/components/runs/run-status-badge.tsx diff --git a/app/src/components/runs/run-terminal.tsx b/src/components/runs/run-terminal.tsx similarity index 100% rename from app/src/components/runs/run-terminal.tsx rename to src/components/runs/run-terminal.tsx diff --git a/app/src/components/runs/runs-toolbar.tsx b/src/components/runs/runs-toolbar.tsx similarity index 100% rename from app/src/components/runs/runs-toolbar.tsx rename to src/components/runs/runs-toolbar.tsx diff --git a/app/src/components/runs/xterm-view.tsx b/src/components/runs/xterm-view.tsx similarity index 100% rename from app/src/components/runs/xterm-view.tsx rename to src/components/runs/xterm-view.tsx diff --git a/app/src/components/ui/alert.tsx b/src/components/ui/alert.tsx similarity index 100% rename from app/src/components/ui/alert.tsx rename to src/components/ui/alert.tsx diff --git a/app/src/components/ui/badge.tsx b/src/components/ui/badge.tsx similarity index 100% rename from app/src/components/ui/badge.tsx rename to src/components/ui/badge.tsx diff --git a/app/src/components/ui/button.tsx b/src/components/ui/button.tsx similarity index 100% rename from app/src/components/ui/button.tsx rename to src/components/ui/button.tsx diff --git a/app/src/components/ui/card.tsx b/src/components/ui/card.tsx similarity index 100% rename from app/src/components/ui/card.tsx rename to src/components/ui/card.tsx diff --git a/app/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx similarity index 100% rename from app/src/components/ui/checkbox.tsx rename to src/components/ui/checkbox.tsx diff --git a/app/src/components/ui/command.tsx b/src/components/ui/command.tsx similarity index 100% rename from app/src/components/ui/command.tsx rename to src/components/ui/command.tsx diff --git a/app/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx similarity index 100% rename from app/src/components/ui/dialog.tsx rename to src/components/ui/dialog.tsx diff --git a/app/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx similarity index 100% rename from app/src/components/ui/dropdown-menu.tsx rename to src/components/ui/dropdown-menu.tsx diff --git a/app/src/components/ui/form.tsx b/src/components/ui/form.tsx similarity index 100% rename from app/src/components/ui/form.tsx rename to src/components/ui/form.tsx diff --git a/app/src/components/ui/input-group.tsx b/src/components/ui/input-group.tsx similarity index 100% rename from app/src/components/ui/input-group.tsx rename to src/components/ui/input-group.tsx diff --git a/app/src/components/ui/input.tsx b/src/components/ui/input.tsx similarity index 100% rename from app/src/components/ui/input.tsx rename to src/components/ui/input.tsx diff --git a/app/src/components/ui/label.tsx b/src/components/ui/label.tsx similarity index 100% rename from app/src/components/ui/label.tsx rename to src/components/ui/label.tsx diff --git a/app/src/components/ui/popover.tsx b/src/components/ui/popover.tsx similarity index 100% rename from app/src/components/ui/popover.tsx rename to src/components/ui/popover.tsx diff --git a/app/src/components/ui/radio-group.tsx b/src/components/ui/radio-group.tsx similarity index 100% rename from app/src/components/ui/radio-group.tsx rename to src/components/ui/radio-group.tsx diff --git a/app/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx similarity index 100% rename from app/src/components/ui/scroll-area.tsx rename to src/components/ui/scroll-area.tsx diff --git a/app/src/components/ui/select.tsx b/src/components/ui/select.tsx similarity index 100% rename from app/src/components/ui/select.tsx rename to src/components/ui/select.tsx diff --git a/app/src/components/ui/separator.tsx b/src/components/ui/separator.tsx similarity index 100% rename from app/src/components/ui/separator.tsx rename to src/components/ui/separator.tsx diff --git a/app/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx similarity index 100% rename from app/src/components/ui/skeleton.tsx rename to src/components/ui/skeleton.tsx diff --git a/app/src/components/ui/slider.tsx b/src/components/ui/slider.tsx similarity index 100% rename from app/src/components/ui/slider.tsx rename to src/components/ui/slider.tsx diff --git a/app/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx similarity index 100% rename from app/src/components/ui/sonner.tsx rename to src/components/ui/sonner.tsx diff --git a/app/src/components/ui/switch.tsx b/src/components/ui/switch.tsx similarity index 100% rename from app/src/components/ui/switch.tsx rename to src/components/ui/switch.tsx diff --git a/app/src/components/ui/table.tsx b/src/components/ui/table.tsx similarity index 100% rename from app/src/components/ui/table.tsx rename to src/components/ui/table.tsx diff --git a/app/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx similarity index 100% rename from app/src/components/ui/textarea.tsx rename to src/components/ui/textarea.tsx diff --git a/app/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx similarity index 100% rename from app/src/components/ui/tooltip.tsx rename to src/components/ui/tooltip.tsx diff --git a/app/src/hooks/use-run-socket.ts b/src/hooks/use-run-socket.ts similarity index 100% rename from app/src/hooks/use-run-socket.ts rename to src/hooks/use-run-socket.ts diff --git a/app/src/lib/auth/guard.ts b/src/lib/auth/guard.ts similarity index 100% rename from app/src/lib/auth/guard.ts rename to src/lib/auth/guard.ts diff --git a/app/src/lib/auth/password.ts b/src/lib/auth/password.ts similarity index 100% rename from app/src/lib/auth/password.ts rename to src/lib/auth/password.ts diff --git a/app/src/lib/auth/rate-limit.ts b/src/lib/auth/rate-limit.ts similarity index 100% rename from app/src/lib/auth/rate-limit.ts rename to src/lib/auth/rate-limit.ts diff --git a/app/src/lib/auth/session.ts b/src/lib/auth/session.ts similarity index 100% rename from app/src/lib/auth/session.ts rename to src/lib/auth/session.ts diff --git a/app/src/lib/auth/sync.ts b/src/lib/auth/sync.ts similarity index 100% rename from app/src/lib/auth/sync.ts rename to src/lib/auth/sync.ts diff --git a/app/src/lib/auth/tokens.ts b/src/lib/auth/tokens.ts similarity index 100% rename from app/src/lib/auth/tokens.ts rename to src/lib/auth/tokens.ts diff --git a/app/src/lib/config/load.ts b/src/lib/config/load.ts similarity index 100% rename from app/src/lib/config/load.ts rename to src/lib/config/load.ts diff --git a/app/src/lib/config/schema.ts b/src/lib/config/schema.ts similarity index 100% rename from app/src/lib/config/schema.ts rename to src/lib/config/schema.ts diff --git a/app/src/lib/config/serialize.ts b/src/lib/config/serialize.ts similarity index 100% rename from app/src/lib/config/serialize.ts rename to src/lib/config/serialize.ts diff --git a/app/src/lib/config/ui-control-map.ts b/src/lib/config/ui-control-map.ts similarity index 100% rename from app/src/lib/config/ui-control-map.ts rename to src/lib/config/ui-control-map.ts diff --git a/app/src/lib/db/client.ts b/src/lib/db/client.ts similarity index 100% rename from app/src/lib/db/client.ts rename to src/lib/db/client.ts diff --git a/app/src/lib/db/schema.ts b/src/lib/db/schema.ts similarity index 100% rename from app/src/lib/db/schema.ts rename to src/lib/db/schema.ts diff --git a/app/src/lib/docs.ts b/src/lib/docs.ts similarity index 60% rename from app/src/lib/docs.ts rename to src/lib/docs.ts index 137c8e0..317c8b9 100644 --- a/app/src/lib/docs.ts +++ b/src/lib/docs.ts @@ -27,11 +27,15 @@ export function getDocMeta(slug: string): DocMeta | undefined { return DOCS.find((doc) => doc.slug === slug); } -// docs/ ships at the repo root, one level up from this Next app - resolved at runtime rather -// than imported, since the compiled Route Handler module graph doesn't preserve source-relative -// paths (same reasoning as config path resolution in lib/config/load.ts). +// Resolved from TRIGGERSHELL_APP_ROOT (set once in server.ts), not `process.cwd()` or +// `import.meta.dirname` - this file is read from a Route Handler compiled through Next's own +// module graph, which is a separate module instantiation from server.ts and doesn't preserve +// source-relative `import.meta` paths (see the `globalThis` comment in `runner/events.ts`). +// Falls back to a source-relative resolution for contexts where server.ts never ran (e.g. tests). function docsDir(): string { - return path.resolve(process.cwd(), "..", "docs"); + const appRoot = + process.env.TRIGGERSHELL_APP_ROOT ?? path.resolve(import.meta.dirname, "..", ".."); + return path.resolve(appRoot, "docs"); } export function readDocContent(doc: DocMeta): string | null { diff --git a/app/src/lib/runner/build-args.ts b/src/lib/runner/build-args.ts similarity index 100% rename from app/src/lib/runner/build-args.ts rename to src/lib/runner/build-args.ts diff --git a/app/src/lib/runner/engine.ts b/src/lib/runner/engine.ts similarity index 100% rename from app/src/lib/runner/engine.ts rename to src/lib/runner/engine.ts diff --git a/app/src/lib/runner/events.ts b/src/lib/runner/events.ts similarity index 100% rename from app/src/lib/runner/events.ts rename to src/lib/runner/events.ts diff --git a/app/src/lib/runner/log-file.ts b/src/lib/runner/log-file.ts similarity index 100% rename from app/src/lib/runner/log-file.ts rename to src/lib/runner/log-file.ts diff --git a/app/src/lib/runner/registry.ts b/src/lib/runner/registry.ts similarity index 100% rename from app/src/lib/runner/registry.ts rename to src/lib/runner/registry.ts diff --git a/app/src/lib/utils.ts b/src/lib/utils.ts similarity index 100% rename from app/src/lib/utils.ts rename to src/lib/utils.ts diff --git a/app/src/lib/validation/variable-schema.ts b/src/lib/validation/variable-schema.ts similarity index 100% rename from app/src/lib/validation/variable-schema.ts rename to src/lib/validation/variable-schema.ts diff --git a/app/src/lib/ws/protocol.ts b/src/lib/ws/protocol.ts similarity index 100% rename from app/src/lib/ws/protocol.ts rename to src/lib/ws/protocol.ts diff --git a/app/src/lib/ws/server.ts b/src/lib/ws/server.ts similarity index 100% rename from app/src/lib/ws/server.ts rename to src/lib/ws/server.ts diff --git a/app/src/proxy.ts b/src/proxy.ts similarity index 100% rename from app/src/proxy.ts rename to src/proxy.ts diff --git a/app/templates/triggershell.yml b/templates/triggershell.yml similarity index 100% rename from app/templates/triggershell.yml rename to templates/triggershell.yml diff --git a/app/tsconfig.json b/tsconfig.json similarity index 100% rename from app/tsconfig.json rename to tsconfig.json