chore: housekeeping & make eslint happy - #488
Conversation
prefer-array-from-mapper, prefer-timer-args, prefer-slice-over-split-index, prefer-string-code-point-operations; foxts added to schema for split-nth
…iberate effect patterns
…omise/no-nesting warnings
…ray-reduce-to-object
Greptile SummaryThis housekeeping PR resolves existing ESLint violations across the monorepo while preserving the application’s overall architecture.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/src/shell/desktop-shell.tsx | Replaces layout-effect-driven panel host attachment with stable callback refs; no eligible follow-up defect was established. |
| packages/presentation/ui/src/keyboard/hooks.ts | Refactors keyboard listener and registration hooks for lint compliance; no publishable follow-up issue was established. |
| packages/foundation/schema/src/remote-config.ts | Applies utility and iteration refactors to remote configuration handling without an established contract regression. |
| packages/host/agent-adapter/src/native/claude-code.ts | Performs extensive lint-oriented control-flow and iteration cleanup in the Claude Code adapter. |
| pnpm-lock.yaml | Regenerates dependency resolution after workspace-wide utility and lint-tool upgrades. |
Reviews (4): Last reviewed commit: "Update packages/host/agent-adapter/src/n..." | Re-trigger Greptile
There was a problem hiding this comment.
ℹ️ No correctness defects found. Two process concerns (undeclared dependency scope, one release-age pin) and a few nitpicks.
Reviewed changes
- A repo-wide ESLint codemod across 340 files: ~500
for...of→ hoisted-lenindexed loops,Object.fromEntries→reduceobject builders,[...x].map()→Array.from(x, fn),localeCompare→ module-scopeIntl.Collator,setTimeout(() => f(a), ms)→setTimeout(f, ms, a),codePointAt→charCodeAt, and thesukka/*→vibe-proof/*rule-id namespace migration. eslint-suppressions.json(ESLint native bulk suppressions) is deleted outright.- ~15 new
split0th/split1stcall sites fromfoxts/split-nth, replacingstr.split(sep, n)[i], including two request-routing hot paths (transport/src/http-server.ts,daemon/src/sim/mcp-endpoint.ts). - Genuine behavioral rewrites folded into the sweep:
desktop-shell.tsxmoves fromuseState+useLayoutEffectDOM capture to React 19 callback refs;transport/src/hub.tsconverts anif/else ifchain toswitch (p.kind);keyboard/hooks.tsadoptsfoxact/use-abortable-effectwith{ signal }listener teardown;brand-assets.ts/verify-artifactsswitch tolstatSync(…, { throwIfNoEntry: false })with an explicitundefinedguard. - Dependency and toolchain bumps:
foxts→^5.9.1across 8 packages,eslint^10.8.0→^10.9.1, thesukkaconfig/react/formatter trio^8.14.2→^9.0.1(major),packageManagerpnpm@11.10.0→pnpm@11.24.0,verkit@0.3.2added, and ~2,874 lockfile lines.
✅ What I verified rather than assumed
Three properties of a codemod this size are only trustworthy if actually checked, so I checked them:
- Hoisted
lennever freezes a live worklist. Every one of the ~500 converted loops was classified by whether its body can grow the array it iterates. None can. The one genuine BFS worklist —packages/host/engine/src/workspace/file-suggest-service.ts— is correctly exempted with aprefer-indexed-array-loopdisable and a comment explaining why both.lengthreads must stay live. Good catch by the author; that's the case that would have silently truncated file search. foxts/split-nthis an exact substitution.split0th(s, sep)≡s.split(sep)[0]andsplit1st(s, sep)≡s.split(sep)[1]—split1streturns the segment between the first and second separator, not the remainder, sosplit1st(name, '/')really does matchname.split('/', 2)[1]for scoped package names inhost/assets/src/closure.ts. (Worth stating explicitly: had it returned the remainder, the npm tarball URL builder and the MIME-subtype label would both have been wrong.)- The
desktop-shell.tsxcallback refs are not a regression. The docked and maximized panel regions can never both render the ref'd<div>:contentHiddengates it, and the two instances are driven by the sameexpandedPanelvalue inlayout/workspace.tsx:280-292. The newattachRightContentHost/attachBottomContentHostalso ignore thenullcall entirely and just re-parent auseSingleton-owned host node, so there is no state to clobber. This is strictly simpler than theuseState+useLayoutEffectversion it replaces.
Also confirmed: OPENCODE_TOOL_NAME_SANITIZE_RE carries the g flag, so the replace → replaceAll change in native/opencode/history.ts cannot throw; and providers/routing.ts exports only a type, so export * → export type * in presentation/ui/src/shell/index.ts is safe.
⚠️ The PR body under-describes what's in the commit
The title and description read as a pure lint sweep, but the diff also carries a major-version bump of the ESLint config trio (eslint-config-sukka, @eslint-sukka/react, eslint-formatter-sukka ^8.14.2 → ^9.0.1), a packageManager change from pnpm@11.10.0 to pnpm@11.24.0, a new verkit@0.3.2 dependency, and hand-edited version ranges in packages/vendor/coss-ui/package.json (@base-ui/react ^1.6.0 → ^1.7.0, foxact ^0.3.8 → ^0.3.10, input-otp ^1.4.2 → ^1.5.0).
Two things follow from that:
- The sukka major bump is almost certainly why the codemod exists — new rules landed. Saying so in the body turns 340 files of unexplained churn into a legible consequence of one line.
packages/vendor/coss-uiis the repo's designated vendored package:AGENTS.mdsays upstream formatting is "preserved as-synced — never hand-edit". Bumping its dependency ranges directly is a divergence from that sync contract. If these came from an upstream coss-ui resync, that's fine and worth stating; if they were bumped by hand to satisfy the lockfile, it will get clobbered on the next sync.
Neither blocks the PR — but a reviewer skimming "make eslint happy" will not expect to be reviewing a toolchain upgrade.
ℹ️ foxact@0.3.10 may trip pnpm's release-age gate
.github/dependabot.yml:6 documents that pnpm 11's default minimumReleaseAge (1 day) gates installs, and pnpm-workspace.yaml carries a 90-entry minimumReleaseAgeExclude allowlist for exactly this. Of the newly pinned versions:
foxts— allow-listed (bare entry, line 141) ✅eslint-config-sukka/@eslint-sukka/react/eslint-formatter-sukka— covered by theeslint-*-sukkaand@eslint-sukka/*globs ✅eslint@10.9.1(2026-08-24),input-otp@1.5.0(2026-08-18),verkit@0.3.2(2026-08-15),@base-ui/react@1.7.0(2026-08-04) — all comfortably past 1 day ✅foxact@0.3.10— published 2026-08-27T16:19Z, and not in the allowlist.
That is right on the 24-hour boundary as of this PR. A CI runner doing a cold install before 2026-08-27T16:19Z + 24h would be refused the version the lockfile pins. It self-heals with the clock, so this is informational rather than blocking — but if CI has already gone red on install, this is the reason.
ℹ️ Nitpicks
Object.definePropertyis applied unevenly. Eight of the new reduce-based object builders useObject.definePropertywith a comment explaining thatacc.__proto__ = …would mutate the prototype instead of creating an own property —remote-config.tseven notes that a JSON__proto__member "must survive into the canonical payload". Four sites use plainacc[key] = valueinstead. Three of those four take keys from in-repo string literals or a closed Zod enum and are unreachable; the fourth is flagged inline below. Not a vulnerability, but the rationale the author wrote eight times should either apply everywhere or the safe sites should say why they're special.- The codemod emits a redundant alias in ~10 files:
const index = i, item = items[i];whereiis already the loop variable (chat/activity-groups.ts,foundation/common/src/config/i-json.ts,node/release-artifact.ts,node/release-compliance.ts,schema/src/model/{linkcode-marketplace,permission,question}.ts,remote-config.ts,native/claude-code.ts,native/opencode/adapter.ts,engine/src/__tests__/engine-sessions.test.ts,workbench/src/history/use-provider-history.ts). Naming the loop variableindexdirectly drops a line at each site. presentation/ui/src/lib/base-ui.tsdropsimport type * as React from 'react'while the file still writesReact.SyntheticEvent, so the type now resolves through the@types/reactUMD global namespace rather than an explicit import. It typechecks, but it's a silent dependency on ambient types in a package that otherwise imports what it uses.shell/git/diff-viewer.tsxhoistsDiffViewerSkeletonfrom a component to a module-scopediffViewerSkeletonJsxelement. Correct (React permits reusing element objects), and it does remove a component identity — just noting it's a rendering-semantics change, not a rename.
Claude Opus | 𝕏
…th fallbacks, name loop indices directly
There was a problem hiding this comment.
ℹ️ All four of my earlier comments are genuinely addressed — I've replied to and resolved those threads. One informational note below, plus a correction to a call I got wrong last round.
Three new commits since my last review (96df5ef7..e52164a4, 16 files, +92/−89).
0290143b is a real bug fix, and a good catch. Resolving artifact paths against realpath(root) matters because a symlinked root — macOS /var → /private/var — makes every legitimate path read as an escape. Containment still holds for absolute and .. inputs, so the fix doesn't weaken the guard. CI never caught this because /tmp on Linux isn't a symlink and the tests use bare mkdtemp(join(tmpdir(), …)); codex-commands.test.ts:369 shows the repo already wraps with realpath elsewhere. I grepped every realpath( site — no sibling instance of the same bug.
b96a69d8 is faithful to the lockfile. I ran the repo's own drift guard (closure.test.ts → "the committed pi manifest matches the lockfile") and cross-read pnpm-lock.yaml: @google/genai@1.52.0 and @mistralai/mistralai@2.2.6 both now list ws: 8.21.1, matching the hoisted top-level, so the nested copies correctly disappear. See the one scope question below.
Tests run locally, all passing: foundation/{schema,common} + host/agent-adapter + presentation/ui (148 files / 1537 tests), closure.test.ts + common/src/node/__tests__ (7 / 59), engine-sessions.test.ts + client/workbench (43 / 260).
ℹ️ The pi closure revision change forces every existing user to re-download the closure
packages/host/assets/src/pi-closure.gen.ts moves revision: 'd6ff0228b84fa10c' → '6fdb7aeb2039774d' while pi itself stays at 0.80.6. Because installIdentity keys the store directory on <version>+<revision>:
// packages/host/assets/src/install.ts:50
return isClosureDescriptor(descriptor) ? `${version}+${descriptor.closure.revision}` : version;…the new identity is 0.80.6+6fdb7aeb2039774d, a directory nobody has. Every existing pi user re-fetches the whole ~230-package closure.
The manifest is correct — it's the honest output of the generator against the current lockfile. But the delta is entirely incidental transitive churn from the pnpm 11.24 lockfile regen, not anything about pi: ws@8.21.0 nested copies deduped away, minimatch@10.2.5 newly nested under pi (top-level moved 10.2.5→10.2.6), @opentelemetry/semantic-conventions 1.41.1→1.43.0, brace-expansion 5.0.8→5.0.9, has-flag@4.0.0 and supports-color@8.1.1 added.
Not a defect, and nothing to change in the code — just flagging that a lint-sweep PR carries a full re-download for every pi user, which is a scope call only you can make. Committing the regen is clearly right if the lockfile bump is staying in this PR; the question is whether the lockfile bump belongs here at all (which is the same scope-creep thread from my last review, still open).
Not re-raising
The foxact@0.3.10 release-age gate from my last review is moot — 0.3.10 is now well past the 24h minimumReleaseAge boundary. The three items I verified in round 1 (hoisted len never freezing a live worklist, foxts/split-nth being an exact substitution, desktop-shell.tsx callback refs) are unaffected by these commits and stay settled.
Claude Opus | 𝕏
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>

Summary
Housekeeping phase 1: sweep existing ESLint issues.
Verification
11
eslint-disablereports forvibe-proofare introduced, mostly potential race conditions. These require future refactors.re-ran codegen to update artifacts.
Checklist
pnpm check:ciandpnpm testboth pass (pluscargo fmt/clippy/testfor Rust changes)WIRE_PROTOCOL_VERSIONis bumped