git clone https://github.com/kaonis/woly-server.git
cd woly-server
nvm use # Node.js 24
npm install # All workspaces
npm run dev:doctor # Verify required local tooling/hooks
npm run build # Protocol first, then apps
npm run test # Verify everything worksCopy environment files before running dev servers:
cp apps/node-agent/.env.example apps/node-agent/.env
cp apps/cnc/.env.example apps/cnc/.env- Create a branch from
main - Make changes
- Run
npm run build && npm run typecheck && npm run testto verify - Push and open a PR against
main
Local hooks are managed by Husky (npm install runs npm run prepare):
pre-commit: staged secret scan (gitleaks) +lint-staged.pre-push:npm run prepush:checks(typecheck+ related Jest tests).commit-msg: commit message linting viacommitlint(Conventional Commits).
Install gitleaks locally so pre-commit can run:
brew install gitleaksOptional policy check for maintainers:
npm run ci:branch-protection:checkFor CNC feature work, follow docs/CNC_SYNC_POLICY.md.
Before merge:
- link issues in both repos (
kaonis/woly-serverandkaonis/woly) - keep the 3-part chain explicit:
- protocol contract
- backend endpoint/command
- frontend integration
- run contract gates (mobile compatibility + protocol consumer typecheck when protocol is touched)
This is an npm workspaces monorepo with Turborepo for task orchestration.
Run a command in a specific workspace:
npm run test -w apps/node-agent
npm run build -w packages/protocolBuild order matters. packages/protocol must build before either app. Turborepo handles this automatically via turbo.json, but if running tsc directly in an app, build protocol first.
Adding a dependency to a workspace:
npm install axios -w apps/node-agent # Runtime dep
npm install @types/ws -w apps/cnc --save-dev # Dev depShared dev dependencies (typescript, eslint, prettier) live in the root package.json.
When modifying packages/protocol/src/index.ts:
- Make the change
- Run
npm run build -w packages/protocolto regeneratedist/ - Run
npm run typecheckto verify both apps still compile - Run
npm run testto verify no runtime regressions - If the mobile app needs the update, publish to npm (see below)
The protocol package is published to npm for the mobile app to consume. Use these scripts from the monorepo root:
# 1. Bump version (creates a git commit and tag)
npm run protocol:version:patch # Bug fixes (1.1.0 → 1.1.1)
npm run protocol:version:minor # New features (1.1.0 → 1.2.0)
npm run protocol:version:major # Breaking changes (1.1.0 → 2.0.0)
# 2. Build and publish to npm
npm run protocol:publish # Publish with 'latest' tag
npm run protocol:publish:next # Publish with 'next' tag (for pre-releases)Notes:
protocol:publishautomatically runsprotocol:buildbefore publishing- Requires npm authentication and publish permissions for
@kaonisscope - The
publishConfig.access: "public"in package.json ensures scoped packages are published publicly - Monorepo apps always use the workspace-linked source, so publishing only affects the mobile app
All workspaces extend tsconfig.base.json which enables strict mode. Key settings:
noUnusedLocals: true/noUnusedParameters: true— prefix unused params with_strict: true— no implicit any, strict null checks, etc.- Express 5 types:
req.paramsvalues arestring | string[], cast withas string
Test files use tsconfig.test.json which relaxes unused variable checks.
npm run test # All workspaces
npm run test:ci # CI mode with coverage
npm run test -w apps/cnc # Single workspaceIf better-sqlite3 fails after switching Node versions:
npm rebuild better-sqlite3 --build-from-sourceBuild images from the repo root (Dockerfiles copy root workspace files):
docker build -f apps/node-agent/Dockerfile -t woly-node-agent .
docker build -f apps/cnc/Dockerfile -t woly-cnc .The node agent requires --net host for ARP scanning to discover devices on the local network.
- Formatting: Prettier (run
npm run format) - Linting: ESLint with TypeScript plugin (run
npm run lint) - Logging: Winston with structured object context, not string interpolation
- Error handling: Throw
AppErrorinstances, caught by global error handler middleware