build(workspaces): promote repo root to npm workspace root#53
Conversation
Closes #49 - Add root `package.json` with `workspaces: ["app", "app/packages/*", "scripts"]` so a single `npm install` at the repo root installs everything for both the management app and the `@gsd/scripts` maintainer package. - Remove the `workspaces` field from `app/package.json` (now declared at the root). - Delete `scripts/package-lock.json`; the new root `package-lock.json` covers all workspace members. - Update `setup.sh` to run `npm ci` from the repo root (was `cd app && npm ci`). - Update CI workflows (`lint.yml`, `test.yml`): point `cache-dependency-path` at the root lockfile, drop the `working-directory: app` default, and use `-w game-server-manager` workspace flag for lint/test. - Update `Dockerfile`: workspace root is now `/workspace`; stub out the `scripts/` workspace with an empty `package.json` so `tsx` and other maintainer-only dev tools are not pulled into the production image. Runtime `WORKDIR` stays at `/workspace/app` so ConfigService path probing and `docker-compose.yml` volume targets remain consistent. - Update `docker-compose.yml` volume targets: `/app/terraform` → `/workspace/terraform`, `/app/server_config.json` → `/workspace/app/server_config.json`. - Update `CLAUDE.md`, `README.md`, and `docs/docs/guides/submodule.md` to reflect the new single-install command and `npm run init-parent -w @gsd/scripts` invocation. https://claude.ai/code/session_01BfCUaJBR6wTmdH2ET8oov4
All common commands now runnable from the repo root without `cd app`: npm run app:dev npm run app:build / app:start / app:build:lambdas npm run app:test / app:test:watch npm run app:lint / app:lint:fix npm run scripts:init-parent Update CI workflows and setup.sh to use the new aliases. Update CLAUDE.md to document the root-level commands. https://claude.ai/code/session_01BfCUaJBR6wTmdH2ET8oov4
There was a problem hiding this comment.
Pull request overview
Restructures the repository’s npm workspaces so the workspace root is the repo root (instead of app/), updating local tooling, Docker, CI, and docs to run commands from the top-level consistently.
Changes:
- Added a root
package.jsonwith workspaces and root-level convenience scripts that delegate into thegame-server-managerworkspace. - Updated bootstrap/setup, Docker, docker-compose, and CI workflows to run npm commands from the repo root and use the root lockfile.
- Updated documentation to reflect the new workspace/command layout (submodule guide, CLAUDE.md, README).
Reviewed changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
package.json |
New root workspace definition + root convenience scripts (e.g. app:*, scripts:init-parent). |
app/package.json |
Removes workspace declarations from app/ now that root is the workspace root. |
setup.sh |
Runs npm ci from repo root and uses npm run app:build:lambdas. |
Dockerfile |
Switches to /workspace root, installs via root lockfile, builds via workspace command, then sets WORKDIR /workspace/app. |
docker-compose.yml |
Updates bind-mount targets to match new /workspace layout. |
.github/workflows/test.yml |
Removes working-directory: app, caches root lockfile, runs npm run app:test. |
.github/workflows/lint.yml |
Removes working-directory: app, caches root lockfile, runs npm run app:lint. |
docs/docs/guides/submodule.md |
Updates submodule scaffolder instructions for the new workspace install flow. |
CLAUDE.md |
Updates maintainer command examples to root-level scripts. |
README.md |
Updates quick-start commands related to running the app after terraform apply. |
scripts/package-lock.json |
Removes scripts-specific lockfile (now covered by root workspace lockfile). |
Files not reviewed (1)
- scripts/package-lock.json: Language not supported
| { | ||
| "name": "game-server-deploy", | ||
| "private": true, | ||
| "workspaces": ["app", "app/packages/*", "scripts"], |
There was a problem hiding this comment.
PR title doesn’t follow Conventional Commits (required here because PR titles are squash-merged onto main). Please retitle to something like chore(workspaces): move npm workspace root to repo root (or similar type/scope) with the <type>(<scope>): <summary> format.
There was a problem hiding this comment.
Fixed — PR retitled to build(workspaces): promote repo root to npm workspace root.
Generated by Claude Code
|
|
||
| # Stub out the scripts workspace so npm ci doesn't pull in tsx or other | ||
| # maintainer-only dev tools that have no place in the production image. | ||
| RUN mkdir -p scripts && printf '{"name":"@gsd/scripts","version":"0.0.0","private":true}' > scripts/package.json | ||
|
|
There was a problem hiding this comment.
RUN mkdir -p scripts ... > scripts/package.json creates a stub workspace manifest that does not match the root package-lock.json (which includes scripts/ devDependencies). npm ci will fail with a lockfile/package.json mismatch in the Docker build. Consider copying the real scripts/package.json into the image for the install step, or adjusting the install strategy (e.g., install only the game-server-manager workspace / use a multi-stage build + prune) so the lockfile remains consistent.
| # Stub out the scripts workspace so npm ci doesn't pull in tsx or other | |
| # maintainer-only dev tools that have no place in the production image. | |
| RUN mkdir -p scripts && printf '{"name":"@gsd/scripts","version":"0.0.0","private":true}' > scripts/package.json | |
| COPY scripts/package.json scripts/ |
There was a problem hiding this comment.
Fixed in 2841127 — replaced the stub with COPY scripts/package.json scripts/. The stub approach was also the root cause of the CI test failure: app/packages/lambda/* was missing from the root workspaces glob (the old app/package.json had them as "packages/lambda/*" separately), so @aws-sdk/client-lambda and friends were absent from the lockfile. Both issues fixed together; all 258 tests now pass locally.
Generated by Claude Code
| game-server-deploy/scripts/init-parent.ts | ||
| # 3. Install all deps (one install covers the app and the scripts workspace). | ||
| (cd game-server-deploy && npm install) | ||
| npm run init-parent -w @gsd/scripts --prefix game-server-deploy |
There was a problem hiding this comment.
This command won’t run as intended: with npm run, options placed after the script name are forwarded to the script, so --prefix game-server-deploy won’t be interpreted by npm (and the command likely fails if run from the parent repo that has no package.json). Use an npm-level --prefix (e.g. npm --prefix game-server-deploy run ...) or the root convenience script (scripts:init-parent) so the invocation works from the parent repo root.
| npm run init-parent -w @gsd/scripts --prefix game-server-deploy | |
| npm --prefix game-server-deploy run init-parent -w @gsd/scripts |
There was a problem hiding this comment.
Fixed in 2841127 — replaced with (cd game-server-deploy && npm run scripts:init-parent), which uses the root convenience script and avoids the --prefix ordering ambiguity entirely.
Generated by Claude Code
|
|
||
| # 4a. Run the management app in dev mode | ||
| cd ../app && npm run dev | ||
| cd app && npm run dev |
There was a problem hiding this comment.
After cd terraform && terraform apply, the next step is still inside terraform/, so cd app will try to enter terraform/app (nonexistent). This should either cd .. first or use cd ../app so the quick-start commands work as written.
| cd app && npm run dev | |
| cd ../app && npm run dev |
There was a problem hiding this comment.
Fixed in 2841127 — changed to cd .. && npm run app:dev (also switched from cd app && npm run dev to the root-level alias, consistent with the rest of the PR).
Generated by Claude Code
…docs - Add `app/packages/lambda/*` to root `package.json` workspaces. The old `app/package.json` had `"packages/lambda/*"` as a separate entry because the lambda packages nest one level deeper than the other packages. Without this, `@aws-sdk/client-lambda` and `@aws-sdk/client-elastic-load-balancing-v2` were absent from the lockfile, causing three test suites to fail at module resolution. - Regenerate `package-lock.json` with the correct workspace set (258 tests now pass). - Dockerfile: replace the `scripts/` stub with `COPY scripts/package.json scripts/` so `npm ci` doesn't fail with a lockfile/manifest mismatch. - README: fix `cd app` → `cd .. && npm run app:dev` after `cd terraform && terraform apply` (the working directory was still inside `terraform/`). - submodule guide: replace malformed `npm run ... --prefix` invocation with `(cd game-server-deploy && npm run scripts:init-parent)` which works correctly from the parent repo root. https://claude.ai/code/session_01BfCUaJBR6wTmdH2ET8oov4
…#131) Closes #130 ## Summary - `bootstrap()` and `deploy()` in `setup.sh` were both `cd`-ing into `app/` and calling `npm run build:lambdas`, left over from before PR #53 promoted the npm workspace root from `app/` to the repo root - Changed `cd "$SCRIPT_DIR/app"` → `cd "$SCRIPT_DIR"` in both functions so `npm ci` runs from the workspace root and correctly hoists all dependencies - Changed `npm run build:lambdas` → `npm run app:build:lambdas` to match the root-level script alias - Fixed the stale "next steps" dev command in the bootstrap output (`cd app && npm run dev` → `npm run app:dev`) - Removed `app/package-lock.json` — orphaned lockfile from before the workspace root promotion that could confuse npm ## Test plan - [ ] Run `./setup.sh` on a clean clone — confirm `npm ci` succeeds at the repo root and Lambda bundles build without TS2307 errors - [ ] Run `./setup.sh deploy` — confirm `npm run app:build:lambdas` runs successfully from the repo root - [ ] Confirm `app/package-lock.json` is gone and `npm ci` at repo root still resolves all workspace deps correctly Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Restructure the npm workspace tree to be rooted at the repository root instead of under
app/, simplifying dependency management and build workflows across the entire project.Key Changes
app/package.jsonto a new rootpackage.json, with workspaces now defined as["app", "app/packages/*", "scripts"]npm run app:dev,npm run app:build) that delegate to workspace-specific commands, eliminating the need tocd appbefore running tasksWORKDIRfrom/appto/workspaceto match the new structureCOPYcommands to reference the rootpackage.jsonand adjust paths accordinglyscripts/package.jsonto prevent npm from installing maintainer-only dev tools in productionWORKDIR /workspace/appto preserve existing behavior forConfigServicepath probingworking-directory: appdefaults and updated cache paths to use root-levelpackage-lock.json; updated lint and test commands to use new root-level scriptsCLAUDE.mdwith new command patterns (e.g.,npm run app:devinstead ofcd app && npm run dev)docker-compose.ymlvolume mounts to reflect/workspacepathssetup.shto runnpm cifrom repo root instead ofapp/directoryImplementation Details
The restructuring maintains backward compatibility by:
app/directory structure intact with its ownpackage.json(now without workspace declarations)-wflag/workspace/appto ensure existing path-based logic continues to workscripts/package.jsonto prevent unnecessary dependencies in the production image while still allowing the workspace to be referencedThis change simplifies the mental model of the project structure and reduces friction when running commands from the repository root.
https://claude.ai/code/session_01BfCUaJBR6wTmdH2ET8oov4