diff --git a/.github/workflows/code-qa.yml b/.github/workflows/code-qa.yml index b9f0b54b36..2d85b6e578 100644 --- a/.github/workflows/code-qa.yml +++ b/.github/workflows/code-qa.yml @@ -66,6 +66,8 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup-node-pnpm + with: + install-args: "--frozen-lockfile" - name: Verify all translations are complete run: node scripts/find-missing-translations.js @@ -76,6 +78,8 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup-node-pnpm + with: + install-args: "--frozen-lockfile" - name: Verify Knip guardrails run: pnpm test:knip-policy - name: Run knip checks @@ -90,6 +94,8 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup-node-pnpm + with: + install-args: "--frozen-lockfile" - name: Check formatting run: pnpm format:check - name: Lint @@ -163,6 +169,8 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup-node-pnpm + with: + install-args: "--frozen-lockfile" - name: Restore Turbo cache id: turbo-cache uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 diff --git a/apps/cli/package.json b/apps/cli/package.json index 21c4deef9f..0c67eac69f 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -9,8 +9,8 @@ "roo": "dist/index.js" }, "scripts": { - "format": "prettier --write 'src/**/*.ts'", - "lint": "eslint src --ext .ts --max-warnings=0", + "format": "prettier --write 'src/**/*.{ts,tsx}'", + "lint": "eslint src --ext .ts,.tsx --max-warnings=0", "check-types": "tsc --noEmit", "test": "vitest run", "test:coverage": "vitest run --coverage", diff --git a/knip.json b/knip.json index 5f93aa1438..6f57a2fe54 100644 --- a/knip.json +++ b/knip.json @@ -3,14 +3,11 @@ "ignore": [ "apps/vscode-e2e/**", "scripts/**", - "apps/cli/scripts/**", - "**/__tests__/**!", "packages/core/src/custom-tools/__tests__/fixtures/**", "packages/core/src/custom-tools/__tests__/fixtures-override/**", "src/integrations/misc/__tests__/performance/**", "src/integrations/terminal/__tests__/setupTerminalTests.ts", "src/integrations/terminal/__tests__/streamUtils/index.ts", - "src/services/tree-sitter/__tests__/fixtures/sample-python.ts", "src/services/tree-sitter/__tests__/helpers.ts" ], "ignoreDependencies": ["lint-staged"], @@ -43,7 +40,7 @@ ] }, "webview-ui": { - "entry": ["src/index.tsx!", "src/**/*.visual.tsx", "src/**/*.visual.{fixture,i18n}.{ts,tsx}"], + "entry": ["src/**/*.visual.tsx", "src/**/*.visual.{fixture,i18n}.{ts,tsx}"], "project": [ "src/**/*.{ts,tsx}!", "../src/shared/*.ts!", @@ -66,7 +63,6 @@ ] }, "apps/cli": { - "ignore": ["eslint.config.mjs", "scripts/**"], "project": ["src/**/*.ts!", "src/**/*.tsx!"], "ignoreDependencies": ["@vscode/ripgrep"] }, diff --git a/package.json b/package.json index ef599e6605..71b9392f6c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "install": "node scripts/bootstrap.mjs", "install:all": "node scripts/bootstrap.mjs", "lint": "turbo lint --log-order grouped --output-logs new-only", - "check-types": "turbo check-types --log-order grouped --output-logs new-only", + "check-types": "tsc -p tsconfig.json --noEmit && turbo check-types --log-order grouped --output-logs new-only", "test": "turbo test --log-order grouped --output-logs new-only", "test:code-qa-ci": "node --test scripts/code-qa-workflow.test.mjs", "solheim:smoke": "node --import tsx scripts/solheim-smoke/driver.mts", @@ -27,7 +27,7 @@ "parser-scope:model-check": "node scripts/run-native-tool-call-parser-scoping.mjs", "mcp:integration-check": "tsx scripts/check-mcp-oauth-integration.ts", "test:coverage": "turbo test:coverage --log-order grouped --output-logs new-only", - "format": "turbo format --log-order grouped --output-logs new-only", + "format": "prettier --write .", "format:check": "prettier --check .", "build": "turbo build --log-order grouped --output-logs new-only", "bundle": "turbo bundle --log-order grouped --output-logs new-only", @@ -36,9 +36,9 @@ "install:vsix": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix && node scripts/install-vsix.js", "code-server:install": "node scripts/code-server.js", "changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .", - "knip": "knip", + "knip": "knip --treat-config-hints-as-errors", "npm:publish:types": "pnpm --filter @roo-code/types npm:publish", - "knip:production": "knip --production", + "knip:production": "knip --production --treat-config-hints-as-errors", "test:knip-policy": "node --test scripts/knip-policy.test.mjs" }, "devDependencies": { @@ -71,7 +71,7 @@ "webview-ui/src/**/*.{ts,tsx}": [ "pnpm --dir webview-ui exec eslint --max-warnings=0 --no-warn-ignored" ], - "apps/cli/src/**/*.ts": [ + "apps/cli/src/**/*.{ts,tsx}": [ "pnpm --dir apps/cli exec eslint --max-warnings=0 --no-warn-ignored" ], "apps/vscode-e2e/src/**/*.ts": [ diff --git a/packages/config-eslint/eslint.config.js b/packages/config-eslint/eslint.config.js new file mode 100644 index 0000000000..c34d9ac863 --- /dev/null +++ b/packages/config-eslint/eslint.config.js @@ -0,0 +1,3 @@ +import { config } from "./base.js" + +export default config diff --git a/packages/config-eslint/package.json b/packages/config-eslint/package.json index b73c800f7c..af9fa5eab4 100644 --- a/packages/config-eslint/package.json +++ b/packages/config-eslint/package.json @@ -10,6 +10,7 @@ "./api-provider-hygiene": "./api-provider-hygiene.js" }, "scripts": { + "lint": "eslint . --max-warnings=0", "test": "node --test provider-identifiers.test.js api-provider-hygiene.test.js" }, "devDependencies": { diff --git a/scripts/check-mcp-oauth-integration.ts b/scripts/check-mcp-oauth-integration.ts index e50fa67456..9f6c18f07b 100644 --- a/scripts/check-mcp-oauth-integration.ts +++ b/scripts/check-mcp-oauth-integration.ts @@ -25,7 +25,7 @@ assert.deepEqual(MCP_OAUTH_GRANT_TYPES, ["authorization_code", "refresh_token"]) for (let mask = 0; mask < 1 << advertisedGrantTypes.length; mask++) { const advertised = advertisedGrantTypes.filter((_, index) => mask & (1 << index)) const selected = selectMcpOAuthGrantTypes(advertised) - const expected = MCP_OAUTH_GRANT_TYPES.filter((grantType) => advertised.includes(grantType)) + const expected: string[] = MCP_OAUTH_GRANT_TYPES.filter((grantType) => advertised.includes(grantType)) // Normative MUST: RFC 7591 section 2 says grant_types describes grants the // client can use, and each token-endpoint grant_type must match its registered diff --git a/scripts/check-provider-handoff-scheduler.ts b/scripts/check-provider-handoff-scheduler.ts index e6c4c29a38..c8faebe709 100644 --- a/scripts/check-provider-handoff-scheduler.ts +++ b/scripts/check-provider-handoff-scheduler.ts @@ -495,5 +495,5 @@ function formatViolation(policy: Policy, violations: string[], trace: TraceStep[ } function task(id: string, status: HistoryItem["status"], parentTaskId?: string): HistoryItem { - return { id, status, parentTaskId, task: id, ts: 1, tokensIn: 0, tokensOut: 0, totalCost: 0 } + return { id, status, parentTaskId, task: id, number: 1, ts: 1, tokensIn: 0, tokensOut: 0, totalCost: 0 } } diff --git a/scripts/code-qa-workflow.test.mjs b/scripts/code-qa-workflow.test.mjs index 3f83d1129e..5e1e1a59c0 100644 --- a/scripts/code-qa-workflow.test.mjs +++ b/scripts/code-qa-workflow.test.mjs @@ -120,8 +120,8 @@ describe("platform unit-test workflow", () => { describe("Knip quality gate", () => { it("runs analyzer challenge tests and both dependency graphs without allowing failure", () => { const manifest = JSON.parse(fs.readFileSync(path.join(repositoryRoot, "package.json"), "utf8")) - assert.equal(manifest.scripts.knip, "knip") - assert.equal(manifest.scripts["knip:production"], "knip --production") + assert.equal(manifest.scripts.knip, "knip --treat-config-hints-as-errors") + assert.equal(manifest.scripts["knip:production"], "knip --production --treat-config-hints-as-errors") assert.equal(manifest.scripts["test:knip-policy"], "node --test scripts/knip-policy.test.mjs") for (const [stepName, command] of [ ["Verify Knip guardrails", "pnpm test:knip-policy"], @@ -136,3 +136,15 @@ describe("Knip quality gate", () => { assert.doesNotMatch(job, /continue-on-error|if:/) }) }) + +describe("Code QA dependency install", () => { + it("installs every job with a frozen lockfile", () => { + const setups = workflow.match(/uses: \.\/\.github\/actions\/setup-node-pnpm\n/g) ?? [] + const frozen = + workflow.match( + /uses: \.\/\.github\/actions\/setup-node-pnpm\n\s+with:\n\s+install-args: "--frozen-lockfile"\n/g, + ) ?? [] + assert.ok(setups.length > 0, "missing setup-node-pnpm steps") + assert.equal(frozen.length, setups.length) + }) +}) diff --git a/scripts/knip-policy.test.mjs b/scripts/knip-policy.test.mjs index f7ea6b1e6a..cbd7f3f57a 100644 --- a/scripts/knip-policy.test.mjs +++ b/scripts/knip-policy.test.mjs @@ -41,8 +41,23 @@ function fixture(files, run, includeWebview = false) { }), ) if (includeWebview) { - write("webview-ui/package.json", JSON.stringify({ name: "fixture-webview", private: true })) + write( + "webview-ui/package.json", + JSON.stringify({ + name: "fixture-webview", + private: true, + scripts: { dev: "vite" }, + devDependencies: { vite: "8.0.0" }, + }), + ) + write("webview-ui/vite.config.ts", "export default {}\n") + write("webview-ui/index.html", '\n') write("webview-ui/src/index.tsx", 'console.log("application entry")\n') + symlinkSync( + path.join(root, "webview-ui/node_modules"), + path.join(directory, "webview-ui/node_modules"), + "junction", + ) } write("src/extension.ts", 'import { live } from "./helper"\nconsole.log(live)\n') write("src/helper.ts", "export const live = 1\n") diff --git a/tsconfig.json b/tsconfig.json index 44f734c197..34ac10448e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,13 @@ { "extends": "@roo-code/config-typescript/base.json", "compilerOptions": { - "types": ["node"] + "module": "esnext", + "moduleResolution": "Bundler", + // Scripts import src code. Match the src package settings so the root check does not report src errors. + "noUncheckedIndexedAccess": false, + "types": ["node"], + "useUnknownInCatchVariables": false }, "exclude": ["node_modules"], - "include": ["scripts/*.ts"] + "include": ["scripts/*.ts", "src/types/global-agent.d.ts"] } diff --git a/webview-ui/eslint.config.mjs b/webview-ui/eslint.config.mjs index c8b5b49bfb..0d91b86f42 100644 --- a/webview-ui/eslint.config.mjs +++ b/webview-ui/eslint.config.mjs @@ -4,6 +4,7 @@ import { providerIdentifiers, retiredProviderIdentifiers } from "@roo-code/types /** @type {import("eslint").Linter.Config} */ export default [ + { ignores: ["playwright/.cache/**"] }, ...reactConfig, createProviderIdentifierConfig({ providerIdentifiers, retiredProviderIdentifiers }), { @@ -40,6 +41,14 @@ export default [ "no-case-declarations": "off", }, }, + { + files: ["playwright/run-docker.mjs"], + languageOptions: { + globals: { + process: "readonly", + }, + }, + }, { files: ["src/**/*.{ts,tsx}"], rules: { diff --git a/webview-ui/package.json b/webview-ui/package.json index 2ea7e5eea3..89601c1e66 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -3,7 +3,7 @@ "private": true, "type": "module", "scripts": { - "lint": "eslint src --ext=ts,tsx --max-warnings=0 --cache --cache-strategy content --cache-location node_modules/.cache/eslint/.eslintcache", + "lint": "eslint src playwright playwright-ct.config.ts --ext=ts,tsx,mjs --max-warnings=0 --cache --cache-strategy content --cache-location node_modules/.cache/eslint/.eslintcache", "check-types": "tsc --noEmit", "pretest": "turbo run bundle --cwd ..", "test": "vitest run",