Skip to content

feat: auto-restart tools when dependency lock file changes#177

Draft
Copilot wants to merge 8 commits intomainfrom
copilot/improve-vscode-extension-ui
Draft

feat: auto-restart tools when dependency lock file changes#177
Copilot wants to merge 8 commits intomainfrom
copilot/improve-vscode-extension-ui

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

Watches dependency lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb, bun.lock) for changes so that tools are restarted automatically after npm install, pnpm install, yarn install, or bun install — without requiring a VS Code restart. For globally installed or settings-specified binaries that have no project lock file, the binary file itself is watched directly.

Changes Made

  • client/findBinary.ts — added watcherPath?: string to BinarySearchResult. When set, BinaryWatcher watches that specific file instead of searching for a lock file. searchGlobalNodeModulesBin and searchSettingsBin set this to the resolved binary path; project-local search functions (searchProjectNodeModulesBin, searchYarnPnpBin) leave it unset so lock-file walking handles them.
  • client/tools/BinaryWatcher.ts — new class with two watching strategies:
    • Global / settings-specified binaries (watcherPath set): watches that exact file for creation, change, and deletion — since global installs have no project lock file.
    • Project-local binaries (watcherPath not set): walks up from the resolved binary path to the first ancestor directory containing a lock file and watches that directory. This correctly handles pnpm's versioned store layout (.pnpm/pkg@version/node_modules/…) where updating a package creates a brand-new directory instead of modifying the existing binary. Falls back to all workspace folders when no binary is found yet (initial install) or no lock file is found on the walk.
  • client/extension.ts — passes the BinarySearchResult from findBinary to BinaryWatcher.
  • .gitignorepackage-lock.json added.

Testing

  • ✅ Build verified (rolldown compiles successfully)
  • ✅ CodeQL scan passed (0 alerts)
Original prompt

This section details on the original issue you should resolve

<issue_title>Improve VS Code Extension User Experience</issue_title>
<issue_description>Currently, the extension's internal state, the Status Bar UI, and the actual background processes frequently fall out of sync. This leads to confusion regarding whether the tools are actually running and results in a broken feedback loop.

Proposed Fixes & Features

  1. (Fix) Sync oxc.enable with extension UI. When I set oxc.enable: false, the extension UI still reports oxlint is enabled (vX.X.X) and oxfmt is enabled (vX.X.X). Conversely, when I set oxc.enable: true, the UI incorrectly reports oxlint is disabled (oxc.enable is false) and oxfmt is disabled. fix: update status bar item tooltip after changes #43

  2. (Fix) Sync process start/kill. When setting oxc.enable: false, oxlint is correctly killed, but oxfmt continues to run, wasting resources and locking node_modules. When setting oxc.enable: true, only oxlint is correctly started; oxfmt does not initialize. feat: add oxc.enable.oxlint and oxc.enable.oxfmt to control each connection separately #32

  3. (Fix) Make Stop Server a functional toggle. When I click Stop Server, the extension still displays oxlint is enabled (vX.X.X) and the button label does not change. Please add proper Start/Stop Server states and synchronize the label to show oxlint is enabled/disabled. fix: update status bar item tooltip after changes #43

  4. (Feature Request) Allow independent control of linting and formatting. Introduce oxc.fmt.enable and oxc.lint.enable to allow starting/stopping them separately. Keep oxc.enable as a master toggle to enable/disable all. Add Start/Stop Server functionality to oxfmt and sync the status to show oxlint/oxfmt is enabled (vX.X.X)/disabled. feat: add oxc.enable.oxlint and oxc.enable.oxfmt to control each connection separately #32

  5. (Fix) Check settings on dependency installation. When running npm/bun install, the extension should check settings.json and start oxlint and oxfmt if oxc.enable is true. Currently, a VS Code restart is required for this to take effect. This should also sync with the extension UI.

  6. (Feature Request) Make the oxc status bar item clickable. Unlike most VS Code status bar buttons, the oxc item is not consistently responsive. If I click it, the menu often fails to open unless I move the mouse out of the area and re-enter.

Disclaimer: These are personal suggestions. Feel free to address whichever items the team approves.</issue_description>

<agent_instructions>Only do this task:
(Fix) Check settings on dependency installation. When running npm/bun install, the extension should check settings.json and start oxlint and oxfmt if oxc.enable is true. Currently, a VS Code restart is required for this to take effect. This should also sync with the extension UI.
Add a file watcher on the found binary and restart the complete tool inside the extension. You are allowed to create a new class if this improves readability</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@Sysix Thank you for the proposed improvements. I will look into each one individually :) @Sysix Note: the newest release improved the status bar item and the tooltip of it. It now respectfully updated its content, but only after a re-hover. This is how VS Code works and we do not have a way to optimize it. Maybe making it clickable will solve this problem 🤞 Do not know if there is even a way, but I noticed the inconsistency too :) @Sysix "oxc.enable" is a "root" switch for both "oxc.enable.oxlint" and "oxc.enable.oxfmt". This is how VS Code resolve the config, nothing we can do :(

test("update enable, will update enable.oxlint and enable.oxfmt respectively", async () => {
await conf.update("enable", false);
const config = new VSCodeConfig();
strictEqual(config.enableOxlint, false);
strictEqual(config.enableOxfmt, false);
});
test("update `enable.oxlint` to false, while `enable` is true", async () => {
await conf.update("enable", true);
await conf.update("enable.oxlint", false);
const config = new VSCodeConfig();
strictEqual(config.enableOxlint, true);
strictEqual(config.enableOxfmt, true);
});
test("updating values updates the workspace configuration", async () => {
const config = new VSCodeConfig();
await Promise.all([
config.updateEnableOxlint(false),
config.updateEnableOxfmt(false),
config.updateRequireConfig(true),
config.updateTrace("messages"),
config.updateBinPathOxlint("./binary"),
config.updateBinPathOxfmt("./formatter"),
config.updateBinPathTsGoLint("./tsgolint"),
config.updateNodePath("./node"),
]);
const wsConfig = workspace.getConfiguration("oxc");
strictEqual(wsConfig.get("enable.oxlint"), false);
strictEqual(wsConfig.get("enable.oxfmt"), false);
strictEqual(wsConfig.get("requireConfig"), true);
strictEqual(wsConfig.get("trace.server"), "messages");
strictEqual(wsConfig.get("path.oxlint"), "./binary");
strictEqual(wsConfig.get("path.oxfmt"), "./formatter");
strictEqual(wsConfig.get("path.tsgolint"), "./tsgolint");
strictEqual(wsConfig.get("path.node"), "./node");
});
</comment_new>


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Copilot AI changed the title [WIP] Fix sync issues between extension state and UI feat: auto-restart tools when binary is created/deleted in node_modules Mar 25, 2026
Copilot AI requested a review from Sysix March 25, 2026 22:16
@Sysix
Copy link
Copy Markdown
Member

Sysix commented Mar 25, 2026

@copilot check for findBinary result, do not check by yourself. We only want to watch for this one file per tool.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot check for findBinary result, do not check by yourself. We only want to watch for this one file per tool.

Done in commit 80cc971. BinaryWatcher now accepts the BinarySearchResult from findBinary directly and uses RelativePattern to watch exactly that one file. When no binary was found (not yet installed), it falls back to {firstWorkspaceFolder}/node_modules/.bin/{binaryName} so that the initial npm install is still detected. One watcher per tool in all cases.

Comment thread client/tools/BinaryWatcher.ts Outdated
* first workspace folder is returned so that an initial `npm install` is
* also detected.
*/
private resolveWatchPath(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot The watch file should already be resolved. No need to check for workspace or exe extension

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1e05627. Removed the fallback resolveWatchPath logic entirely — BinaryWatcher now simply returns early when binary is undefined, and uses binary.path directly when it is resolved.

Copilot AI requested a review from Sysix March 25, 2026 22:47
@Dykam
Copy link
Copy Markdown

Dykam commented Mar 26, 2026

Does this resolve one of the core issues which is that the extension locks the binaries? There is no use in adding a watcher if you can't update the binaries.

@Sysix
Copy link
Copy Markdown
Member

Sysix commented Mar 26, 2026

@Dykam I guess you are on Windows? I could not find an issue in this repo. Could you please create one.
This PR will not fix it.

@Sysix
Copy link
Copy Markdown
Member

Sysix commented Mar 28, 2026

@copilot this will not work as expected. When we found the binary, we have for pnpm a path like:
/home/sysix/dev/oxc-vscode/node_modules/.pnpm/oxfmt@0.42.0/node_modules/oxfmt/bin/oxfmt
Updating it, will create a new folder with binary in .pnpm, instead of updating the old binary.

We should search from the found binary the projects package.json or the lock file (respect yarn, pnpm, bun lock files too).
And watch for changes from there.
Keep in mind there are monorepos with multiple package jsons.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 28, 2026

@copilot this will not work as expected. When we found the binary, we have for pnpm a path like:
`/home/sysix/dev/oxc-vscode/node_modules/.pnpm/oxfmt@0.42.0/node_modules/oxfmt/bin/o...

Done in 63e2ad1. BinaryWatcher now watches lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb, bun.lock) instead of the binary itself.

When a binary is found, findProjectRoot walks up from the binary path to the first ancestor directory containing a lock file — so for pnpm's path like /project/node_modules/.pnpm/oxfmt@0.42.0/node_modules/oxfmt/bin/oxfmt it correctly resolves to /project and watches pnpm-lock.yaml there.

When no binary is found yet (initial install), all workspace folders are watched so the first npm/pnpm/yarn/bun install is still detected. The same workspace-folder fallback is used if no lock file is found by walking up.

Copilot AI changed the title feat: auto-restart tools when binary is created/deleted in node_modules feat: auto-restart tools when dependency lock file changes Mar 28, 2026
@Sysix
Copy link
Copy Markdown
Member

Sysix commented Mar 28, 2026

@copilot does global installed modules have a lock file? We need to have a way to watch for them too if not.
You can change the BinarySearchResult to include a watcher path if you want.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 28, 2026

@copilot does global installed modules have a lock file? We need to have a way to watch for them too if not.
You can change the BinarySearchResult to include a watcher path if you...

Done in b43f239. Added watcherPath?: string to BinarySearchResult:

  • searchGlobalNodeModulesBin and searchSettingsBin both set watcherPath: result.path — since global installs have no project lock file, BinaryWatcher falls into a new branch that watches that specific file for create/change/delete events.
  • searchProjectNodeModulesBin and searchYarnPnpBin leave watcherPath unset — BinaryWatcher continues using its lock-file walking logic for those (handles pnpm versioned store etc.).

A small withWatcherPath() helper in findBinary.ts keeps the pattern DRY across both functions that need it.

@ZWQ652
Copy link
Copy Markdown

ZWQ652 commented Mar 31, 2026

@copilot this will not work as expected. When we found the binary, we have for pnpm a path like:这不会按预期工作。当我们找到二进制文件时,对于 pnpm,我们有一个类似这样的路径: /home/sysix/dev/oxc-vscode/node_modules/.pnpm/oxfmt@0.42.0/node_modules/oxfmt/bin/oxfmt Updating it, will create a new folder with binary in .pnpm, instead of updating the old binary.更新它,将会在.pnpm 中创建一个包含二进制文件的新文件夹,而不是更新旧的二进制文件。

We should search from the found binary the projects package.json or the lock file (respect yarn, pnpm, bun lock files too).我们应该从找到的二进制文件中搜索项目的 package.json 或锁定文件(也要支持 yarn、pnpm、bun 的锁定文件)。 And watch for changes from there.然后留意从那里开始的变化。 Keep in mind there are monorepos with multiple package jsons.请记住,有些单体仓库中包含多个 package.json 文件。

Has it been considered that some projects already have package-lock. json but do not have node-modules.
This situation should also be restarted after npm i

@ZWQ652
Copy link
Copy Markdown

ZWQ652 commented Mar 31, 2026

#181 restart lint server after npm i

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve VS Code Extension User Experience

4 participants