From 4a4ee4d5e276ab9c6b35b13d615e4c83472bae9d Mon Sep 17 00:00:00 2001 From: Igor Beylin Date: Mon, 27 Jul 2026 16:07:51 -0400 Subject: [PATCH] chore(lint): add ESLint 9 flat config so npm run lint works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lint script pointed at ESLint 9 with no config file present, so it exited nonzero on every invocation — the script existed but had never been runnable. Adds eslint.config.js (flat, ESM, TypeScript) plus the two devDeps ESLint 9 requires for TS: @eslint/js and typescript-eslint. Not type-aware: tsconfig excludes tests/, so recommendedTypeChecked would fail on the parser rather than on a real rule. no-explicit-any and no-unused-vars land as warn, not error. This codebase has never been linted; the 58 any and 15 unused-binding findings are pre-existing debt made visible rather than a wall of failures on first run. Raise both to error once cleared. Also picks up the generated formatter-ownership block in AGENTS.md. Co-authored-by: Cursor --- AGENTS.md | 17 +++++++++++++++++ eslint.config.js | 38 ++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ 3 files changed, 57 insertions(+) create mode 100644 eslint.config.js diff --git a/AGENTS.md b/AGENTS.md index afeb45b..67425ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -127,3 +127,20 @@ points at a `seed.ts` that does not exist. Follow the code; don't propagate the Done = code + tests + contracts/migrations updated together · `npx tsc --noEmit` and `npx vitest run` green with output shown (or the exact blocker/UNKNOWN stated) · diff reviewed for scope creep · no known unreported regression · Unknowns recorded, never invented. + + + +## Formatter ownership + +Workspace class: `eslint_owned` — Workspaces where ESLint/Prettier config in the repo is authoritative for JS/TS. Python is still Ruff-owned. + +Exactly one formatter owns each language. Do not reformat a file with a tool other than its owner, and do not add config for a competing formatter: the result is a diff that churns on every save. + +| Languages | Owner | Note | +|---|---|---| +| `javascript`, `javascriptreact`, `typescript`, `typescriptreact`, `json`, `jsonc` | eslint (this repo's own config) | do not add a competing formatter config | +| `python` | **ruff** | bound by the governed IDE profile | + +Generated from `environment/ide/policy.json` in the governance clone by `ops/scripts/adapters/agentdocs.sh`. Edit the policy, not this block. + + diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..341f9b3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,38 @@ +// @ts-check +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +// ESLint v9 flat config. This repo is ESM (`"type": "module"`) and TypeScript-only: +// src/ is the shipped surface, tests/ and scripts/ are dev-time TS. The `lint` script +// targets src/ only; the tests/scripts blocks below apply when a wider path is passed. +// +// Not type-aware (`recommended`, not `recommendedTypeChecked`): type-aware linting +// needs a resolved tsconfig program per file, and tsconfig.json excludes tests/, so +// the type-checked preset would error on every test file it was asked to lint. +export default tseslint.config( + { + ignores: ['dist/**', 'node_modules/**', 'coverage/**', 'drizzle/**'], + }, + eslint.configs.recommended, + ...tseslint.configs.recommended, + { + files: ['src/**/*.ts'], + rules: { + // Warn, not error, during the initial rollout: this config is being added to a + // codebase that has never been linted, so pre-existing findings become visible + // debt rather than a wall of failures on the first run. As of this config there + // are 58 `any` warnings and 15 unused-binding warnings, all pre-existing. Raise + // both to 'error' once that backlog is cleared, so new violations block. + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + }, + }, + { + // Tests and one-off scripts legitimately reach for `any` and console output. + files: ['tests/**/*.ts', 'scripts/**/*.ts'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + }, + }, +); diff --git a/package.json b/package.json index 7031230..4a86cbc 100644 --- a/package.json +++ b/package.json @@ -43,12 +43,14 @@ "nodemailer": "^6.9.0" }, "devDependencies": { + "@eslint/js": "^9.39.5", "@types/node": "^22.0.0", "@types/nodemailer": "^6.4.0", "@types/pg": "^8.11.0", "eslint": "^9.0.0", "tsx": "^4.19.0", "typescript": "^5.6.0", + "typescript-eslint": "^8.64.0", "vitest": "^2.1.0", "drizzle-kit": "^0.28.1" },