mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Two independent multipliers were pushing bare `pnpm run lint` past node's default heap: 1. parserOptions.project expanded to every package tsconfig plus the root one — each matched config built its OWN ts.Program, and the dev paths map pulls sibling package SOURCES (plus the vendored Cordis stack) into every such program, so resident memory grew as sum-of-closures, not repo size: ~4.6 GB peak for 425 repo files. projectService shares one tsserver-style graph: ~2.0 GB peak, ~28 s → ~14 s wall. 2. `eslint .` traversed .claude/ harness-local state — stale worktree checkouts there carry tens of thousands of additional .ts files (whole-repo copies), roughly tripling the work again even under the project service. Other checkouts are not this one's sources; ignore them like node_modules. (#169 carries the identical ignore line inside its chain; the hunks dedupe on its next rebase.) Type-aware rules verified live under the service: a floating-promise probe still trips no-floating-promises.
147 lines
6.0 KiB
JavaScript
147 lines
6.0 KiB
JavaScript
import stylistic from '@stylistic/eslint-plugin'
|
|
import tseslint from 'typescript-eslint'
|
|
|
|
/**
|
|
* ESLint flat config. Two layers:
|
|
*
|
|
* 1. typescript-eslint strict-type-checked — correctness rules that need the
|
|
* type checker. The headline rules for this codebase: no-floating-promises
|
|
* and no-misused-promises (an un-awaited promise in the agent loop is our
|
|
* primary bug class), switch-exhaustiveness-check (we switch over
|
|
* merge-extensible unions everywhere).
|
|
* 2. @stylistic — formatting (2-space, no semicolons, single quotes, trailing
|
|
* commas), so style is enforced rather than drifting between agents.
|
|
*
|
|
* vendor/ is linted lightly (style only stays OFF — vendored code keeps
|
|
* upstream style; only a few safety rules apply there) and examples/tests are
|
|
* linted with relaxed unsafe-* rules where mocks intentionally bend types.
|
|
*/
|
|
export default tseslint.config(
|
|
{
|
|
ignores: [
|
|
'**/lib/**',
|
|
'**/node_modules/**',
|
|
'**/.sessions/**',
|
|
'.claude/**', // harness-local state (worktrees, skills) — other checkouts, not this one's sources
|
|
'**/.doc-typecheck-*/**',
|
|
'vendor/**', // vendored source keeps upstream style and idioms
|
|
'**/*.js',
|
|
'**/*.mjs',
|
|
'*.config.ts', // root tool configs (vitest, tsdown) — no project service
|
|
],
|
|
},
|
|
|
|
// --- our packages: full strictness -------------------------------------
|
|
{
|
|
files: ['packages/*/*/src/**/*.ts', 'examples/**/*.ts', 'scripts/**/*.ts'],
|
|
extends: [
|
|
...tseslint.configs.strictTypeChecked,
|
|
],
|
|
languageOptions: {
|
|
parserOptions: {
|
|
// One shared tsserver-style project service instead of 60+ standalone
|
|
// per-package programs: the old `project` glob built every package's
|
|
// full dependency closure (sibling sources via the dev `paths` map +
|
|
// the vendored Cordis stack) as its own program and kept them all
|
|
// resident — ~5 GB peak, an OOM past node's default heap. The service
|
|
// resolves each file to its nearest owning tsconfig and shares the
|
|
// graph.
|
|
projectService: true,
|
|
tsconfigRootDir: import.meta.dirname,
|
|
},
|
|
},
|
|
rules: {
|
|
// The bug class this repo cares most about: lost promises in the loop.
|
|
'@typescript-eslint/no-floating-promises': 'error',
|
|
'@typescript-eslint/no-misused-promises': 'error',
|
|
'@typescript-eslint/require-await': 'error',
|
|
'@typescript-eslint/switch-exhaustiveness-check': ['error', {
|
|
considerDefaultExhaustiveForUnions: true,
|
|
}],
|
|
'@typescript-eslint/no-unnecessary-condition': ['error', {
|
|
allowConstantLoopConditions: true,
|
|
}],
|
|
// `any` requires a justification comment — enforced as: no bare casts.
|
|
'@typescript-eslint/no-explicit-any': 'error',
|
|
// Style points where the codebase intentionally diverges from preset:
|
|
'@typescript-eslint/no-namespace': 'off', // Cordis Config-namespace idiom
|
|
'@typescript-eslint/no-empty-object-type': 'off', // merge-extensible maps
|
|
'@typescript-eslint/no-invalid-void-type': 'off', // event signatures
|
|
'@typescript-eslint/restrict-template-expressions': ['error', {
|
|
allowNumber: true,
|
|
allowBoolean: true,
|
|
}],
|
|
// `void foo()` in arrow listeners is our idiom for intentional fire-and-forget
|
|
'no-void': 'off',
|
|
'@typescript-eslint/no-unused-vars': ['error', {
|
|
argsIgnorePattern: '^_',
|
|
varsIgnorePattern: '^_',
|
|
caughtErrorsIgnorePattern: '^_',
|
|
}],
|
|
},
|
|
},
|
|
|
|
// --- examples: demo code conforms to async interfaces without awaiting ---
|
|
{
|
|
files: ['examples/**/*.ts'],
|
|
rules: {
|
|
'@typescript-eslint/require-await': 'off',
|
|
},
|
|
},
|
|
|
|
// --- tests: same rules, minus the friction that fights test ergonomics --
|
|
{
|
|
files: ['packages/*/*/tests/**/*.ts', 'examples/*/tests/**/*.ts'],
|
|
extends: [
|
|
...tseslint.configs.strictTypeChecked,
|
|
],
|
|
languageOptions: {
|
|
parserOptions: {
|
|
// Same shared project service as the src block: test files resolve
|
|
// through the root tsconfig (its include covers every tests/ tree).
|
|
projectService: true,
|
|
tsconfigRootDir: import.meta.dirname,
|
|
},
|
|
},
|
|
rules: {
|
|
'@typescript-eslint/no-floating-promises': 'error',
|
|
'@typescript-eslint/no-misused-promises': 'error',
|
|
'@typescript-eslint/no-explicit-any': 'error',
|
|
'@typescript-eslint/no-non-null-assertion': 'off', // assertions follow expect()s
|
|
'@typescript-eslint/no-unnecessary-condition': 'off',
|
|
'@typescript-eslint/require-await': 'off', // mock execute() signatures
|
|
'@typescript-eslint/no-empty-function': 'off', // stub agents
|
|
'@typescript-eslint/only-throw-error': 'off', // testing non-Error throws
|
|
'@typescript-eslint/no-namespace': 'off',
|
|
'@typescript-eslint/no-empty-object-type': 'off',
|
|
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
'@typescript-eslint/no-unused-vars': ['error', {
|
|
argsIgnorePattern: '^_',
|
|
varsIgnorePattern: '^_',
|
|
caughtErrorsIgnorePattern: '^_',
|
|
}],
|
|
},
|
|
},
|
|
|
|
// --- formatting (everything we own) -------------------------------------
|
|
{
|
|
files: ['packages/**/*.ts', 'examples/**/*.ts', 'scripts/**/*.ts', 'eslint.config.mjs'],
|
|
plugins: { '@stylistic': stylistic },
|
|
rules: {
|
|
'@stylistic/indent': ['error', 2],
|
|
'@stylistic/semi': ['error', 'never'],
|
|
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
|
'@stylistic/comma-dangle': ['error', 'always-multiline'],
|
|
'@stylistic/eol-last': ['error', 'always'],
|
|
'@stylistic/no-trailing-spaces': 'error',
|
|
'@stylistic/object-curly-spacing': ['error', 'always'],
|
|
'@stylistic/arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }],
|
|
'@stylistic/member-delimiter-style': ['error', {
|
|
multiline: { delimiter: 'none' },
|
|
singleline: { delimiter: 'semi', requireLast: false },
|
|
}],
|
|
'@stylistic/max-len': ['error', { code: 140, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true }],
|
|
},
|
|
},
|
|
)
|