Repository navigation
build: add ESLint flat config and CI lint step - #57
Merged
Merged
Conversation
Owner
Author
|
CI note: on the first attempt, the macOS |
This was referenced Sep 26, 2026
Baseline @eslint/js + typescript-eslint recommended (not type-checked) via a @borg/eslint-config shim that pins typescript 6.0.3 for typescript-eslint, since the repo's typescript 7 has no JS compiler API. Adds pnpm lint, a Lint step in both CI jobs, and three no-op source fixes. The headless example now loads its plugins with static imports instead of require() so it passes no-require-imports; the README copy is updated to match. README and CONTRIBUTING list pnpm lint with the other checks. Part of #33
danielgerlag
force-pushed
the
build/eslint
branch
from
September 26, 2026 14:35
3b4c6a3 to
e560dda
Compare
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #33. This covers the lint item only:
pnpm lintexists and runs in CI.Head:
e560dda, one commit rebased onto main5817703(after #56).What this adds
eslint.config.mjs(flat config) at the repo root. It uses@eslint/jsrecommended plustypescript-eslintrecommended. The rules are syntax-only, not type-checked: noprojectorprojectService. There are no other plugins and no stylistic rules.tooling/eslint-config(@borg/eslint-config, private, no build/test scripts). It is a three-line re-export shim for@eslint/js,typescript-eslintandglobals.tooling/*is added topnpm-workspace.yaml.lintscript (eslint .) and devDepseslint10.11.0 and@borg/eslint-configworkspace:*.Lintstep in both jobs (verifyandverify (ubuntu-latest)), before Type-check. No other workflow changes.Pinned versions, all from registry.npmjs.org: eslint 10.11.0, @eslint/js 10.0.1, typescript-eslint 8.70.1, globals 17.12.0, typescript 6.0.3 (lint only). The registry config is untouched.
Docs and example (added after the rebase onto #56)
corepack pnpm lintis the first line.pnpm lint, the CI paragraph says both jobs runlint, and the pre-PR sentence reads "pnpm lint,pnpm typecheck, andpnpm test".examples/headless/src/main.ts(added by docs: pitch-first README and plugin authoring guide #56) had 2no-require-importshits: template-stringrequire()for each plugin's manifest and main.borg.plugin.jsonandmain, with an explicitplugins: [...]array. No new disables.loadMain. Because the imports are static, typos now fail at compile time.examples/headless/testchecks that it is verbatim. The example still printsborg.hello: Kernel alive.examples/headless/test/headless.test.tswas already clean.Decision: TypeScript 7 vs typescript-eslint
The repo is on
typescript^7.0.2, the native port. Its npm package has no JS compiler API;require("typescript")is onlyversion.cjs. typescript-eslint 8.70.1, the latest, requires a JS-API TypeScript>=4.8.4 <6.1.0. It crashes on load when itstypescriptpeer resolves to 7.0.2, which is what happens when it is a root devDep. pnpmoverridesdon't apply to peer dependencies; I tried.The fix is to install typescript-eslint through the
@borg/eslint-configworkspace package, which depends ontypescript6.0.3. pnpm resolves the peer inside that importer, so the lint parser gets 6.0.3. The repo's own TypeScript is unchanged:tsc -vis 7.0.2pnpm typecheckstill runs on 7.0.2@typescript-eslint/*with(typescript@6.0.3)and everything else as beforeWhen typescript-eslint supports TS 7, the shim and the 6.0.3 pin can go away.
The config file is
.mjsbecause the rootpackage.jsonhas no"type": "module". With a.jsname, Node printsMODULE_TYPELESS_PACKAGE_JSONon every run. I left the root module type alone; changing it is a repo-wide change.Ignored (generated or build output)
**/dist/**,**/.package/**,**/node_modules/**,**/bundled-plugins.ts,**/bundled-ui-plugins.ts,**/coverage/**,**/.vite/**,playwright-report/**,test-results/**,.research/**. These mirror.gitignoreplus the two generated bundle files. No hand-written source is ignored.Baseline: pure recommended config, 84 errors across 13 rules
no-emptyallowEmptyCatch: true(all 20 were emptycatch {})no-undefscripts/verify-graph-designer.mjs(page.evaluatecallbacks)@typescript-eslint/no-require-importstests/e2e/**/*.tsonly@typescript-eslint/no-unused-vars^_names (all 12 were_-prefixed discards)preserve-caught-errorprefer-constno-control-regex@typescript-eslint/no-this-aliasno-unassigned-varsno-unused-private-class-members@typescript-eslint/no-empty-object-typeno-useless-assignmentno-useless-escapeDisabled rules, to tighten later
Each one has a comment in
eslint.config.mjs.preserve-caught-errorError.cause. Addingcausechanges the thrown error objects.prefer-constletdeclared before a closure that references it, then assigned (e.g.runin loop-manager,disposablein graphs executor). Converting needs restructuring per site.@typescript-eslint/no-require-importstests/e2e/**/*.tsrequire(require.resolve("electron")).no-control-regexpackages/contracts/src/index.ts,packages/kernel/src/tls-service.ts@typescript-eslint/no-this-aliaspackages/kernel/src/tls-service.tsconst self = thisinside ReadableStream/WritableStream callbacks.no-unassigned-varsplugins/mcp-apps/src/ui.tsxref={frame}assigns the variable, which the rule can't see.no-unused-private-class-membersplugins/channel-imap/src/imap-codec.tsImapCodec.#loopis a write-only once-guard.The file-scoped offs stay enforced everywhere else. I checked this with a planted snippet: it fails in a new kernel file and passes only in the listed file. There are no inline
eslint-disablecomments.Source fixes (type-level or no-op; no runtime behavior change)
packages/kernel/src/prompt-assembler.ts:export interface PromptSlot extends PromptSlotContribution {}becomesexport type PromptSlot = PromptSlotContribution. It is the same type, nothing declaration-mergesPromptSlot, and the kernel index re-export is unchanged.packages/kernel/src/model-gateway.ts:existing = await journal.save(...)becomesawait journal.save(...).existingis never read after that point; the save is still awaited.packages/kernel/src/tls-service.ts:/[\[\]]/becomes/[[\]]/. It is the same character class and the regex has no flags.Lockfile
The diff against main is additions only (+749 / -0), regenerated with pnpm 12.0.0 on top of #56's lockfile: the new
tooling/eslint-configimporter, the two root devDeps, and the packages and snapshots they pull in. Nothing existing is re-resolved and the settings are unchanged.Gates (local, Node 24, CI=true, on e560dda)
pnpm install --frozen-lockfilepnpm lintpnpm check:boundariespnpm typechecktsc -v= 7.0.2)pnpm testxvfb-run -a pnpm test:e2e