diff --git a/backend/Dockerfile b/backend/Dockerfile index c4feea1d00..9e8e139bf9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,3 +1,22 @@ +# Build stage: dev dependencies are needed for tsc and never ship. +FROM node:22 AS build + +WORKDIR /app + +COPY package*.json ./ + +# Install all dependencies including dev dependencies +RUN npm install --include=dev + +COPY . . + +# Compile TypeScript to dist/ +RUN npm run build + +# Copy non-JS assets that tsc doesn't copy +RUN cp -r external dist/external 2>/dev/null || true + +# Runtime stage FROM node:22 WORKDIR /app @@ -54,16 +73,14 @@ ENV OPENUI_TELEMETRY_DISABLED=1 COPY package*.json ./ -# Install all dependencies including dev dependencies -RUN npm install --include=dev +# Production dependencies only. Dev tooling (jest, eslint, ts-node, typescript, +# mongodb-memory-server, ...) stays in the build stage and never reaches prod. +RUN npm ci --omit=dev COPY . . -# Compile TypeScript to dist/ -RUN npm run build - -# Copy non-JS assets that tsc doesn't copy -RUN cp -r external dist/external 2>/dev/null || true +# Compiled output from the build stage: dist/ with config/ and external/ in place +COPY --from=build /app/dist ./dist EXPOSE 5000 diff --git a/backend/__tests__/unit/scripts/migrate-github-issue-write-capability.test.js b/backend/__tests__/unit/scripts/migrate-github-issue-write-capability.test.js index dbf1b03489..c5997ced9d 100644 --- a/backend/__tests__/unit/scripts/migrate-github-issue-write-capability.test.js +++ b/backend/__tests__/unit/scripts/migrate-github-issue-write-capability.test.js @@ -29,7 +29,7 @@ describe('migrateGitHubIssueWriteCapability', () => { test('exposes the migration through the backend package scripts for deploy operators', () => { expect(backendPackage.scripts['migrate:github-issue-write-capability']) - .toContain('migrate-github-issue-write-capability.ts'); + .toBe('node dist/scripts/migrate-github-issue-write-capability.js'); }); test('grants every legacy install for a configured dev identity once, while leaving other identities ungranted', async () => { diff --git a/backend/package-lock.json b/backend/package-lock.json index d95894451a..4860497aea 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -29,6 +29,7 @@ "express-async-errors": "3.1.1", "express-rate-limit": "^8.3.2", "helmet": "^7.1.0", + "json5": "^2.2.3", "jsonwebtoken": "^9.0.0", "mongodb": "^6.3.0", "mongoose": "^7.0.3", @@ -8978,7 +8979,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -19641,8 +19642,7 @@ "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonify": { "version": "0.0.1", diff --git a/backend/package.json b/backend/package.json index c8f05804ae..127fe4f6f8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,7 @@ "start": "node dist/server.js", "dev": "nodemon --exec 'ts-node --transpile-only' server.ts", "migrate-files": "node migrations/migrateFilesToDB.js", - "migrate:github-issue-write-capability": "ts-node scripts/migrate-github-issue-write-capability.ts", + "migrate:github-issue-write-capability": "node dist/scripts/migrate-github-issue-write-capability.js", "test": "jest", "test:temp-cleanup": "node scripts/verify-jest-temp-cleanup.js", "test:watch": "jest --watch", @@ -23,19 +23,19 @@ "discord:register": "node scripts/register-discord-commands.js", "discord:list": "node scripts/register-discord-commands.js list", "bootstrap:clawd-bot": "node scripts/bootstrap-clawd-bot.js", - "backfill:attention-items": "ts-node scripts/backfill-attention-items.ts", - "backfill:message-author-kind": "ts-node scripts/backfill-message-author-kind.ts", - "backfill:local-messages": "ts-node scripts/backfill-local-messages-to-pg.ts", - "migrate:task-priority": "ts-node scripts/migrate-task-priority.ts", - "migrate:task-source-ref-identity": "ts-node scripts/migrate-task-source-ref-identity.ts", - "sweep:resolved-mention-attention": "ts-node scripts/sweep-resolved-mention-attention.ts", - "audit:replied-attention-stamps": "ts-node scripts/audit-replied-attention-stamps.ts", - "sweep:done-task-handoffs": "ts-node scripts/sweep-done-task-handoffs.ts", - "sweep:leftover-runtime-tokens": "ts-node scripts/sweep-leftover-runtime-tokens.ts", - "sweep:stale-digest": "ts-node scripts/sweep-stale-digest.ts", - "backfill:hosted-mcp-client-id": "ts-node scripts/backfill-hosted-mcp-client-id.ts", - "revive:native-installations": "ts-node scripts/revive-native-installations.ts", - "set:agent-descriptions": "ts-node scripts/set-agent-descriptions.ts", + "backfill:attention-items": "node dist/scripts/backfill-attention-items.js", + "backfill:message-author-kind": "node dist/scripts/backfill-message-author-kind.js", + "backfill:local-messages": "node dist/scripts/backfill-local-messages-to-pg.js", + "migrate:task-priority": "node dist/scripts/migrate-task-priority.js", + "migrate:task-source-ref-identity": "node dist/scripts/migrate-task-source-ref-identity.js", + "sweep:resolved-mention-attention": "node dist/scripts/sweep-resolved-mention-attention.js", + "audit:replied-attention-stamps": "node dist/scripts/audit-replied-attention-stamps.js", + "sweep:done-task-handoffs": "node dist/scripts/sweep-done-task-handoffs.js", + "sweep:leftover-runtime-tokens": "node dist/scripts/sweep-leftover-runtime-tokens.js", + "sweep:stale-digest": "node dist/scripts/sweep-stale-digest.js", + "backfill:hosted-mcp-client-id": "node dist/scripts/backfill-hosted-mcp-client-id.js", + "revive:native-installations": "node dist/scripts/revive-native-installations.js", + "set:agent-descriptions": "node dist/scripts/set-agent-descriptions.js", "sync:seats-record": "node scripts/sync-seats-record.js", "tsc:check": "tsc --noEmit -p tsconfig.typescheck.json", "tsc:check:all": "tsc --noEmit" @@ -61,6 +61,7 @@ "express-async-errors": "3.1.1", "express-rate-limit": "^8.3.2", "helmet": "^7.1.0", + "json5": "^2.2.3", "jsonwebtoken": "^9.0.0", "mongodb": "^6.3.0", "mongoose": "^7.0.3", diff --git a/docs/runbooks/migrate-chat-token-copies.md b/docs/runbooks/migrate-chat-token-copies.md index 88d474530f..3f4ad540cc 100644 --- a/docs/runbooks/migrate-chat-token-copies.md +++ b/docs/runbooks/migrate-chat-token-copies.md @@ -36,10 +36,10 @@ key ring (`CONNECTOR_SECRET_KEYS`, `CONNECTOR_SECRET_ACTIVE_KEY`) supplied by th existing ops-runner secret environment (never paste them into a command): ```sh -npx ts-node scripts/migrate-chat-token-copies.ts +node dist/scripts/migrate-chat-token-copies.js # Review the DRY-RUN counts by type, then explicitly apply: -npx ts-node scripts/migrate-chat-token-copies.ts --apply -npx ts-node scripts/migrate-chat-token-copies.ts +node dist/scripts/migrate-chat-token-copies.js --apply +node dist/scripts/migrate-chat-token-copies.js ``` **What the counts mean.** The final dry run should report zero candidates and diff --git a/docs/runbooks/scrub-feed-token-copies.md b/docs/runbooks/scrub-feed-token-copies.md index e06381710b..917e5c3525 100644 --- a/docs/runbooks/scrub-feed-token-copies.md +++ b/docs/runbooks/scrub-feed-token-copies.md @@ -17,10 +17,10 @@ From the deployed backend directory, with `MONGO_URI` supplied by the existing ops-runner secret environment (never paste it into a command): ```sh -npx ts-node scripts/scrub-feed-token-copies.ts +node dist/scripts/scrub-feed-token-copies.js # Review DRY-RUN counts by type, then explicitly apply: -npx ts-node scripts/scrub-feed-token-copies.ts --apply -npx ts-node scripts/scrub-feed-token-copies.ts +node dist/scripts/scrub-feed-token-copies.js --apply +node dist/scripts/scrub-feed-token-copies.js ``` The final dry run should report zero candidates for both types. Reports contain