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.
Move the 18 flat packages/<name> packages into role-grouped dirs:
core/, llm/, bash/, session-persistence/, ui/, support/. Group dirs are
pure containers; each package keeps its @deepseek-ai/dsh-* name.
Collapse the per-package tsconfig paths maps (base + typecheck) into one
@deepseek-ai/dsh-* wildcard with a candidate per group, and derive the
publint list from the hierarchy. Update all depth-coupled globs/configs
(workspace, tsdown, vitest, eslint, knip, tsconfig includes/refs,
per-package tsconfigs, generators, doc-script scopes, type-equiv manifest)
and the cross-package/script relative imports in tests.
Fix doc-typecheck's workspacePaths() to parse tsconfig JSONC via the
TypeScript API instead of a regex comment-strip, which corrupted the
new wildcard `/*/` path candidates.
WIP: doc cross-links and package/RFC docs still to update.
Flat config with two layers. Correctness (type-checked): the headline
rules for this codebase are no-floating-promises / no-misused-promises
(a lost promise in the agent loop is our primary bug class),
switch-exhaustiveness-check (we switch over merge-extensible unions
everywhere), no-unnecessary-condition, require-await, and
no-explicit-any. Style (@stylistic): 2-space, no semicolons, single
quotes, trailing commas, max-len 140 — the existing house style, now
enforced instead of drifting between agents. vendor/ is excluded
(vendored source keeps upstream style); tests relax the rules that
fight test ergonomics (non-null assertions after expects, async mock
signatures, non-Error throws).
Code adjusted to pass: registry disposers wrap ctx.effect's
promise-returning disposer behind a sync () => void (our public API),
BlockAssembler gains an invariant-checking mustGet instead of non-null
assertions, lastTurnNumber uses findLast, waterfall tails return
Promise.resolve instead of async-without-await arrows, and the two
deliberate suppressions (non-exhaustive derivation switch, unbound
execute pass-through) carry justification comments.
yarn lint / yarn lint:fix added.