chore: migrate lint/format stack to OXC#11
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (11)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request modernizes the project's code quality infrastructure by transitioning to the OXC linting and formatting tools, which streamlines the development workflow. It also includes significant internal refactorings to improve type safety and modularity in core functionalities, such as terminal process management and the handling of repository cloning events within the user interface. These changes aim to enhance code consistency, reduce potential errors, and provide a more robust foundation for future development. Highlights
Changelog
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request successfully migrates the project's linting and formatting stack to OXC, which is a significant undertaking. The changes include new configurations, updated dependencies, and numerous code improvements to align with the new tooling. I'm particularly impressed with the widespread adoption of stricter TypeScript types, which greatly enhances code quality and maintainability. My review includes a couple of suggestions: one for cleaning up a redundant entry in the .gitignore file, and a more important one regarding the disabling of some strict TypeScript compiler options that could affect long-term code quality.
Note: Security Review did not run due to the size of the PR.
| "noUnusedLocals": false, | ||
| "noUnusedParameters": false, | ||
| "noPropertyAccessFromIndexSignature": false |
There was a problem hiding this comment.
Disabling noUnusedLocals, noUnusedParameters, and noPropertyAccessFromIndexSignature can reduce code quality and hide potential bugs. While this might be a temporary measure for the migration, it's best to keep these strict checks enabled and fix the reported issues. If that's not feasible right now, consider adding a // TODO: comment to track re-enabling these flags in the future.
| "noUnusedLocals": false, | |
| "noUnusedParameters": false, | |
| "noPropertyAccessFromIndexSignature": false | |
| "noUnusedLocals": true, | |
| "noUnusedParameters": true, | |
| "noPropertyAccessFromIndexSignature": true |
| .roo/ | ||
| .amazonq/ | ||
| .github/copilot/ | ||
| .kittify/.dashboard |
There was a problem hiding this comment.
Pull request overview
Migrates the repo’s lint/format/typecheck plumbing to the OXC toolchain (oxlint/oxfmt/tsgolint), updates CI to run the new gates, and includes some refactors/typing improvements in the renderer and main process to align with the new stricter tooling.
Changes:
- Add OXC configs and update
package.jsonscripts to useoxlint/oxfmtandtsc --noEmit. - Introduce a new CI workflow (plus required-check name guard + manifest) to enforce the new lanes.
- Refactor/introduce git-slate helper modules and small typing/utilities (repo clone watcher, terminal manager, UI types).
Reviewed changes
Copilot reviewed 17 out of 21 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Relaxes several TS “stricter flags” (unused locals/params, index signature access). |
| src/renderers/ivde/types/ui.ts | Adds shared UI-related types used by the renderer. |
| src/renderers/ivde/slates/git/types.ts | Introduces typed shapes for git slate UI state and git change records. |
| src/renderers/ivde/slates/git/spinner.ts | Adds helper to inject spinner keyframes into the document. |
| src/renderers/ivde/slates/git/helpers.ts | Adds parsing helper for git status output lines. |
| src/renderers/ivde/slates/git/diff.ts | Adds a content reader/diff helper for working tree/index/commit comparisons. |
| src/renderers/ivde/services/settingsSyncService.ts | Adds RPC request typing + replaces (electrobun.rpc as any) with a typed request alias. |
| src/renderers/ivde/repoCloneWatcher.ts | Extracts repo clone polling logic into a dedicated helper. |
| src/renderers/ivde/index.tsx | Uses new repo clone watcher + improves typing for DOM/webview/analytics status. |
| src/main/utils/terminalManager.ts | Improves typing around spawn and PTY IO + adds guards for writable/readable streams. |
| package.json | Wires new scripts (lint, format, typecheck, test) and adds OXC devDependencies. |
| docs/branch-health-reconcile-2026-03-03.md | Adds a branch reconciliation plan document. |
| bun.lock | Locks new OXC toolchain dependencies. |
| .oxlintrc.json | Adds oxlint configuration (rules/plugins/overrides). |
| .oxfmtrc.json | Adds oxfmt configuration. |
| .gitignore | Ignores various AI tool artifacts/config directories. |
| .github/workflows/required-check-names-guard.yml | Adds workflow to verify required check names exist. |
| .github/workflows/ci.yml | Adds CI workflow for typecheck/lint/tests/coverage/secret scan + summary job. |
| .github/workflows/build-release.yml | Makes Zig vendor path detection tolerant of legacy vendor/zig path. |
| .github/required-checks.txt | Adds manifest of required check names used by the guard workflow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - `/Users/kooshapari/CodeProjects/Phenotype/repos/heliosApp-colab` | ||
| - `HEAD` vs `origin/main`: ahead 1, behind 8 | ||
| - `HEAD` vs `upstream/main`: ahead 1, behind 0 | ||
| - `/Users/kooshapari/CodeProjects/Phenotype/repos/heliosApp` | ||
| - `HEAD` (`heliosapp-upstream-recon`) vs `upstream/main`: ahead 9, behind 0 | ||
| - `HEAD` vs `origin/main`: ahead 13, behind 510 | ||
|
|
There was a problem hiding this comment.
This new doc includes absolute local filesystem paths (e.g. /Users/...) and personal branch context. That isn’t portable documentation and can leak developer-specific environment details into the repo. Consider rewriting it to use generic placeholders (e.g. /path/to/repo) and focusing on repo-agnostic steps, or keep it out of version control if it’s purely personal notes.
| const [analyticsStatus, setAnalyticsStatus] = createSignal<AnalyticsStatus>({ | ||
| enabled: false, | ||
| level: "Community", | ||
| isAnonymous: true, | ||
| hasToken: false, | ||
| userOptedIn: false, | ||
| userHasBeenPrompted: false, | ||
| }); |
There was a problem hiding this comment.
There’s an extra indentation level before const [analyticsStatus, ...] which makes this block misaligned with surrounding code and may violate formatter expectations. Running oxfmt (or adjusting the indentation) should align it with the other const declarations in GlobalSettings.
| const [analyticsStatus, setAnalyticsStatus] = createSignal<AnalyticsStatus>({ | |
| enabled: false, | |
| level: "Community", | |
| isAnonymous: true, | |
| hasToken: false, | |
| userOptedIn: false, | |
| userHasBeenPrompted: false, | |
| }); | |
| const [analyticsStatus, setAnalyticsStatus] = createSignal<AnalyticsStatus>({ | |
| enabled: false, | |
| level: "Community", | |
| isAnonymous: true, | |
| hasToken: false, | |
| userOptedIn: false, | |
| userHasBeenPrompted: false, | |
| }); |
| if (document.getElementById(SPINNER_STYLE_ID)) { | ||
| return; | ||
| } | ||
| const style = document.createElement("style"); | ||
| style.id = SPINNER_STYLE_ID; | ||
| style.innerHTML = ` | ||
| @keyframes spinner-rotate { | ||
| 0% { transform: rotate(0deg); } | ||
| 100% { transform: rotate(360deg); } | ||
| } | ||
| `; | ||
| document.head.appendChild(style); |
There was a problem hiding this comment.
This file uses tab indentation on several lines, but .oxfmtrc.json is configured with useTabs: false. Running bun run format (or converting tabs to spaces) will keep formatting consistent and avoid churn in future formatting runs.
| if (document.getElementById(SPINNER_STYLE_ID)) { | |
| return; | |
| } | |
| const style = document.createElement("style"); | |
| style.id = SPINNER_STYLE_ID; | |
| style.innerHTML = ` | |
| @keyframes spinner-rotate { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| if (document.getElementById(SPINNER_STYLE_ID)) { | |
| return; | |
| } | |
| const style = document.createElement("style"); | |
| style.id = SPINNER_STYLE_ID; | |
| style.innerHTML = ` | |
| @keyframes spinner-rotate { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| `; | |
| document.head.appendChild(style); |
| options: string[]; | ||
| repoRoot: string; | ||
| }) => Promise<string | undefined>; | ||
| export type FileExistsRequest = (args: { | ||
| path: string; | ||
| }) => Promise<boolean | undefined>; | ||
| export type ReadFileRequest = (args: { | ||
| path: string; | ||
| }) => Promise<{ textContent?: string } | undefined>; | ||
|
|
||
| type GetFileDiffArgs = { | ||
| filepath: string; | ||
| commitHash?: string; | ||
| changeType?: string; | ||
| isStaged?: boolean; | ||
| }; | ||
|
|
||
| type FileContentRequests = { | ||
| gitShow?: GitShowRequest; | ||
| exists?: FileExistsRequest; | ||
| readFile?: ReadFileRequest; | ||
| }; | ||
|
|
||
| export const createGitContentReader = ( | ||
| repoRootPath: string, | ||
| requests: FileContentRequests, | ||
| ) => { | ||
| const getFileContents = async (filepath: string, commitRef = "HEAD") => { | ||
| if (commitRef === "WORKING") { | ||
| const absolutePath = join(repoRootPath, filepath); | ||
| const exists = await requests.exists?.({ path: absolutePath }); | ||
| if (!exists) { | ||
| return ""; | ||
| } | ||
| const result = await requests.readFile?.({ path: absolutePath }); | ||
| return result?.textContent || ""; | ||
| } | ||
| if (commitRef === "INDEX") { | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| } | ||
| if (commitRef !== "HEAD") { | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`${commitRef}:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| } | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`HEAD:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| }; |
There was a problem hiding this comment.
This new file uses tab indentation (e.g. in the exported type definitions and function bodies) while .oxfmtrc.json is configured with useTabs: false. Running bun run format will normalize this and prevent formatting-only diffs later.
| options: string[]; | |
| repoRoot: string; | |
| }) => Promise<string | undefined>; | |
| export type FileExistsRequest = (args: { | |
| path: string; | |
| }) => Promise<boolean | undefined>; | |
| export type ReadFileRequest = (args: { | |
| path: string; | |
| }) => Promise<{ textContent?: string } | undefined>; | |
| type GetFileDiffArgs = { | |
| filepath: string; | |
| commitHash?: string; | |
| changeType?: string; | |
| isStaged?: boolean; | |
| }; | |
| type FileContentRequests = { | |
| gitShow?: GitShowRequest; | |
| exists?: FileExistsRequest; | |
| readFile?: ReadFileRequest; | |
| }; | |
| export const createGitContentReader = ( | |
| repoRootPath: string, | |
| requests: FileContentRequests, | |
| ) => { | |
| const getFileContents = async (filepath: string, commitRef = "HEAD") => { | |
| if (commitRef === "WORKING") { | |
| const absolutePath = join(repoRootPath, filepath); | |
| const exists = await requests.exists?.({ path: absolutePath }); | |
| if (!exists) { | |
| return ""; | |
| } | |
| const result = await requests.readFile?.({ path: absolutePath }); | |
| return result?.textContent || ""; | |
| } | |
| if (commitRef === "INDEX") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| if (commitRef !== "HEAD") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`HEAD:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| }; | |
| options: string[]; | |
| repoRoot: string; | |
| }) => Promise<string | undefined>; | |
| export type FileExistsRequest = (args: { | |
| path: string; | |
| }) => Promise<boolean | undefined>; | |
| export type ReadFileRequest = (args: { | |
| path: string; | |
| }) => Promise<{ textContent?: string } | undefined>; | |
| type GetFileDiffArgs = { | |
| filepath: string; | |
| commitHash?: string; | |
| changeType?: string; | |
| isStaged?: boolean; | |
| }; | |
| type FileContentRequests = { | |
| gitShow?: GitShowRequest; | |
| exists?: FileExistsRequest; | |
| readFile?: ReadFileRequest; | |
| }; | |
| export const createGitContentReader = ( | |
| repoRootPath: string, | |
| requests: FileContentRequests, | |
| ) => { | |
| const getFileContents = async (filepath: string, commitRef = "HEAD") => { | |
| if (commitRef === "WORKING") { | |
| const absolutePath = join(repoRootPath, filepath); | |
| const exists = await requests.exists?.({ path: absolutePath }); | |
| if (!exists) { | |
| return ""; | |
| } | |
| const result = await requests.readFile?.({ path: absolutePath }); | |
| return result?.textContent || ""; | |
| } | |
| if (commitRef === "INDEX") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| if (commitRef !== "HEAD") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`HEAD:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| }; |
| @@ -0,0 +1,69 @@ | |||
| export type GitChangeCode = "A" | "M" | "D" | "?" | ""; | |||
There was a problem hiding this comment.
GitChangeCode is currently limited to "A" | "M" | "D" | "?" | "", but git status / --name-status can emit additional codes (e.g. R rename, C copy, U unmerged, etc.). Since the rest of the git UI appears to pass through file.index.trim()/file.status values, this type is likely to become inaccurate quickly. Consider expanding the union (or explicitly mapping unknown codes to a dedicated "?"/"unknown" value) so the types reflect real inputs.
| export type GitChangeCode = "A" | "M" | "D" | "?" | ""; | |
| export type GitChangeCode = "A" | "M" | "D" | "R" | "C" | "U" | "T" | "?" | "!" | ""; |
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| } | ||
| if (commitRef !== "HEAD") { | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`${commitRef}:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| } | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`HEAD:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); |
There was a problem hiding this comment.
requests.gitShow?.(...) can evaluate to undefined, but the code then unconditionally calls .catch(...) on the result. If gitShow is not provided this will throw at runtime (TypeError: cannot read properties of undefined). Consider storing the promise in a variable and using optional chaining on the promise (const p = requests.gitShow?.(...); const content = await p?.catch(...)) or branching when the request is missing.
| const content = await requests | |
| .gitShow?.({ | |
| options: [`:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| if (commitRef !== "HEAD") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`HEAD:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| const gitShowPromise = requests.gitShow?.({ | |
| options: [`:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }); | |
| const content = await gitShowPromise?.catch(() => ""); | |
| return content || ""; | |
| } | |
| if (commitRef !== "HEAD") { | |
| const gitShowPromise = requests.gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }); | |
| const content = await gitShowPromise?.catch(() => ""); | |
| return content || ""; | |
| } | |
| const gitShowPromise = requests.gitShow?.({ | |
| options: [`HEAD:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }); | |
| const content = await gitShowPromise?.catch(() => ""); |
| type RepoCloneWatcherArgs = { | ||
| previewNode: FileNodeType; | ||
| onExpandRepo: (repoPath: string) => void; | ||
| onOpenGitSlate: (gitPath: string) => void; | ||
| }; | ||
|
|
||
| const POLL_INTERVAL_MS = 500; | ||
| const MAX_REPO_POLL_ATTEMPTS = 20; | ||
| const MAX_GIT_POLL_ATTEMPTS = 20; | ||
|
|
||
| export const watchClonedRepoAndOpenGitSlate = ({ | ||
| previewNode, | ||
| onExpandRepo, | ||
| onOpenGitSlate, | ||
| }: RepoCloneWatcherArgs): void => { |
There was a problem hiding this comment.
This file uses tab indentation in the new code, but .oxfmtrc.json sets useTabs: false. Consider running bun run format so the new utility matches the repo’s formatting configuration.
| for (const plugin of settings.plugins) { | ||
| try { | ||
| // Check if plugin is already installed | ||
| const installedPlugins = await (electrobun.rpc as any)?.request.pluginGetInstalled?.(); | ||
| const isInstalled = installedPlugins?.some((p: any) => p.name === plugin.name); | ||
| const installedPlugins = await request?.pluginGetInstalled?.(); | ||
| const isInstalled = installedPlugins?.some((p) => p.name === plugin.name); | ||
|
|
There was a problem hiding this comment.
applySyncedSettings calls pluginGetInstalled inside the loop for every plugin being synced. That can create an avoidable N+1 RPC pattern. Consider fetching the installed plugins list once before the loop and reusing it (or updating it locally when you install a missing plugin).
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
Co-authored-by: Codex <noreply@openai.com>
- fix Zig vendor path drift in build-release workflow - add PR CI jobs for typecheck, lint, unit tests, and ci-summary - add required-checks manifest and guard workflow - add branch health reconciliation runbook for heliosApp and heliosApp-colab Co-authored-by: Codex <noreply@openai.com>
Use 'bun test --pass-with-no-tests' so baseline PR CI stays actionable while test suites are introduced. Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
…minal services Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Slice 3 reduces concrete TypeScript errors in src/renderers/ivde/services/settingsSyncService.ts (9->0) and src/main/utils/terminalManager.ts (33->10) with targeted lib/type references and explicit exit callback typing. Co-authored-by: Codex <noreply@openai.com>
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/renderers/ivde/services/settingsSyncService.ts (1)
215-240:⚠️ Potential issue | 🟡 MinorRedundant RPC call inside loop degrades performance.
pluginGetInstalledis called inside the loop at Line 219 for every plugin being synced. This results in O(n) RPC calls where a single call before the loop would suffice.🔧 Proposed fix to hoist RPC call outside loop
// Install/update plugins if (settings.plugins && settings.plugins.length > 0) { + const installedPlugins = await request?.pluginGetInstalled?.() ?? []; for (const plugin of settings.plugins) { try { // Check if plugin is already installed - const installedPlugins = await request?.pluginGetInstalled?.(); const isInstalled = installedPlugins?.some((p) => p.name === plugin.name); if (!isInstalled) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderers/ivde/services/settingsSyncService.ts` around lines 215 - 240, The code calls request.pluginGetInstalled repeatedly inside the for loop causing redundant RPCs; hoist that call outside the loop by invoking request.pluginGetInstalled once (guarding request and the method) and store the result in a local installedPlugins variable, then inside the loop use installedPlugins.some(...) to compute isInstalled; keep the existing calls to request.pluginInstall, request.pluginSetSettingValue, and request.pluginSetEnabled and the existing try/catch per plugin but remove pluginGetInstalled from inside the loop.src/main/utils/terminalManager.ts (1)
279-292:⚠️ Potential issue | 🟠 MajorReader cleanup path is currently broken by registration order.
At Line 288, reader refs are saved via
this.terminals.get(terminalId), butcreateTerminalcallsreadPtyOutputbefore inserting the session (Line 226 before Line 246). In that flow,stdoutReader/stderrReaderstay unset andcleanupReaderscannot cancel them reliably.Suggested fix
- // Handle PTY output - this.readPtyOutput(proc, terminalId); - // Handle process exit proc.exited.then((exitCode: number) => { @@ - this.terminals.set(terminalId, terminal); + this.terminals.set(terminalId, terminal); + + // Handle PTY output after session registration so reader refs are persisted + this.readPtyOutput(proc, terminalId);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/utils/terminalManager.ts` around lines 279 - 292, readPtyOutput is saving stdoutReader/stderrReader into this.terminals.get(terminalId) but createTerminal calls readPtyOutput before inserting the session, so the readers are never stored and cleanupReaders cannot cancel them; fix by ensuring the terminal session exists before readPtyOutput tries to store readers—either insert the session into this.terminals prior to calling readPtyOutput in createTerminal, or change readPtyOutput to lookup-or-create the terminal entry (e.g., get or set a TerminalSession object) and then assign terminal.stdoutReader/terminal.stderrReader so cleanupReaders can always find and cancel the readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/build-release.yml:
- Around line 118-132: The success log prints the legacy path because after
creating the symlink the script sets ZIG_DIR="vendor/zig"; update the branch
that handles the legacy path so ZIG_DIR is set to the canonical vendors/zig (or
otherwise normalize ZIG_DIR to vendors/zig before the echo), and ensure the
final echo uses the normalized ZIG_DIR variable so the message reports the
canonical path; reference the ZIG_DIR variable and the legacy-path branch where
the symlink is created/ln -sfn.
In @.github/workflows/ci.yml:
- Around line 22-25: The CI workflow's Setup Bun step currently uses the
variable value bun-version: latest which causes non-reproducible builds; change
the `Setup Bun` step (the action using oven-sh/setup-bun@v2 and the
`bun-version` input) to pin a specific Bun version or range (for example `1.1.x`
or a concrete patch like `1.1.8`) instead of `latest` so CI runs remain stable
and reproducible.
- Around line 33-36: The lint job currently lists needs: [typecheck] making it
run serially; remove that dependency from the lint job (delete needs:
[typecheck]) so lint and typecheck can run in parallel, and update the
unit-tests job to depend on both checks by setting its needs to include both
typecheck and lint (e.g., needs: [typecheck, lint]) so unit-tests and then
coverage still run after both finish.
In @.github/workflows/required-check-names-guard.yml:
- Around line 48-51: The script exits on failure but never emits a success
message or explicitly confirms completion; after the existing if ... fi block
that checks the variable "missing" add an echo to confirm success (e.g., echo
"Required check name guard passed: all required names present.") and ensure the
workflow file is properly closed so the job/step YAML structure ends cleanly;
locate the if block that references the variable "missing" and append the
success echo and any needed closing YAML statements to terminate the workflow.
In @.oxlintrc.json:
- Around line 138-146: The TS lint config currently disables important async
safety rules; re-enable at least "typescript/no-floating-promises" and
"typescript/no-misused-promises" (and consider "typescript/await-thenable") by
changing them from "off" to "warn" or "error", and if existing legacy code
prevents a full flip, create targeted "overrides" for specific legacy file globs
to keep them off while turning the rules back on globally; also add a short
migration TODO (or issue) tracking re-enablement progress so teams can fix
violations incrementally.
In `@docs/branch-health-reconcile-2026-03-03.md`:
- Around line 24-53: Fenced code blocks using the triple-backtick markers (e.g.,
```bash) in the numbered steps are not surrounded by blank lines; update each
fenced block so there is a blank line before the opening ``` and a blank line
after the closing ``` throughout the document (this includes the examples under
steps 1–6 and the fallback block), ensuring list items and surrounding text
maintain a single blank line separation to satisfy MD031.
In `@package.json`:
- Around line 67-69: The package.json lists non-existent versions for oxlint and
oxlint-tsgolint which will break installs; update the dependency versions for
"oxlint" and "oxlint-tsgolint" to valid npm releases (e.g., set "oxlint" to
1.43.0 and "oxlint-tsgolint" to 0.11.4) while keeping "oxfmt" at 0.36.0, then
run npm install (or yarn) and verify package-lock.json / yarn.lock is updated;
ensure the changes are made to the dependencies block where "oxfmt", "oxlint",
and "oxlint-tsgolint" are declared.
In `@src/main/utils/terminalManager.ts`:
- Around line 20-22: The TerminalMessage type declares terminalExit.signal as a
number but the code always emits 0, which conflates “no signal info” with a real
signal; change the TerminalMessage union so terminalExit.signal is number | null
(or undefined) to represent unknown signals, then update the emitter that
constructs terminalExit (the code that currently hardcodes 0) to set signal to
the actual child/OS signal if present (e.g., from the child process's signal
code/termination info) or to null when unknown; also update any consumers of
TerminalMessage/terminalExit to handle the nullable signal value accordingly.
In `@src/renderers/ivde/repoCloneWatcher.ts`:
- Around line 28-41: The console.log debugging inside openGitSlateWhenReady
(which prints gitPollAttempts, gitNode presence, "Opening git slate for:" with
gitFolderPath, and the timeout message) should be removed or gated behind a
debug flag/logger; update the function to either remove these console.log calls
or replace them with a conditional debug/logger check (e.g., a DEBUG/VERBOSE env
flag or a renderer-level logger.debug) so logs only emit when enabled, keeping
behavior of invoking onOpenGitSlate(gitFolderPath),
setTimeout(openGitSlateWhenReady, POLL_INTERVAL_MS) and the
MAX_GIT_POLL_ATTEMPTS logic unchanged.
- Around line 15-66: The polling logic in watchClonedRepoAndOpenGitSlate
(functions expandWhenReady, pollForGitDirectory, openGitSlateWhenReady) has no
cleanup for setTimeout — add cancellation: store each setTimeout ID (for both
repo and git polls) in scoped variables, set a "cancelled" flag when cleanup
runs, clearTimeout for any pending IDs, and short-circuit handlers
(expandWhenReady/openGitSlateWhenReady) if cancelled to avoid calling
onExpandRepo/onOpenGitSlate after unmount; finally change
watchClonedRepoAndOpenGitSlate to return a cleanup function that performs the
clearing and sets the flag so callers can cancel polling.
In `@src/renderers/ivde/slates/git/diff.ts`:
- Around line 50-66: The code duplicates gitShow calls for the HEAD and non-HEAD
cases; collapse them by building a single refSpec and calling requests.gitShow
once. Concretely, compute const refSpec = `${commitRef}:${filepath}` (or use
commitRef ?? "HEAD" if commitRef can be undefined) and call requests.gitShow?.({
options: [refSpec], repoRoot: repoRootPath }).catch(() => "") and return the
result || "". Update the block that currently branches on commitRef !== "HEAD"
to this single unified implementation referencing commitRef, filepath,
repoRootPath, and requests.gitShow.
In `@src/renderers/ivde/slates/git/types.ts`:
- Line 1: GitChangeCode's union is incomplete and is being bypassed by a type
assertion in the helper (the cast to "as GitChangeCode" in helpers.ts), so
either expand the GitChangeCode type to include the missing git status codes
("R", "C", "U", "T") or remove the assertion and add explicit validation/mapping
in the helper that returns the existing fallback ("" or default behavior) for
unknown codes; update the helper (the function that currently does the "as
GitChangeCode" cast) to perform a safe runtime check (e.g., switch or lookup)
against the allowed GitChangeCode values and only return a typed GitChangeCode
for known codes while handling unknowns explicitly.
In `@tsconfig.json`:
- Around line 27-29: The TypeScript strictness flags noUnusedLocals,
noUnusedParameters, and noPropertyAccessFromIndexSignature were relaxed; add a
concise technical-debt note and tracking entry: insert a TODO comment near the
three flags referencing a short ticket/issue ID (or create one) to re-enable
noUnusedLocals, noUnusedParameters, and noPropertyAccessFromIndexSignature after
lint/format migration stabilizes, and create the corresponding task in your
issue tracker with acceptance criteria for re-enabling and fixing resulting
errors.
---
Outside diff comments:
In `@src/main/utils/terminalManager.ts`:
- Around line 279-292: readPtyOutput is saving stdoutReader/stderrReader into
this.terminals.get(terminalId) but createTerminal calls readPtyOutput before
inserting the session, so the readers are never stored and cleanupReaders cannot
cancel them; fix by ensuring the terminal session exists before readPtyOutput
tries to store readers—either insert the session into this.terminals prior to
calling readPtyOutput in createTerminal, or change readPtyOutput to
lookup-or-create the terminal entry (e.g., get or set a TerminalSession object)
and then assign terminal.stdoutReader/terminal.stderrReader so cleanupReaders
can always find and cancel the readers.
In `@src/renderers/ivde/services/settingsSyncService.ts`:
- Around line 215-240: The code calls request.pluginGetInstalled repeatedly
inside the for loop causing redundant RPCs; hoist that call outside the loop by
invoking request.pluginGetInstalled once (guarding request and the method) and
store the result in a local installedPlugins variable, then inside the loop use
installedPlugins.some(...) to compute isInstalled; keep the existing calls to
request.pluginInstall, request.pluginSetSettingValue, and
request.pluginSetEnabled and the existing try/catch per plugin but remove
pluginGetInstalled from inside the loop.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: cc1346d1-7328-4dd7-a33b-553d55ad2163
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (20)
.github/required-checks.txt.github/workflows/build-release.yml.github/workflows/ci.yml.github/workflows/required-check-names-guard.yml.gitignore.oxfmtrc.json.oxlintrc.jsondocs/branch-health-reconcile-2026-03-03.mdpackage.jsonsrc/main/utils/terminalManager.tssrc/renderers/ivde/index.tsxsrc/renderers/ivde/repoCloneWatcher.tssrc/renderers/ivde/services/settingsSyncService.tssrc/renderers/ivde/slates/GitSlate.tsxsrc/renderers/ivde/slates/git/diff.tssrc/renderers/ivde/slates/git/helpers.tssrc/renderers/ivde/slates/git/spinner.tssrc/renderers/ivde/slates/git/types.tssrc/renderers/ivde/types/ui.tstsconfig.json
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.41.0)
src/renderers/ivde/slates/git/spinner.ts
[warning] 8-13: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: style.innerHTML = @Keyframesspinner-rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/
- https://cwe.mitre.org/data/definitions/79.html
(unsafe-html-content-assignment)
[warning] 8-13: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: style.innerHTML = @Keyframesspinner-rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html
(dom-content-modification)
🪛 markdownlint-cli2 (0.21.0)
docs/branch-health-reconcile-2026-03-03.md
[warning] 25-25: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 28-28: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 30-30: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 32-32: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 34-34: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 36-36: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 38-38: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 41-41: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 43-43: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 45-45: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 49-49: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 58-58: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 62-62: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 64-64: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 67-67: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 69-69: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 71-71: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 73-73: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 75-75: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 78-78: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 81-81: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
🔇 Additional comments (24)
.gitignore (2)
12-18: Good cleanup of local AI-tool artifacts.These ignore entries are consistent with keeping ephemeral local tooling output out of version control.
Also applies to: 22-28, 31-32
19-20: No action needed. The.github/copilot/,.github/prompts/, and.github/copilot-instructions.mdentries are clearly AI tool artifacts, not repository documentation or intentionally versioned content. No tracked files currently exist in these paths, and the ignore rules are appropriate for excluding tool-specific configurations..oxfmtrc.json (1)
1-15: LGTM!The oxfmt configuration is well-structured with sensible defaults (100 char width, 2-space indentation) and comprehensive ignore patterns that align with the project's build artifacts and vendor directories.
src/renderers/ivde/types/ui.ts (1)
1-16: LGTM!These types provide incremental type safety improvements for webview interactions and analytics state management. The types match their usage in
index.tsxand related files.Consider expanding
ReloadableWebviewElementin the future to include other webview methods (goBack,goForward, etc.) as seen inWebSlate.tsxLine 233-241, allowing replacement of theanytype annotation there..oxlintrc.json (1)
1-171: Configuration is well-structured for the OXC migration.The ignore patterns, plugin selection, and category severities are sensible. The test file overrides appropriately relax rules for testing contexts. The configuration provides a solid foundation that can be incrementally tightened.
package.json (1)
67-69: No changes needed. Theoxlint-tsgolintdependency is an optional peer dependency of oxlint (as specified in oxlint'speerDependencies), not an unused dependency. Optional peer dependencies provide enhancements when installed but do not require explicit configuration in.oxlintrc.json. It is correctly included in the project.> Likely an incorrect or invalid review comment.src/renderers/ivde/services/settingsSyncService.ts (3)
12-38: RPC type definitions diverge from canonical schema.The local RPC types don't match the actual RPC definitions:
PluginInstalledRpcRecordomitsstate,installedAt,updatedAt,isLocal,localPathfields present in the actual RPC schema (seesrc/renderers/ivde/rpc.ts:756-770).
pluginGetSettingsValuesresponse is typed asRecord<string, unknown>but the actual RPC returnsRecord<string, string | number | boolean>- the local type is more permissive.
pluginInstallreturnsPromise<unknown>but the actual response contains{ ok: boolean; plugin?: {...}; error?: string }- errors aren't being checked.Consider aligning these types with the canonical RPC schema or importing directly from the RPC definitions to avoid drift.
[suggest_recommended_refactor, request_verification]
#!/bin/bash # Check if there are existing shared RPC types that could be imported rg -l "pluginGetInstalled|pluginInstall|pluginGetSettingsValues" --type=ts | head -10
104-139: LGTM!The token gathering logic with optional chaining and try/catch error handling is appropriate for graceful degradation when RPC is unavailable.
141-168: LGTM!Plugin gathering with graceful error handling is well-structured. The empty catch block for settings fetch errors is acceptable given the explicit comment documenting the intent.
.github/required-checks.txt (1)
1-8: LGTM!The required checks manifest is well-structured with clear pipe-delimited format. The self-referential entry for
verify-required-check-namesensures the guard workflow validates itself.src/renderers/ivde/slates/git/spinner.ts (1)
1-16: LGTM!The static analysis warning about
innerHTMLis a false positive here. The CSS content is a hardcoded string literal with no user input, so there's no XSS risk. This is a standard pattern for dynamically injecting CSS keyframes..github/workflows/ci.yml (1)
104-129: LGTM!The
ci-summaryjob properly aggregates results and fails if any required job didn't succeed. Theif: always()ensures it runs even on failures to provide a comprehensive status.src/renderers/ivde/index.tsx (4)
1-2: LGTM!The DOM reference directive ensures proper DOM type availability for this renderer module.
3837-3841: LGTM!Clean extraction of clone-watching logic to
watchClonedRepoAndOpenGitSlate. The callback pattern provides good separation of concerns.
1013-1020: LGTM!The
AnalyticsStatustype properly replaces genericanyusage, providing type safety for analytics state and component props.Also applies to: 1181-1181
568-570: LGTM!The minimal interface type for
githubAuthWebviewappropriately exposes only theaddEventListenermethod that's actually used, following interface segregation principles.src/renderers/ivde/slates/git/diff.ts (1)
68-131: LGTM!The
getFileDiffmethod correctly implements Git diff semantics:
- Staged changes compare HEAD → INDEX
- Unstaged changes compare INDEX → WORKING
- Added files have empty original text
- Deleted files have empty modified text
- Commit diffs correctly use
commitHash^for the parentThe parallel fetching via
Promise.allis a good optimization.src/renderers/ivde/slates/git/helpers.ts (1)
5-12: TheparseStatusLinefunction is imported but never actually used in the codebase.While the review raises a theoretically valid concern about renamed file handling (
R old_path -> new_path), the function itself is dead code. The actual file status parsing inGitSlate.tsxuses manual parsing withsplit("\t")instead of callingparseStatusLine. No refactoring is needed for an unused function, and the suggested diff improvement is not applicable to the actual code flow.> Likely an incorrect or invalid review comment.src/renderers/ivde/slates/git/types.ts (4)
3-13: LGTM!Clean type definitions with proper extension pattern for
FileChangeWithCommitType.
15-37: LGTM!Type definitions are well-structured. Using
numberforCommitType.date(timestamp) andstring[]for refs is appropriate.
39-57: LGTM!Well-structured types that map cleanly to git concepts. Separating
allandremotebranches inBranchInfois a sensible design.
59-69: LGTM!Comprehensive UI state type. The literal union for
activeSectionprovides good type safety for section switching logic.src/main/utils/terminalManager.ts (2)
20-25: Nice move to discriminated terminal messages and typed handlers.This materially reduces
any-driven mistakes in message routing and makes handler contracts explicit.Also applies to: 83-97
49-61: Good hardening on PTY IO guards before writes.
hasWrite/hasReaderchecks make the stream handling path safer and prevent invalidstdinwrites.Also applies to: 268-274
| ZIG_DIR="" | ||
| if [ -f "vendors/zig/zig" ]; then | ||
| ZIG_DIR="vendors/zig" | ||
| elif [ -f "vendor/zig/zig" ]; then | ||
| # Accept legacy singular path and normalize to canonical vendors/zig. | ||
| mkdir -p vendors | ||
| ln -sfn ../vendor/zig vendors/zig | ||
| ZIG_DIR="vendor/zig" | ||
| fi | ||
|
|
||
| if [ -z "${ZIG_DIR}" ]; then | ||
| echo "❌ Zig not found, running setup" | ||
| bun setup | ||
| else | ||
| echo "✅ Zig found at vendors/zig/zig" | ||
| echo "✅ Zig found at ${ZIG_DIR}/zig" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Log message reports legacy path after symlink normalization.
After creating the symlink at Line 124, ZIG_DIR is set to "vendor/zig" (Line 125), so the success message at Line 132 reports the legacy path. The symlink ensures vendors/zig works for downstream scripts, but the log could be clearer by reporting the canonical path:
💡 Suggested improvement
elif [ -f "vendor/zig/zig" ]; then
# Accept legacy singular path and normalize to canonical vendors/zig.
mkdir -p vendors
ln -sfn ../vendor/zig vendors/zig
- ZIG_DIR="vendor/zig"
+ ZIG_DIR="vendors/zig (symlinked from vendor/zig)"
fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/build-release.yml around lines 118 - 132, The success log
prints the legacy path because after creating the symlink the script sets
ZIG_DIR="vendor/zig"; update the branch that handles the legacy path so ZIG_DIR
is set to the canonical vendors/zig (or otherwise normalize ZIG_DIR to
vendors/zig before the echo), and ensure the final echo uses the normalized
ZIG_DIR variable so the message reports the canonical path; reference the
ZIG_DIR variable and the legacy-path branch where the symlink is created/ln
-sfn.
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider pinning Bun version for reproducible builds.
Using bun-version: latest may cause unexpected CI failures when Bun releases breaking changes. Pinning to a specific version (e.g., bun-version: 1.1.x) provides more predictable builds.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/ci.yml around lines 22 - 25, The CI workflow's Setup Bun
step currently uses the variable value bun-version: latest which causes
non-reproducible builds; change the `Setup Bun` step (the action using
oven-sh/setup-bun@v2 and the `bun-version` input) to pin a specific Bun version
or range (for example `1.1.x` or a concrete patch like `1.1.8`) instead of
`latest` so CI runs remain stable and reproducible.
| lint: | ||
| name: lint | ||
| runs-on: ubuntu-latest | ||
| needs: [typecheck] |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Sequential job chain could be optimized.
The lint job depends on typecheck, but these are independent checks. Running them in parallel would reduce CI time on green builds while still catching issues early.
Current: typecheck → lint → unit-tests → coverage (~serial)
Suggested: typecheck ⟍ → unit-tests → coverage (~parallel start)
lint ⟋
🔧 Example parallel configuration
lint:
name: lint
runs-on: ubuntu-latest
- needs: [typecheck]
steps:Then update unit-tests:
unit-tests:
name: unit-tests
runs-on: ubuntu-latest
- needs: [lint]
+ needs: [typecheck, lint]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/ci.yml around lines 33 - 36, The lint job currently lists
needs: [typecheck] making it run serially; remove that dependency from the lint
job (delete needs: [typecheck]) so lint and typecheck can run in parallel, and
update the unit-tests job to depend on both checks by setting its needs to
include both typecheck and lint (e.g., needs: [typecheck, lint]) so unit-tests
and then coverage still run after both finish.
| if [ "${missing}" -ne 0 ]; then | ||
| echo "Required check name guard failed." | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Workflow file appears truncated - missing closing statement.
The workflow ends abruptly at line 51 without proper closure. While the shell script logic is complete, there should be an echo statement for success confirmation to aid debugging.
📝 Proposed fix to add success message
if [ "${missing}" -ne 0 ]; then
echo "Required check name guard failed."
exit 1
fi
+
+ echo "All required check names verified successfully."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/required-check-names-guard.yml around lines 48 - 51, The
script exits on failure but never emits a success message or explicitly confirms
completion; after the existing if ... fi block that checks the variable
"missing" add an echo to confirm success (e.g., echo "Required check name guard
passed: all required names present.") and ensure the workflow file is properly
closed so the job/step YAML structure ends cleanly; locate the if block that
references the variable "missing" and append the success echo and any needed
closing YAML statements to terminate the workflow.
| "typescript/no-floating-promises": "off", | ||
| "typescript/no-confusing-void-expression": "off", | ||
| "typescript/promise-function-async": "off", | ||
| "typescript/no-unnecessary-type-assertion": "off", | ||
| "typescript/no-misused-promises": "off", | ||
| "typescript/await-thenable": "off", | ||
| "typescript/prefer-nullish-coalescing": "off", | ||
| "typescript/prefer-optional-chain": "warn", | ||
| "typescript/ban-ts-comment": "off" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Disabled TypeScript promise/async rules represent safety gaps.
Several TypeScript rules that catch common async bugs are disabled:
no-floating-promises: Catches unhandled promise rejectionsno-misused-promises: Catches promises in non-async contextsawait-thenable: Catches awaiting non-promise values
These are likely disabled to manage existing debt during migration. Consider tracking re-enablement of at least no-floating-promises and no-misused-promises as they catch runtime errors.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.oxlintrc.json around lines 138 - 146, The TS lint config currently disables
important async safety rules; re-enable at least
"typescript/no-floating-promises" and "typescript/no-misused-promises" (and
consider "typescript/await-thenable") by changing them from "off" to "warn" or
"error", and if existing legacy code prevents a full flip, create targeted
"overrides" for specific legacy file globs to keep them off while turning the
rules back on globally; also add a short migration TODO (or issue) tracking
re-enablement progress so teams can fix violations incrementally.
| export const watchClonedRepoAndOpenGitSlate = ({ | ||
| previewNode, | ||
| onExpandRepo, | ||
| onOpenGitSlate, | ||
| }: RepoCloneWatcherArgs): void => { | ||
| let repoPollAttempts = 0; | ||
|
|
||
| const pollForGitDirectory = (gitFolderPath: string) => { | ||
| let gitPollAttempts = 0; | ||
|
|
||
| const openGitSlateWhenReady = () => { | ||
| gitPollAttempts += 1; | ||
| const gitNode = getNode(gitFolderPath); | ||
| console.log( | ||
| `Git folder poll attempt ${gitPollAttempts}, found:`, | ||
| gitNode ? "yes" : "no", | ||
| ); | ||
| if (gitNode) { | ||
| console.log("Opening git slate for:", gitFolderPath); | ||
| onOpenGitSlate(gitFolderPath); | ||
| return; | ||
| } | ||
| if (gitPollAttempts < MAX_GIT_POLL_ATTEMPTS) { | ||
| setTimeout(openGitSlateWhenReady, POLL_INTERVAL_MS); | ||
| return; | ||
| } | ||
| console.log("Timeout waiting for .git folder"); | ||
| }; | ||
|
|
||
| openGitSlateWhenReady(); | ||
| }; | ||
|
|
||
| const expandWhenReady = () => { | ||
| repoPollAttempts += 1; | ||
| const node = getNode(previewNode.path); | ||
| if (node) { | ||
| console.log("Found repo node, expanding:", previewNode.path); | ||
| onExpandRepo(previewNode.path); | ||
| const gitFolderPath = join(previewNode.path, ".git"); | ||
| console.log("Looking for git folder at:", gitFolderPath); | ||
| pollForGitDirectory(gitFolderPath); | ||
| return; | ||
| } | ||
| if (repoPollAttempts < MAX_REPO_POLL_ATTEMPTS) { | ||
| setTimeout(expandWhenReady, POLL_INTERVAL_MS); | ||
| return; | ||
| } | ||
| console.log("Timeout waiting for cloned repo to appear in file tree"); | ||
| }; | ||
|
|
||
| expandWhenReady(); | ||
| }; |
There was a problem hiding this comment.
Missing cleanup mechanism for polling timers.
The polling functions use setTimeout recursively but provide no way to cancel pending timers. If the component unmounts or the user navigates away before polling completes, callbacks will continue executing against potentially stale state.
Consider returning a cleanup function:
♻️ Proposed refactor
-export const watchClonedRepoAndOpenGitSlate = ({
+export const watchClonedRepoAndOpenGitSlate = ({
previewNode,
onExpandRepo,
onOpenGitSlate,
-}: RepoCloneWatcherArgs): void => {
+}: RepoCloneWatcherArgs): (() => void) => {
+ let cancelled = false;
let repoPollAttempts = 0;
const pollForGitDirectory = (gitFolderPath: string) => {
let gitPollAttempts = 0;
const openGitSlateWhenReady = () => {
+ if (cancelled) return;
gitPollAttempts += 1;
const gitNode = getNode(gitFolderPath);
// ... rest of function
};
openGitSlateWhenReady();
};
const expandWhenReady = () => {
+ if (cancelled) return;
repoPollAttempts += 1;
// ... rest of function
};
expandWhenReady();
+ return () => { cancelled = true; };
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const watchClonedRepoAndOpenGitSlate = ({ | |
| previewNode, | |
| onExpandRepo, | |
| onOpenGitSlate, | |
| }: RepoCloneWatcherArgs): void => { | |
| let repoPollAttempts = 0; | |
| const pollForGitDirectory = (gitFolderPath: string) => { | |
| let gitPollAttempts = 0; | |
| const openGitSlateWhenReady = () => { | |
| gitPollAttempts += 1; | |
| const gitNode = getNode(gitFolderPath); | |
| console.log( | |
| `Git folder poll attempt ${gitPollAttempts}, found:`, | |
| gitNode ? "yes" : "no", | |
| ); | |
| if (gitNode) { | |
| console.log("Opening git slate for:", gitFolderPath); | |
| onOpenGitSlate(gitFolderPath); | |
| return; | |
| } | |
| if (gitPollAttempts < MAX_GIT_POLL_ATTEMPTS) { | |
| setTimeout(openGitSlateWhenReady, POLL_INTERVAL_MS); | |
| return; | |
| } | |
| console.log("Timeout waiting for .git folder"); | |
| }; | |
| openGitSlateWhenReady(); | |
| }; | |
| const expandWhenReady = () => { | |
| repoPollAttempts += 1; | |
| const node = getNode(previewNode.path); | |
| if (node) { | |
| console.log("Found repo node, expanding:", previewNode.path); | |
| onExpandRepo(previewNode.path); | |
| const gitFolderPath = join(previewNode.path, ".git"); | |
| console.log("Looking for git folder at:", gitFolderPath); | |
| pollForGitDirectory(gitFolderPath); | |
| return; | |
| } | |
| if (repoPollAttempts < MAX_REPO_POLL_ATTEMPTS) { | |
| setTimeout(expandWhenReady, POLL_INTERVAL_MS); | |
| return; | |
| } | |
| console.log("Timeout waiting for cloned repo to appear in file tree"); | |
| }; | |
| expandWhenReady(); | |
| }; | |
| export const watchClonedRepoAndOpenGitSlate = ({ | |
| previewNode, | |
| onExpandRepo, | |
| onOpenGitSlate, | |
| }: RepoCloneWatcherArgs): (() => void) => { | |
| let cancelled = false; | |
| let repoPollAttempts = 0; | |
| const pollForGitDirectory = (gitFolderPath: string) => { | |
| let gitPollAttempts = 0; | |
| const openGitSlateWhenReady = () => { | |
| if (cancelled) return; | |
| gitPollAttempts += 1; | |
| const gitNode = getNode(gitFolderPath); | |
| console.log( | |
| `Git folder poll attempt ${gitPollAttempts}, found:`, | |
| gitNode ? "yes" : "no", | |
| ); | |
| if (gitNode) { | |
| console.log("Opening git slate for:", gitFolderPath); | |
| onOpenGitSlate(gitFolderPath); | |
| return; | |
| } | |
| if (gitPollAttempts < MAX_GIT_POLL_ATTEMPTS) { | |
| setTimeout(openGitSlateWhenReady, POLL_INTERVAL_MS); | |
| return; | |
| } | |
| console.log("Timeout waiting for .git folder"); | |
| }; | |
| openGitSlateWhenReady(); | |
| }; | |
| const expandWhenReady = () => { | |
| if (cancelled) return; | |
| repoPollAttempts += 1; | |
| const node = getNode(previewNode.path); | |
| if (node) { | |
| console.log("Found repo node, expanding:", previewNode.path); | |
| onExpandRepo(previewNode.path); | |
| const gitFolderPath = join(previewNode.path, ".git"); | |
| console.log("Looking for git folder at:", gitFolderPath); | |
| pollForGitDirectory(gitFolderPath); | |
| return; | |
| } | |
| if (repoPollAttempts < MAX_REPO_POLL_ATTEMPTS) { | |
| setTimeout(expandWhenReady, POLL_INTERVAL_MS); | |
| return; | |
| } | |
| console.log("Timeout waiting for cloned repo to appear in file tree"); | |
| }; | |
| expandWhenReady(); | |
| return () => { cancelled = true; }; | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderers/ivde/repoCloneWatcher.ts` around lines 15 - 66, The polling
logic in watchClonedRepoAndOpenGitSlate (functions expandWhenReady,
pollForGitDirectory, openGitSlateWhenReady) has no cleanup for setTimeout — add
cancellation: store each setTimeout ID (for both repo and git polls) in scoped
variables, set a "cancelled" flag when cleanup runs, clearTimeout for any
pending IDs, and short-circuit handlers (expandWhenReady/openGitSlateWhenReady)
if cancelled to avoid calling onExpandRepo/onOpenGitSlate after unmount; finally
change watchClonedRepoAndOpenGitSlate to return a cleanup function that performs
the clearing and sets the flag so callers can cancel polling.
| console.log( | ||
| `Git folder poll attempt ${gitPollAttempts}, found:`, | ||
| gitNode ? "yes" : "no", | ||
| ); | ||
| if (gitNode) { | ||
| console.log("Opening git slate for:", gitFolderPath); | ||
| onOpenGitSlate(gitFolderPath); | ||
| return; | ||
| } | ||
| if (gitPollAttempts < MAX_GIT_POLL_ATTEMPTS) { | ||
| setTimeout(openGitSlateWhenReady, POLL_INTERVAL_MS); | ||
| return; | ||
| } | ||
| console.log("Timeout waiting for .git folder"); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider removing or gating debug console.log statements.
The polling progress logs are useful during development but may clutter production console output. Consider using a debug flag or removing these before release.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderers/ivde/repoCloneWatcher.ts` around lines 28 - 41, The console.log
debugging inside openGitSlateWhenReady (which prints gitPollAttempts, gitNode
presence, "Opening git slate for:" with gitFolderPath, and the timeout message)
should be removed or gated behind a debug flag/logger; update the function to
either remove these console.log calls or replace them with a conditional
debug/logger check (e.g., a DEBUG/VERBOSE env flag or a renderer-level
logger.debug) so logs only emit when enabled, keeping behavior of invoking
onOpenGitSlate(gitFolderPath), setTimeout(openGitSlateWhenReady,
POLL_INTERVAL_MS) and the MAX_GIT_POLL_ATTEMPTS logic unchanged.
| if (commitRef !== "HEAD") { | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`${commitRef}:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| } | ||
| const content = await requests | ||
| .gitShow?.({ | ||
| options: [`HEAD:${filepath}`], | ||
| repoRoot: repoRootPath, | ||
| }) | ||
| .catch(() => ""); | ||
| return content || ""; | ||
| }; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Redundant branching can be simplified.
Lines 50-58 and 59-65 have nearly identical logic - both call gitShow with a commit ref and filepath. The HEAD case is just a special case of the general commit ref case.
♻️ Simplified implementation
- if (commitRef !== "HEAD") {
- const content = await requests
- .gitShow?.({
- options: [`${commitRef}:${filepath}`],
- repoRoot: repoRootPath,
- })
- .catch(() => "");
- return content || "";
- }
+ // Handle HEAD and any other commit ref uniformly
const content = await requests
.gitShow?.({
- options: [`HEAD:${filepath}`],
+ options: [`${commitRef}:${filepath}`],
repoRoot: repoRootPath,
})
.catch(() => "");
return content || "";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (commitRef !== "HEAD") { | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| } | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`HEAD:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; | |
| }; | |
| // Handle HEAD and any other commit ref uniformly | |
| const content = await requests | |
| .gitShow?.({ | |
| options: [`${commitRef}:${filepath}`], | |
| repoRoot: repoRootPath, | |
| }) | |
| .catch(() => ""); | |
| return content || ""; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderers/ivde/slates/git/diff.ts` around lines 50 - 66, The code
duplicates gitShow calls for the HEAD and non-HEAD cases; collapse them by
building a single refSpec and calling requests.gitShow once. Concretely, compute
const refSpec = `${commitRef}:${filepath}` (or use commitRef ?? "HEAD" if
commitRef can be undefined) and call requests.gitShow?.({ options: [refSpec],
repoRoot: repoRootPath }).catch(() => "") and return the result || "". Update
the block that currently branches on commitRef !== "HEAD" to this single unified
implementation referencing commitRef, filepath, repoRootPath, and
requests.gitShow.
| @@ -0,0 +1,69 @@ | |||
| export type GitChangeCode = "A" | "M" | "D" | "?" | ""; | |||
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how GitChangeCode is consumed and whether unknown codes are handled gracefully
echo "=== Usages of GitChangeCode ==="
rg -n "GitChangeCode" --type=ts -C3
echo ""
echo "=== Check if parsing handles unknown/fallback codes ==="
rg -n "changeType|changeCode" --type=ts -C5 src/renderers/ivde/slates/git/Repository: KooshaPari/colab
Length of output: 7183
Type assertion bypasses missing git status codes; consider explicit handling or expanded union.
GitChangeCode uses a type assertion (as GitChangeCode in helpers.ts:6) that allows any git status code to pass through, bypassing the incomplete union type. While the code doesn't crash—unknown codes fall back to default diff behavior via the empty string fallback—this masks whether renamed ("R"), copied ("C"), unmerged ("U"), or type-changed ("T") files are intentionally unsupported or accidentally unhandled. Either expand the union to include these codes or remove the type assertion and validate codes explicitly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderers/ivde/slates/git/types.ts` at line 1, GitChangeCode's union is
incomplete and is being bypassed by a type assertion in the helper (the cast to
"as GitChangeCode" in helpers.ts), so either expand the GitChangeCode type to
include the missing git status codes ("R", "C", "U", "T") or remove the
assertion and add explicit validation/mapping in the helper that returns the
existing fallback ("" or default behavior) for unknown codes; update the helper
(the function that currently does the "as GitChangeCode" cast) to perform a safe
runtime check (e.g., switch or lookup) against the allowed GitChangeCode values
and only return a typed GitChangeCode for known codes while handling unknowns
explicitly.
| "noUnusedLocals": false, | ||
| "noUnusedParameters": false, | ||
| "noPropertyAccessFromIndexSignature": false |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Track re-enabling strictness flags as technical debt.
Relaxing noUnusedLocals, noUnusedParameters, and noPropertyAccessFromIndexSignature is a reasonable approach during migration, but these flags help catch dead code and potential bugs. Consider adding a TODO or tracking issue to re-enable them once the lint/format migration stabilizes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tsconfig.json` around lines 27 - 29, The TypeScript strictness flags
noUnusedLocals, noUnusedParameters, and noPropertyAccessFromIndexSignature were
relaxed; add a concise technical-debt note and tracking entry: insert a TODO
comment near the three flags referencing a short ticket/issue ID (or create one)
to re-enable noUnusedLocals, noUnusedParameters, and
noPropertyAccessFromIndexSignature after lint/format migration stabilizes, and
create the corresponding task in your issue tracker with acceptance criteria for
re-enabling and fixing resulting errors.
Co-authored-by: Codex <noreply@openai.com>
3aba65a to
b0429f1
Compare
Scope CI typecheck to runtime protocol sources and run coverage job via the existing Vitest test script to avoid Bun test-runner mismatches. Co-authored-by: Codex <noreply@openai.com>
Summary\n- migrate lint/format wiring to OXC stack (oxlint, oxfmt, tsgolint)\n- add OXC config files and remove biome/prettier/eslint surfaces where present\n- keep repo-native gates wired to the new stack\n\n## Validation\n- ran repo-native lint/format/quality commands in each lane\n- pre-existing debt and environment blockers are documented in lane notes
Summary by CodeRabbit
Release Notes
New Features
Chores
Documentation