Skip to content

Extension activation or no EIM fixes#1797

Open
brianignacio5 wants to merge 9 commits intomasterfrom
bugfix/extension-activation
Open

Extension activation or no EIM fixes#1797
brianignacio5 wants to merge 9 commits intomasterfrom
bugfix/extension-activation

Conversation

@brianignacio5
Copy link
Copy Markdown
Collaborator

@brianignacio5 brianignacio5 commented Mar 20, 2026

Description

Fixes for non EIM setups that rely on old ESP-IDF setups. Fix New Project Wizard so it doesn't need esptool.py to get serial ports and only rely that IDF_PATH exists.

Fixes #1794
Fixes #1795

This pull request introduces several improvements and refactors to the ESP-IDF extension, focusing on enhancing robustness, simplifying code, and improving error handling. The most important changes include stricter validation of IDF setups, improved serial port listing logic, consolidation and simplification of tool verification methods, and more informative error reporting throughout the extension.

IDF Setup and Environment Validation

  • Added checks to ensure IDF setups and paths exist before using them, preventing errors from missing or invalid configurations. (src/eim/loadIdfSetup.ts, src/extension.ts, src/pythonManager.ts, [1] [2] [3]
  • Modified environment variable loading to prioritize custom variables and ensure paths are valid before proceeding. (src/eim/loadIdfSetup.ts, src/eim/loadIdfSetup.tsL125-R135)

Serial Port Listing Improvements

  • Refactored the serial port listing logic to allow skipping the esptool call, improving performance and reliability when listing ports for new projects. (src/espIdf/serial/serialPort.ts, [1] [2] [3] [4] [5] [6]

Tool Verification Refactor

  • Consolidated getRequiredToolsInfo and getEIMToolsInfo methods in IdfToolsManager into a single streamlined method, reducing code duplication and simplifying tool verification logic. (src/idfToolsManager.ts, [1] [2]
  • Updated tool verification calls throughout the codebase to use the new method signature. (src/eim/verifySetup.ts, [1] src/support/checkEspIdfTools.ts, [2]

Error Handling and Reporting

  • Enhanced error messages and reporting for requirements and environment checks, making errors more descriptive and easier to diagnose. (src/support/checkEspIdfRequirements.ts, [1] [2] [3]
  • Improved error handling in file access checks for flash tasks, ensuring the correct file name is reported. (src/flash/eraseFlashTask.ts, [1] src/flash/flashTask.ts, [2]

Miscellaneous Refactors

  • Removed unnecessary parameters and reordered logic in project initialization for clarity and maintainability. (src/newProject/newProjectInit.ts, [1] [2]
  • Minor cleanup, such as removing unused imports. (src/eim/loadSettings.ts, src/eim/loadSettings.tsL19)

These changes collectively improve reliability, maintainability, and user experience across the extension.

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Steps to test this pull request

  1. Without any EIM ESP-IDF Setup selected try to use the ESP-IDF: New Project wizard which should allow users to select from EIM ESP-IDF setups without any opened directory.
  2. Allow user to configure the ESP-IDF extension using idf.customExtraVars by using IDF_PATH, IDF_TOOLS_PATH or PATH and IDF_PYTHON_VENV_PATH and use that override any currently selected setup. See installation docs in the preview.
  • Expected behaviour:

  • Expected output:

How has this been tested?

Manual test

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Component 1
  • Component 2

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • Bug Fixes

    • Clearer "setup not found" messaging, stronger path/permission checks (including git/tool availability), and improved environment-derived configuration validation.
  • Refactor

    • More reliable workspace setup selection and persistence; streamlined tool discovery/path handling; serial port listing can skip slow chip probing for faster responsiveness; permission checks now include contextual filenames.
  • Documentation

    • Added manual ESP-IDF/tools configuration guidance (en and zh_CN).
  • Tests

    • Updated requirement-path error assertion.

@brianignacio5 brianignacio5 self-assigned this Mar 20, 2026
Copilot AI review requested due to automatic review settings March 20, 2026 11:26
@brianignacio5 brianignacio5 added this to the v2.1.0 milestone Mar 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Always prefer an environment-derived ESP‑IDF setup (extension custom vars or process env), validate filesystem and tooling presence (IDF, tools, git, esptool), persist the chosen setup to workspace config, simplify tool-info APIs and tooling checks, add contextual access labels, allow skipping esptool per-port probes, adjust new‑project flow, update docs/tests, and remove unused classes/files.

Changes

Cohort / File(s) Summary
IDF setup & env loading
src/eim/loadIdfSetup.ts, src/eim/loadSettings.ts, src/eim/verifySetup.ts
Try env-derived setup first; prefer idf.customExtraVars over process.env; add path existence checks for IDF/tools/git; persist idf.currentSetup after selection; isIdfSetupValid now accepts env var map; removed unused EOL import.
Tooling manager & python env
src/idfToolsManager.ts, src/pythonManager.ts, src/eim/migrationTool.ts
Removed basePath param from getRequiredToolsInfo; always compute versions via provided path; return env from package export_vars; pre-flight pathExists checks for idf/tools; allow injected exported tools PATH when building env.
Utilities & access checks
src/utils.ts, src/support/configurationAccess.ts, src/support/gitVersion.ts, src/support/checkEspIdfTools.ts, src/support/checkEspIdfRequirements.ts
canAccessFile gains optional context label; isBinInPath returns Promise<string> and supports container-path filtering; git exec/version parsing wrapped in try/catch with richer error output; callers updated to pass contextual labels and fewer args to tools API.
Serial port & flashing
src/espIdf/serial/serialPort.ts, src/flash/flashTask.ts, src/flash/eraseFlashTask.ts
Serial listing gains skipEsptoolCall opt-out to avoid esptool probes; per-port esptool interrogation preserved when enabled; file permission checks (canAccessFile) now include contextual filename info.
New project & extension init
src/extension.ts, src/newProject/newProjectInit.ts, src/newProject/utils.ts
Filter IDF setups by existing paths before starting new-project flow; remove extensionPath param from getNewProjectArgs; reorder steps (load setups before serial/boards); pass skip flag to serial enumeration; templates may import idf.customExtraVars.
Validation & migration helpers
src/support/checkIdfSetups.ts, src/eim/migrationTool.ts
Validate setups by calling getEnvVariables and pass env map into isIdfSetupValid; allow external exported-tools PATH string to populate PATH.
Removed / minor UI & tests
src/PyReqLog.ts (deleted), src/packageWebError.ts (deleted), src/views/nvs-partition-table/App.vue, src/test/doctor.test.ts
Removed PyReqLog and PackageManagerWebError; small Vue index casting fix (Number(i) !== 0); updated test expectation to include missing requirements path.
Docs / localization
docs_espressif/en/installation.rst, docs_espressif/zh_CN/installation.rst
Added manual env/settings-based configuration guidance and precedence; localization/shortcut text fixes and examples for idf.customExtraVars and exporting env vars.

Sequence Diagram(s)

sequenceDiagram
  participant Env as Env / idf.customExtraVars
  participant Ext as Extension (loadIdfSetup)
  participant FS as Filesystem
  participant Tools as IdfToolsManager
  participant WS as Workspace config

  Ext->>Env: read customExtraVars / process.env
  Ext->>FS: pathExists(IDF_PATH), pathExists(IDF_TOOLS_PATH), isBinInPath("git")
  alt env-defined paths exist and valid
    Ext->>Tools: getRequiredToolsInfo(pathToTools, ["cmake","ninja"])
    Tools-->>Ext: tools env + versions
    Ext->>WS: write idf.currentSetup (env-derived)
    Ext-->>Env: return env-defined setup
  else fallback to workspace setups
    Ext->>WS: read idf.setups list
    Ext->>FS: pathExists(setup.idfPath) for configured currentSetup
    alt found matching setup
      Ext->>WS: write idf.currentSetup (selected)
      Ext-->>Env: return workspace setup
    else
      Ext-->>Env: notify "Current ESP-IDF setup is not found" or "No ESP-IDF Setups found"
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Suggested reviewers

  • Fabricio-ESP
  • AndriiFilippov
  • radurentea
  • kolipakakondal

Poem

🐇 I hopped through PATHs and envs today,
sniffed out scripts and tools along the way.
I favored custom vars, checked every tray,
wrote back the choice, then bounded off to play.
🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title "Extension activation or no EIM fixes" is vague and does not clearly convey the main changes; it uses non-descriptive phrasing that lacks specificity about what issues are being addressed. Consider using a more descriptive title such as "Support manual ESP-IDF installations without EIM requirement" or "Fix IDF path precedence and legacy setup compatibility."
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR addresses core requirements from both linked issues: restoring manual IDF setup support [#1794], prioritizing custom variables and configured paths [#1795], making EIM optional with fallbacks, and improving diagnostics.
Out of Scope Changes check ✅ Passed All file modifications align with stated objectives: env-var loading refactors, path validation, tool verification consolidation, serial-port skipping for wizards, error-message improvements, and documentation updates directly support manual-setup and path-precedence goals.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/extension-activation

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, 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 significantly enhances the robustness and user experience of the ESP-IDF extension by focusing on more reliable environment setup, optimized serial port detection, and clearer error diagnostics. The changes aim to streamline the extension's operation, particularly for non-EIM setups and the New Project Wizard, by ensuring that necessary paths and tools are correctly identified and validated, leading to a more stable and predictable development environment.

Highlights

  • IDF Setup and Environment Validation: Implemented stricter checks for the existence of IDF setups and paths, preventing errors from invalid configurations. Environment variable loading now prioritizes custom variables and ensures path validity.
  • Serial Port Listing Improvements: Refactored serial port listing logic to optionally skip the esptool.py call, enhancing performance and reliability, especially for the New Project Wizard.
  • Tool Verification Refactor: Consolidated getRequiredToolsInfo and getEIMToolsInfo methods in IdfToolsManager into a single, streamlined function, reducing code duplication and simplifying tool verification.
  • Enhanced Error Handling and Reporting: Improved error messages and reporting across various checks (requirements, environment, file access) to provide more descriptive and actionable feedback.
  • New Project Wizard Optimization: Reordered logic and removed unnecessary parameters in the New Project Wizard initialization, improving clarity and maintainability, and leveraging the new serial port listing capabilities.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces several improvements to the ESP-IDF extension's setup and tool management. Key changes include enhancing error handling for Git version retrieval, optimizing serial port listing by allowing esptool calls to be skipped for performance, and making IDF setup loading more robust by validating paths with pathExists. The IdfToolsManager was refactored to consolidate tool information retrieval, reducing code duplication. Environment variable handling was improved by prioritizing user-defined custom variables and dynamically detecting the Git executable path. Additionally, the new project wizard's initialization flow was optimized by deferring serial port and board list loading until after IDF setup selection, and pathExists checks were added before executing idf_tools.py to prevent errors from missing paths. Error reporting for ESP-IDF requirements checks was also made more detailed.

Comment on lines +28 to 49
try {
const rawGitVersion = await execChildProcess(
reportedResult.configurationSettings.gitPath,
["--version"],
context.extensionPath
);
} else {
reportedResult.gitVersion.result = "Not found";
reportedResult.gitVersion.output = rawGitVersion;
const versionMatches = rawGitVersion.match(GIT_VERSION_REGEX);
if (versionMatches && versionMatches.length) {
reportedResult.gitVersion.result = versionMatches[0].replace(
/git\sversion\s/g,
""
);
} else {
reportedResult.gitVersion.result = "Not found";
}
} catch (error) {
reportedResult.gitVersion.output =
error instanceof Error ? error.message : String(error);
reportedResult.gitVersion.result = "Error: " + reportedResult.gitVersion.output;
reportedResult.latestError = error;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

Wrapping the execChildProcess call in a try...catch block for getGitVersion is a critical improvement. It ensures that failures in retrieving the Git version are gracefully handled, and the reportedResult is populated with detailed error information, enhancing the overall robustness and diagnostic capabilities of the extension.

Comment on lines +335 to +339
public async getListArray(
workspaceFolder: vscode.Uri,
skipEsptoolCall: boolean = false
) {
return await this.list(workspaceFolder, skipEsptoolCall);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Adding skipEsptoolCall as a parameter to getListArray and list methods is a significant improvement. This allows callers, like the New Project Wizard, to bypass the potentially slow esptool call when chip ID detection is not immediately necessary, improving performance and user experience.

Comment on lines +2345 to +2349
let existingIdfSetups = await Promise.all(
idfSetups.map(async (setup) => {
return (await pathExists(setup.idfPath)) ? setup : null;
})
).then((results) => results.filter((setup) => setup !== null));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Filtering idfSetups with pathExists to create existingIdfSetups before passing them to getNewProjectArgs is a good robustness improvement. It ensures that only valid and accessible IDF paths are considered, preventing potential errors from stale or incorrect configurations.

const gitPath = "/usr/bin/git";
const idfSetupId = getIdfMd5sum(idfPath);
const idfVersion = await getEspIdfFromCMake(idfPath);
const gitPath = await isBinInPath("git", process.env);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Changing gitPath = "/usr/bin/git" to gitPath = await isBinInPath("git", process.env) makes the Git executable detection more dynamic and robust. This avoids hardcoding a path that might not be valid across different operating systems or user installations, improving portability and reliability.

Comment on lines +133 to +135
if (customVars["IDF_PYTHON_ENV_PATH"] || process.env.IDF_PYTHON_ENV_PATH) {
venvPythonPath = join(
process.env.IDF_PYTHON_ENV_PATH || customVars["IDF_PYTHON_ENV_PATH"],
customVars["IDF_PYTHON_ENV_PATH"] || process.env.IDF_PYTHON_ENV_PATH,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to IDF_PATH, prioritizing customVars["IDF_PYTHON_ENV_PATH"] for the Python virtual environment path is a good improvement. It ensures consistency in respecting user-defined custom variables.

Comment on lines 337 to 346
pathToVerify?: string,
onReqPkgs?: string[],
logToChannel: boolean = true
) {
let versions: { [key: string]: string } = {};
if (pathToVerify) {
versions = await this.verifyPackages(
pathToVerify,
onReqPkgs,
logToChannel
);
}
const packages = await this.getPackageList(onReqPkgs);
const idfToolsList = packages.map((pkg) => {
const pkgVersionsForPlatform = pkg.versions.filter((version) => {
return (
Object.getOwnPropertyNames(version).indexOf(
this.platformInfo.platformToUse
) > -1 ||
Object.getOwnPropertyNames(version).indexOf(
this.platformInfo.fallbackPlatform
) > -1
);
});
const expectedVersions = pkgVersionsForPlatform.map((p) => p.name);
let isToolVersionCorrect =
expectedVersions.indexOf(versions[pkg.name]) > -1 ||
(versions[pkg.name] && versions[pkg.name] === "No command version");
const versionToUse = this.getVersionToUse(pkg);
let pkgExportedPath: string = "";
let pkgVars = pkg.export_vars;
if (basePath) {
pkgExportedPath = pkg.binaries
? path.join(basePath, pkg.name, versionToUse, ...pkg.binaries)
: path.join(basePath, pkg.name, versionToUse);
pkgVars = this.exportVarsForPkg(pkg, basePath);
}
return {
actual: versions[pkg.name] || "",
description: pkg.description,
doesToolExist: isToolVersionCorrect,
env: pkgVars,
expected: expectedVersions.join(","),
name: pkg.name,
path: pkgExportedPath,
} as IEspIdfTool;
});
return idfToolsList;
}

public async getEIMToolsInfo(
pathToVerify: string,
onReqPkgs?: string[],
logToChannel: boolean = true
) {
let versions: { [key: string]: string } = await this.verifyPackages(
const versions = await this.verifyPackages(
pathToVerify,
onReqPkgs,
logToChannel
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The consolidation of getRequiredToolsInfo and getEIMToolsInfo into a single getRequiredToolsInfo method is a significant refactoring improvement. It simplifies the API, reduces code duplication, and makes the tool verification logic more consistent.

Comment on lines +109 to +127
progress.report({ increment: 10, message: "Loading serial ports..." });
let serialPortList: Array<string> = ["detect"];
try {
const serialPortListDetails = await SerialPort.shared().getListArray(
workspace,
true
);
serialPortList.push(...serialPortListDetails.map((p) => p.comName));
} catch (error) {
const msg = error.message
? error.message
: "Error looking for serial ports.";
Logger.infoNotify(msg);
Logger.error(msg, error, "getNewProjectArgs getSerialPort");
serialPortList = ["no port"];
}
progress.report({ increment: 10, message: "Loading ESP-IDF Boards list..." });
const openOcdScriptsPath = await getOpenOcdScripts(workspace);
let espBoards = await getBoards(openOcdScriptsPath);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Moving the serial port and board list loading logic to after the IDF setup selection is a logical improvement. These operations might depend on the chosen IDF setup, ensuring that the correct environment is used. Additionally, calling getListArray with true for skipEsptoolCall is a key performance optimization for the New Project Wizard.

Comment on lines +75 to +82
const doesIdfPathExist = await pathExists(espIdfPath);
if (!doesIdfPathExist) {
return idfToolsDict;
}
const doesIdfToolsPyExist = await pathExists(idfToolsPyPath);
if (!doesIdfToolsPyExist) {
return idfToolsDict;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Adding pathExists checks for espIdfPath and idfToolsPyPath before attempting to execute idf_tools.py significantly improves the robustness of getEnvVarsFromIdfTools. This prevents errors from being thrown if these critical paths are missing, leading to more graceful failure handling.

Comment on lines +55 to +57
reportedResult.idfCheckRequirements.output =
error instanceof Error ? error.message : String(error);
reportedResult.idfCheckRequirements.result = "Error: " + reportedResult.idfCheckRequirements.output;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Capturing the actual error message and including it in both output and result fields provides more detailed and actionable information when checkEspIdfRequirements fails. This significantly improves error reporting.

Comment on lines +80 to +85
await writeParameter(
"idf.currentSetup",
idfSetupToUse.idfPath,
ConfigurationTarget.WorkspaceFolder,
workspaceFolder
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Moving the writeParameter("idf.currentSetup", ...) call to this block ensures that the idf.currentSetup is consistently updated after idfSetupToUse has been determined, regardless of whether it was found from existing setups or defaulted. This improves the reliability of the configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves extension activation and “New Project” wizard behavior for non-EIM / legacy ESP-IDF setups by making IDF setup selection more robust, reducing reliance on esptool.py for serial-port listing, and simplifying tool verification/error reporting.

Changes:

  • Skip esptool.py-based chip-id probing when listing serial ports for the New Project wizard to avoid failures in legacy/non-EIM setups.
  • Refactor/streamline tool verification (IdfToolsManager.getRequiredToolsInfo) and improve error reporting in support diagnostics.
  • Add additional validation of IDF setups/paths during activation and setup loading.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/views/nvs-partition-table/App.vue Ensures first row deleteability check is numeric-safe.
src/utils.ts Extends canAccessFile logging details; updates isBinInPath typing/docs.
src/support/gitVersion.ts Wraps git version detection in try/catch and records error details.
src/support/configurationAccess.ts Passes context labels into canAccessFile for better diagnostics.
src/support/checkEspIdfTools.ts Updates to new getRequiredToolsInfo signature.
src/support/checkEspIdfRequirements.ts Improves requirements-path error message and captures error output.
src/pythonManager.ts Adds existence checks for IDF_PATH/idf_tools.py before exporting vars.
src/newProject/newProjectInit.ts Moves serial-port loading later and skips esptool-based probing for wizard.
src/idfToolsManager.ts Consolidates tool-info methods into a single getRequiredToolsInfo.
src/flash/flashTask.ts Improves file-access logging context for flash script and section binaries.
src/flash/eraseFlashTask.ts Improves file-access logging context for esptool.py.
src/extension.ts Filters out invalid IDF setups (missing idfPath) before launching wizard.
src/espIdf/serial/serialPort.ts Adds skipEsptoolCall option to avoid esptool-based chip-id requests.
src/eim/verifySetup.ts Switches to consolidated getRequiredToolsInfo for EIM/non-EIM paths.
src/eim/loadSettings.ts Removes unused import cleanup.
src/eim/loadIdfSetup.ts Adjusts setup selection and env-var based setup creation (IDF_PATH priority, git path lookup).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/utils.ts (1)

1079-1083: ⚠️ Potential issue | 🟠 Major

Keep scanning PATH when the first hit is outside containerDir.

Returning here drops the rest of the PATH search. If a system binary appears before the ESP-IDF-managed one, the function reports “not found” even when a later entry matches the requested container.

🔧 Suggested fix
       if (containerDir && containerDir.length) {
         const resultContainerPath = containerDir.join(path.sep);
         if (binaryPath.indexOf(resultContainerPath) === -1) {
-          return "";
+          continue;
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils.ts` around lines 1079 - 1083, The current check inside the PATH
scan returns "" as soon as a found binaryPath does not include the
resultContainerPath (containerDir.join(path.sep)), which aborts further PATH
entries and can miss a later valid container-managed binary; change the logic so
that when binaryPath.indexOf(resultContainerPath) === -1 you skip this candidate
and continue scanning the rest of PATH (e.g., replace the early return with
continuing the loop or otherwise only return "" after the entire PATH has been
exhausted), keeping the use of containerDir, resultContainerPath and binaryPath
to locate valid matches.
src/idfToolsManager.ts (1)

26-34: ⚠️ Potential issue | 🟠 Major

Remove the type cast and either populate path or remove it from the interface.

The mapper omits the required path: string property but casts to IEspIdfTool, hiding a contract break. The env is assigned raw pkg.export_vars, which contains unresolved ${TOOL_PATH} placeholders. While current consumers in verifySetup.ts only read doesToolExist and name, any code attempting to access tool.path will get undefined at runtime. Additionally, reportedResult.espIdfToolsVersions expects idfToolResult[] (4 props: actual, doesToolExist, expected, name), but this function returns 6-property objects including description and env, creating a hidden type mismatch.

Either:

  • Include path in the mapper (calling exportVarsForPkg() to resolve placeholders if needed), or
  • Update IEspIdfTool and idfToolResult to match what the function actually returns and remove the cast.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/idfToolsManager.ts` around lines 26 - 34, The mapper is casting package
objects to IEspIdfTool but omits path and leaves env with unresolved
placeholders, causing a contract break with IEspIdfTool and idfToolResult;
either populate path and resolve env by calling exportVarsForPkg() inside the
mapper so each returned object includes path: string and a resolved env, or
change the types (IEspIdfTool and idfToolResult) to match the actual returned
shape and remove the unsafe cast; update references such as
reportedResult.espIdfToolsVersions and verifySetup.ts to use the corrected
shape.
🧹 Nitpick comments (3)
src/views/nvs-partition-table/App.vue (1)

80-80: Unnecessary type conversion and unrelated to PR objectives.

The Number(i) wrapper is redundant because i from Vue's v-for array iteration is already a numeric index. The original i !== 0 was correct and type-safe. Additionally, this NVS partition table UI change appears unrelated to the PR's stated objectives (fixing path resolution and EIM setup issues). Consider reverting this change to keep the PR focused.

♻️ Revert to original expression
-        :canDeleteRow="Number(i) !== 0"
+        :canDeleteRow="i !== 0"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/views/nvs-partition-table/App.vue` at line 80, The prop binding
:canDeleteRow was changed to use Number(i) but the v-for index i is already a
number; revert the expression to the original i !== 0 to remove the unnecessary
type conversion. Update the template where :canDeleteRow is set (the binding
using the loop variable i) to use i !== 0 so the UI logic remains unchanged and
unrelated PR scope stays focused.
src/espIdf/serial/serialPort.ts (1)

335-363: Prefer a named option over skipEsptoolCall.

Threading a bare boolean through getListArray() and list() already produces call sites like getListArray(workspace, true), which are hard to read and easy to invert later. An options object or a dedicated helper would make the new behavior self-documenting.

As per coding guidelines "Prefer self-documenting code (names + small helpers) over comments; write comments for intent/why/constraints/edge cases instead of narrating what the code already says".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/espIdf/serial/serialPort.ts` around lines 335 - 363, Replace the bare
boolean flag skipEsptoolCall on getListArray and list with a small options
object (e.g., { skipEsptoolCall?: boolean } or more explicit { useEsptool?:
boolean }) so callers use named properties instead of positional booleans;
update the signatures of getListArray(workspaceFolder, options) and
list(workspaceFolder, options) and all call sites that call getListArray(...,
true/false) to pass a descriptive object (e.g., getListArray(workspace, {
skipEsptoolCall: true })) and adjust any internal uses of skipEsptoolCall inside
list to read options.skipEsptoolCall.
src/support/gitVersion.ts (1)

44-49: Consider using Logger.error for caught errors.

Per coding guidelines, caught errors should use Logger.error(message, error, "scope identifier"). While the error is captured in reportedResult.latestError, adding explicit logging would improve observability.

Suggested addition
   } catch (error) {
+    Logger.error("Failed to get git version", error, "support gitVersion");
     reportedResult.gitVersion.output =
     error instanceof Error ? error.message : String(error);
     reportedResult.gitVersion.result = "Error: " + reportedResult.gitVersion.output;
     reportedResult.latestError = error;
   }

Note: This would require importing Logger from "../logger/logger".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/support/gitVersion.ts` around lines 44 - 49, The catch block currently
sets reportedResult.gitVersion.output/result and reportedResult.latestError but
doesn't log the error; import Logger from "../logger/logger" and call
Logger.error with a clear message, the caught error, and a scope identifier
(e.g., "gitVersion:getGitVersion" or similar) inside the catch so that errors
for reportedResult.gitVersion and reportedResult.latestError are recorded via
Logger.error(errorMessage, error, "scope").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/eim/loadIdfSetup.ts`:
- Around line 46-57: loadIdfSetup can return undefined (early returns and failed
find), but callers assume a non-null value and access properties directly;
update loadIdfSetup (symbols: loadIdfSetup, idfSetupToUse, idfSetups,
idfConfigurationName) to guarantee a valid return or fail fast: after computing
idfSetupToUse, if it's undefined pick a safe default (e.g., idfSetups[0]) or
throw a descriptive Error; alternatively, keep the current nullable return but
update all callers that dereference its result to check for undefined and handle
cancellation/invalid-setup cases before accessing properties. Ensure the find()
result is explicitly handled so callers at extension call sites never
dereference an undefined value.

In `@src/extension.ts`:
- Around line 2345-2349: After filtering idfSetups into existingIdfSetups (in
the block that calls pathExists), add a guard that checks if existingIdfSetups
is empty and handle it before calling getNewProjectArgs or opening the wizard:
either show a user-facing message (e.g., via showInformationMessage or
showErrorMessage) explaining no valid frameworks were found, or fall back to
idfSetups/unfiltered options if that makes sense. Update both occurrences (the
block creating existingIdfSetups and the similar block around lines 2355-2358)
to avoid calling getNewProjectArgs with an empty list and to return/abort the
flow cleanly when no valid setups exist.

---

Outside diff comments:
In `@src/idfToolsManager.ts`:
- Around line 26-34: The mapper is casting package objects to IEspIdfTool but
omits path and leaves env with unresolved placeholders, causing a contract break
with IEspIdfTool and idfToolResult; either populate path and resolve env by
calling exportVarsForPkg() inside the mapper so each returned object includes
path: string and a resolved env, or change the types (IEspIdfTool and
idfToolResult) to match the actual returned shape and remove the unsafe cast;
update references such as reportedResult.espIdfToolsVersions and verifySetup.ts
to use the corrected shape.

In `@src/utils.ts`:
- Around line 1079-1083: The current check inside the PATH scan returns "" as
soon as a found binaryPath does not include the resultContainerPath
(containerDir.join(path.sep)), which aborts further PATH entries and can miss a
later valid container-managed binary; change the logic so that when
binaryPath.indexOf(resultContainerPath) === -1 you skip this candidate and
continue scanning the rest of PATH (e.g., replace the early return with
continuing the loop or otherwise only return "" after the entire PATH has been
exhausted), keeping the use of containerDir, resultContainerPath and binaryPath
to locate valid matches.

---

Nitpick comments:
In `@src/espIdf/serial/serialPort.ts`:
- Around line 335-363: Replace the bare boolean flag skipEsptoolCall on
getListArray and list with a small options object (e.g., { skipEsptoolCall?:
boolean } or more explicit { useEsptool?: boolean }) so callers use named
properties instead of positional booleans; update the signatures of
getListArray(workspaceFolder, options) and list(workspaceFolder, options) and
all call sites that call getListArray(..., true/false) to pass a descriptive
object (e.g., getListArray(workspace, { skipEsptoolCall: true })) and adjust any
internal uses of skipEsptoolCall inside list to read options.skipEsptoolCall.

In `@src/support/gitVersion.ts`:
- Around line 44-49: The catch block currently sets
reportedResult.gitVersion.output/result and reportedResult.latestError but
doesn't log the error; import Logger from "../logger/logger" and call
Logger.error with a clear message, the caught error, and a scope identifier
(e.g., "gitVersion:getGitVersion" or similar) inside the catch so that errors
for reportedResult.gitVersion and reportedResult.latestError are recorded via
Logger.error(errorMessage, error, "scope").

In `@src/views/nvs-partition-table/App.vue`:
- Line 80: The prop binding :canDeleteRow was changed to use Number(i) but the
v-for index i is already a number; revert the expression to the original i !== 0
to remove the unnecessary type conversion. Update the template where
:canDeleteRow is set (the binding using the loop variable i) to use i !== 0 so
the UI logic remains unchanged and unrelated PR scope stays focused.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87277780-922f-4a3d-a70a-acad43478098

📥 Commits

Reviewing files that changed from the base of the PR and between 9e54012 and 138366f.

📒 Files selected for processing (16)
  • src/eim/loadIdfSetup.ts
  • src/eim/loadSettings.ts
  • src/eim/verifySetup.ts
  • src/espIdf/serial/serialPort.ts
  • src/extension.ts
  • src/flash/eraseFlashTask.ts
  • src/flash/flashTask.ts
  • src/idfToolsManager.ts
  • src/newProject/newProjectInit.ts
  • src/pythonManager.ts
  • src/support/checkEspIdfRequirements.ts
  • src/support/checkEspIdfTools.ts
  • src/support/configurationAccess.ts
  • src/support/gitVersion.ts
  • src/utils.ts
  • src/views/nvs-partition-table/App.vue
💤 Files with no reviewable changes (2)
  • src/eim/loadSettings.ts
  • src/support/checkEspIdfTools.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
docs_espressif/zh_CN/installation.rst (1)

75-75: Minor: Missing blank line before list item continuation.

In reStructuredText, when continuing content after a code block within a numbered list, a blank line is typically needed for proper rendering.

       }
+
 3. 或者,也可使用 PATH(Windows 下为 Path)列出要追加到 PATH 的工具路径:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs_espressif/zh_CN/installation.rst` at line 75, Add a blank line before
the continuation of the numbered list item that begins with "3. 或者,也可使用
PATH(Windows 下为 Path)列出要追加到 PATH 的工具路径:" so the reStructuredText list renders
correctly after the preceding code block; locate that exact list item text and
insert a single empty line before its content continuation.
src/support/checkIdfSetups.ts (1)

36-40: Use const instead of let for envVars.

The variable is not reassigned after initialization.

-    let envVars: { [key: string]: string } = await getEnvVariables(idfSetup);
+    const envVars: { [key: string]: string } = await getEnvVariables(idfSetup);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/support/checkIdfSetups.ts` around lines 36 - 40, Change the mutable
declaration of envVars to an immutable one: replace the current "let envVars"
with "const envVars" where getEnvVariables(idfSetup) is awaited (in the block
that then calls isIdfSetupValid), since envVars is never reassigned; update the
declaration near the calls to getEnvVariables and isIdfSetupValid and keep the
rest (extendedIdfSetup.isValid / .reason assignment) unchanged.
src/eim/loadIdfSetup.ts (1)

203-214: Redundant isValid check.

The if (isValid) check on line 203 is redundant since the function already returns at line 163 when !isValid. The code inside this block will always execute when this point is reached.

♻️ Suggested simplification
-  if (isValid) {
-    ESP.ProjectConfiguration.store.set(
-      ESP.ProjectConfiguration.CURRENT_IDF_CONFIGURATION,
-      customVars
-    );
-    await writeParameter(
-      "idf.currentSetup",
-      envDefinedIdfSetup.idfPath,
-      ConfigurationTarget.WorkspaceFolder,
-      workspaceFolder
-    );
-    return envDefinedIdfSetup;
-  }
+  ESP.ProjectConfiguration.store.set(
+    ESP.ProjectConfiguration.CURRENT_IDF_CONFIGURATION,
+    customVars
+  );
+  await writeParameter(
+    "idf.currentSetup",
+    envDefinedIdfSetup.idfPath,
+    ConfigurationTarget.WorkspaceFolder,
+    workspaceFolder
+  );
+  return envDefinedIdfSetup;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/eim/loadIdfSetup.ts` around lines 203 - 214, The check "if (isValid)"
around the block that stores CURRENT_IDF_CONFIGURATION, writes
"idf.currentSetup" and returns envDefinedIdfSetup is redundant because the
function already returns when !isValid earlier; remove the surrounding if
(isValid) { ... } and unindent the inner statements so they always execute at
that point, keeping the same calls to ESP.ProjectConfiguration.store.set,
writeParameter("idf.currentSetup", envDefinedIdfSetup.idfPath,
ConfigurationTarget.WorkspaceFolder, workspaceFolder), and the return
envDefinedIdfSetup to preserve behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/eim/loadIdfSetup.ts`:
- Around line 138-149: The current case-insensitive lookup using pathNameInEnv =
Object.keys(process.env).find(k => k.toUpperCase() == "PATH") can yield
undefined or return a differently cased key and then use undefined as an index
into customVars; update the lookup to first attempt to find an exact "PATH" key,
otherwise find a case-insensitive match and if none exists default to the
canonical "PATH" string, then use that resolved key (e.g., pathKey) when reading
process.env and when indexing customVars; apply this change in the block around
pathNameInEnv, customVars and the call to
IdfToolsManager.createIdfToolsManager/exportPathsInString so you never use
undefined as a key.
- Around line 118-122: The code computes idfPath = customVars["IDF_PATH"] ||
process.env.IDF_PATH then calls pathExists(idfPath) without checking for
undefined; add a guard before calling pathExists to handle a missing IDF_PATH
(e.g., if idfPath is falsy, log/return/throw as appropriate) so pathExists is
only invoked with a valid string. Update the block around idfPath in
loadIdfSetup.ts to check idfPath (referencing the idfPath variable and
pathExists function) and exit early or provide a clear error when IDF_PATH is
undefined.

---

Nitpick comments:
In `@docs_espressif/zh_CN/installation.rst`:
- Line 75: Add a blank line before the continuation of the numbered list item
that begins with "3. 或者,也可使用 PATH(Windows 下为 Path)列出要追加到 PATH 的工具路径:" so the
reStructuredText list renders correctly after the preceding code block; locate
that exact list item text and insert a single empty line before its content
continuation.

In `@src/eim/loadIdfSetup.ts`:
- Around line 203-214: The check "if (isValid)" around the block that stores
CURRENT_IDF_CONFIGURATION, writes "idf.currentSetup" and returns
envDefinedIdfSetup is redundant because the function already returns when
!isValid earlier; remove the surrounding if (isValid) { ... } and unindent the
inner statements so they always execute at that point, keeping the same calls to
ESP.ProjectConfiguration.store.set, writeParameter("idf.currentSetup",
envDefinedIdfSetup.idfPath, ConfigurationTarget.WorkspaceFolder,
workspaceFolder), and the return envDefinedIdfSetup to preserve behavior.

In `@src/support/checkIdfSetups.ts`:
- Around line 36-40: Change the mutable declaration of envVars to an immutable
one: replace the current "let envVars" with "const envVars" where
getEnvVariables(idfSetup) is awaited (in the block that then calls
isIdfSetupValid), since envVars is never reassigned; update the declaration near
the calls to getEnvVariables and isIdfSetupValid and keep the rest
(extendedIdfSetup.isValid / .reason assignment) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dcd7bb2b-3c7c-46d6-afc3-9aab47fb838e

📥 Commits

Reviewing files that changed from the base of the PR and between 138366f and e58c58a.

📒 Files selected for processing (9)
  • docs_espressif/en/installation.rst
  • docs_espressif/zh_CN/installation.rst
  • src/PyReqLog.ts
  • src/eim/loadIdfSetup.ts
  • src/eim/migrationTool.ts
  • src/eim/verifySetup.ts
  • src/packageWebError.ts
  • src/pythonManager.ts
  • src/support/checkIdfSetups.ts
💤 Files with no reviewable changes (2)
  • src/PyReqLog.ts
  • src/packageWebError.ts
✅ Files skipped from review due to trivial changes (1)
  • docs_espressif/en/installation.rst
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/eim/verifySetup.ts
  • src/pythonManager.ts

Copilot AI review requested due to automatic review settings March 23, 2026 10:11
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/support/checkEspIdfRequirements.ts (1)

54-60: LGTM - Robust error handling with proper type narrowing.

The instanceof Error check correctly extracts the message, with a String(error) fallback for non-Error values. The "Error: " prefix in the result provides better context in diagnostics.

Consider adding a Logger.error call for additional visibility during debugging, per coding guidelines:

Logger.error(reportedResult.idfCheckRequirements.output, error, "checkEspIdfRequirements");

This is optional since the error is already captured in reportedResult.latestError for the diagnostic report.
,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/support/checkEspIdfRequirements.ts` around lines 54 - 60, Add a
Logger.error call inside the catch block of the checkEspIdfRequirements function
to log the extracted error message and the original error for visibility: after
setting reportedResult.idfCheckRequirements.output and
reportedResult.latestError, call Logger.error with the output message, the
caught error object, and the string "checkEspIdfRequirements" so logs include
context; reference the reportedResult.idfCheckRequirements,
reportedResult.latestError, and the catch error variable when adding the call.
src/extension.ts (1)

2345-2356: Good fix for the empty setups issue; minor improvements possible.

The validation and early-return guard address the prior concern about the wizard receiving an empty list. A couple of refinements:

  1. The !existingIdfSetups check is redundant since Promise.all(...).then(...) always returns an array.
  2. Consider using Logger.warnNotify for consistency with similar warnings elsewhere, and provide a more descriptive message explaining the paths were invalid.
💡 Suggested refinement
           let existingIdfSetups = await Promise.all(
             idfSetups.map(async (setup) => {
               return (await pathExists(setup.idfPath)) ? setup : null;
             })
           ).then((results) => results.filter((setup) => setup !== null));

-          if (!existingIdfSetups || existingIdfSetups.length === 0) {
-            vscode.window.showInformationMessage(
-              vscode.l10n.t("No ESP-IDF Setups found")
+          if (existingIdfSetups.length === 0) {
+            Logger.warnNotify(
+              vscode.l10n.t(
+                "No valid ESP-IDF setups were found. Check the configured ESP-IDF paths and try again."
+              )
             );
             return;
           }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/extension.ts` around lines 2345 - 2356, The check for !existingIdfSetups
is redundant because existingIdfSetups (result of Promise.all(...).then(...)) is
always an array; remove that nullity check and only test length, and replace the
vscode.window.showInformationMessage call with the project's standard
Logger.warnNotify to keep messaging consistent (use a more descriptive message
like "No valid ESP-IDF setups found; all configured paths are invalid" when
existingIdfSetups.length === 0). Locate the logic around idfSetups, pathExists,
and existingIdfSetups in the extension activation flow and update the
early-return branch to use Logger.warnNotify instead of
vscode.window.showInformationMessage and drop the redundant null check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/extension.ts`:
- Around line 2345-2356: The check for !existingIdfSetups is redundant because
existingIdfSetups (result of Promise.all(...).then(...)) is always an array;
remove that nullity check and only test length, and replace the
vscode.window.showInformationMessage call with the project's standard
Logger.warnNotify to keep messaging consistent (use a more descriptive message
like "No valid ESP-IDF setups found; all configured paths are invalid" when
existingIdfSetups.length === 0). Locate the logic around idfSetups, pathExists,
and existingIdfSetups in the extension activation flow and update the
early-return branch to use Logger.warnNotify instead of
vscode.window.showInformationMessage and drop the redundant null check.

In `@src/support/checkEspIdfRequirements.ts`:
- Around line 54-60: Add a Logger.error call inside the catch block of the
checkEspIdfRequirements function to log the extracted error message and the
original error for visibility: after setting
reportedResult.idfCheckRequirements.output and reportedResult.latestError, call
Logger.error with the output message, the caught error object, and the string
"checkEspIdfRequirements" so logs include context; reference the
reportedResult.idfCheckRequirements, reportedResult.latestError, and the catch
error variable when adding the call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 035019ee-d5e3-490a-819b-f99b6be5c168

📥 Commits

Reviewing files that changed from the base of the PR and between e58c58a and 1d494e4.

📒 Files selected for processing (8)
  • docs_espressif/zh_CN/installation.rst
  • src/eim/loadIdfSetup.ts
  • src/eim/verifySetup.ts
  • src/extension.ts
  • src/idfToolsManager.ts
  • src/support/checkEspIdfRequirements.ts
  • src/support/gitVersion.ts
  • src/test/doctor.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/test/doctor.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/support/gitVersion.ts
  • src/eim/verifySetup.ts
  • docs_espressif/zh_CN/installation.rst
  • src/eim/loadIdfSetup.ts

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Collaborator

@radurentea radurentea left a comment

Choose a reason for hiding this comment

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

LGTM

@AndriiFilippov
Copy link
Copy Markdown
Collaborator

@brianignacio5 hi !

Tested under:
OS: Mac arm64
ESP-IDF: v5.2.1

I was able to verify that an external manual ESP-IDF v5.2.1 setup works in an existing workspace when configured explicitly.

However, ESP-IDF: New Project still fails with that external setup.

Observed behavior:

  • In the newly created workspace, Doctor shows empty effective values for:

    • IDF_PATH
    • IDF_TOOLS_PATH
    • Python path
  • Doctor ends with errors showing empty arguments being used:

    • IDF_PATH
    • IDF_TOOLS_PATH
    • PYTHON_BIN_PATH
  • Additionally, serial port display still attempts to stat esptool.py from a stale v5.5.4 setup path:

    • ~/.espressif/v5.5.4/esp-idf/components/esptool_py/esptool/esptool.py

settings.json:

{
  "C_Cpp.intelliSenseEngine": "default",
  "idf.extensionActivationMode": "always",
  "idf.openOcdConfigs": [
    "board/esp32-wrover-kit-3.3v.cfg"
  ],
  "idf.port": "detect",
  "idf.currentSetup": "/Users/andriifilippov/Documents/TempIDF/esp-idf-v5.2.1",
  "idf.customExtraVars": {
    "IDF_TARGET": "esp32"
  }
}

and does not contain:

"idf.espIdfPath"
"idf.toolsPath"
"idf.pythonBinPath"

So the wizard did persist the selected setup partially, but not enough for external/manual setup to be usable in the new workspace.
Since there is no data about external/manual IDF recorded in eim_idf.json , it seems that relying on idf.currentSetup may not be sufficient for external IDF setups.

Doctor Command output file:
Doc.txt

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/espIdf/serial/serialPort.ts (2)

455-464: Redundant existence checks; prefer a single stat call.

pathExists followed by vscode.workspace.fs.stat performs two filesystem round-trips. A single stat call suffices—catch FileNotFound errors and check stat.type.

Also, minor grammar fix: "does not exists" → "does not exist".

Proposed simplification
-          const esptoolPathExists = await pathExists(esptoolPath);
-          if (!esptoolPathExists) {
-            throw new Error(`esptool.py does not exists in ${esptoolPath}`);
-          }
-          const stat = await vscode.workspace.fs.stat(
-            vscode.Uri.file(esptoolPath)
-          );
-          if (stat.type !== vscode.FileType.File) {
-            // esptool.py does not exists
-            throw new Error(`esptool.py in ${esptoolPath} is not a file`);
-          }
+          let stat: vscode.FileStat;
+          try {
+            stat = await vscode.workspace.fs.stat(vscode.Uri.file(esptoolPath));
+          } catch {
+            throw new Error(`esptool.py does not exist at ${esptoolPath}`);
+          }
+          if (stat.type !== vscode.FileType.File) {
+            throw new Error(`esptool.py at ${esptoolPath} is not a file`);
+          }

This also removes the need for the fs-extra import at line 32 if pathExists is no longer used elsewhere in this file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/espIdf/serial/serialPort.ts` around lines 455 - 464, Remove the redundant
pathExists call and replace it with a single vscode.workspace.fs.stat wrapped in
try/catch: call vscode.workspace.fs.stat(vscode.Uri.file(esptoolPath)), catch
the file-not-found error and throw a new Error with corrected grammar
("esptool.py does not exist in ${esptoolPath}"), then verify stat.type ===
vscode.FileType.File and if not throw "esptool.py in ${esptoolPath} is not a
file"; remove the now-unused pathExists/esptoolPathExists variable and drop the
fs-extra import if it is no longer used elsewhere in this file.

383-387: Move Python/IDF_PATH retrieval after the skipEsptoolCall guard.

getVirtualEnvPythonPath() and the IDF_PATH lookup execute even when skipEsptoolCall is true. Per the PR objectives, the New Project Wizard uses skipEsptoolCall=true precisely because IDF may not be fully configured yet—calling these functions can fail or produce misleading errors.

Consider deferring them inside the else block at line 447.

Suggested refactor
-        const pythonBinPath = await getVirtualEnvPythonPath();
-        const currentEnvVars = ESP.ProjectConfiguration.store.get<{
-          [key: string]: string;
-        }>(ESP.ProjectConfiguration.CURRENT_IDF_CONFIGURATION, {});
-        const idfPath = currentEnvVars["IDF_PATH"];
         const enableSerialPortChipIdRequest = idfConf.readParameter(
           "idf.enableSerialPortChipIdRequest",
           workspaceFolder
         ) as boolean;
         ...
         if (!enableSerialPortChipIdRequest) {
           return resolve(choices);
         }
-        async function processPorts(serialPort: SerialPortDetails, esptoolPath: string) {
+
+        if (skipEsptoolCall) {
+          resolve(choices);
+        } else {
+          const pythonBinPath = await getVirtualEnvPythonPath();
+          const currentEnvVars = ESP.ProjectConfiguration.store.get<{
+            [key: string]: string;
+          }>(ESP.ProjectConfiguration.CURRENT_IDF_CONFIGURATION, {});
+          const idfPath = currentEnvVars["IDF_PATH"];
+
+          async function processPorts(serialPort: SerialPortDetails, esptoolPath: string) {
             ...
           }
+          const esptoolPath = join(
+            idfPath,
             ...
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/espIdf/serial/serialPort.ts` around lines 383 - 387, The retrieval of the
virtualenv Python binary and IDF_PATH happens before the skipEsptoolCall guard;
move the calls to getVirtualEnvPythonPath() and the
ESP.ProjectConfiguration.store.get<CURRENT_IDF_CONFIGURATION>() lookup that sets
idfPath into the branch that runs when skipEsptoolCall is false (i.e., inside
the else branch that performs esptool actions) so these functions are only
invoked when esptool is actually called; update any variables (pythonBinPath,
idfPath) to be declared/initialized there and remove their pre-guard usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/newProject/utils.ts`:
- Around line 54-70: The code assigns properties on
settingsJson["idf.customExtraVars"] without ensuring it exists; before setting
IDF_PATH/IDF_TOOLS_PATH/IDF_PYTHON_ENV_PATH when customExtraVars is truthy,
initialize settingsJson["idf.customExtraVars"] =
settingsJson["idf.customExtraVars"] || {} (or equivalent) so subsequent
assignments in the block (references: settingsJson, customExtraVars, idfSetup)
do not attempt to write properties on undefined.

---

Nitpick comments:
In `@src/espIdf/serial/serialPort.ts`:
- Around line 455-464: Remove the redundant pathExists call and replace it with
a single vscode.workspace.fs.stat wrapped in try/catch: call
vscode.workspace.fs.stat(vscode.Uri.file(esptoolPath)), catch the file-not-found
error and throw a new Error with corrected grammar ("esptool.py does not exist
in ${esptoolPath}"), then verify stat.type === vscode.FileType.File and if not
throw "esptool.py in ${esptoolPath} is not a file"; remove the now-unused
pathExists/esptoolPathExists variable and drop the fs-extra import if it is no
longer used elsewhere in this file.
- Around line 383-387: The retrieval of the virtualenv Python binary and
IDF_PATH happens before the skipEsptoolCall guard; move the calls to
getVirtualEnvPythonPath() and the
ESP.ProjectConfiguration.store.get<CURRENT_IDF_CONFIGURATION>() lookup that sets
idfPath into the branch that runs when skipEsptoolCall is false (i.e., inside
the else branch that performs esptool actions) so these functions are only
invoked when esptool is actually called; update any variables (pythonBinPath,
idfPath) to be declared/initialized there and remove their pre-guard usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6ed441e-d90f-4539-be9f-83b0a34ed9cf

📥 Commits

Reviewing files that changed from the base of the PR and between 1d494e4 and 34eb18a.

📒 Files selected for processing (2)
  • src/espIdf/serial/serialPort.ts
  • src/newProject/utils.ts

Copilot AI review requested due to automatic review settings April 1, 2026 08:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

src/eim/verifySetup.ts:76

  • failedToolsResult will always be empty here because toolsInfo only contains cmake and ninja (passed to getRequiredToolsInfo), but the filter explicitly excludes those names. This makes isIdfSetupValid incorrectly succeed even when cmake/ninja are missing. Remove the name exclusion or broaden the package list so the filter logic matches the intended validation.
    const failedToolsResult = toolsInfo.filter(
      (tInfo) =>
        !tInfo.doesToolExist && ["cmake", "ninja"].indexOf(tInfo.name) === -1
    );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings April 2, 2026 03:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

src/eim/verifySetup.ts:81

  • The missing-tools filter excludes cmake and ninja (["cmake", "ninja"].indexOf(tInfo.name) === -1). Since getRequiredToolsInfo is called with only ["cmake", "ninja"], this makes failedToolsResult always empty and allows setups to be treated as valid even when those tools are missing. The filter condition should include (not exclude) the required tools.
    let toolsInfo: IEspIdfTool[] = await idfToolsManager.getRequiredToolsInfo(
      envVars[pathNameInEnv],
      ["cmake", "ninja"],
      logToChannel
    );

    const failedToolsResult = toolsInfo.filter(
      (tInfo) =>
        !tInfo.doesToolExist && ["cmake", "ninja"].indexOf(tInfo.name) === -1
    );

    if (failedToolsResult.length) {
      const missingTools = failedToolsResult.map((t) => t.name).join(", ");
      return [false, `Missing required tools: ${missingTools}`];
    }

src/utils.ts:1072

  • isBinInPath uses Object.keys(process.env) to pick a PATH key and then assumes env[pathNameInEnv] exists. If pathNameInEnv is undefined (no PATH in process.env) or if the caller’s env uses a different casing (e.g. PATH vs Path), env[pathNameInEnv].split(...) will throw. Prefer resolving the PATH key from the provided env (case-insensitive) and falling back to "PATH" when not found.
  let pathNameInEnv: string = Object.keys(process.env).find(
    (k) => k.toUpperCase() == "PATH"
  );
  const pathDirs = env[pathNameInEnv].split(path.delimiter);
  for (const pathDir of pathDirs) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AndriiFilippov
Copy link
Copy Markdown
Collaborator

AndriiFilippov commented Apr 2, 2026

@brianignacio5 hi !

the error message is improved ✅
Screenshot 2026-04-02 at 12 56 21

@AndriiFilippov
Copy link
Copy Markdown
Collaborator

AndriiFilippov commented Apr 2, 2026

@brianignacio5

issue for both Mac arm64 / Windows 11

the new issue appears after latest changes:
after updating settings.json to use external IDF and restart VS Code, got error:
ESP-IDF Setup from environment variables is not valid: Git not found in PATH

I did add Git explicitly to my "idf.customExtraPaths": , restarted VS Code and got same error. So, I built project anyway.
Please, take a look on the output:
Build_output.txt
IDF source comes from my manual external setup:
/Users/andriifilippov/Documents/TempIDF/esp-idf-v5.2.1
but toolchain/CMake come from a different, newer setup under:
~/.espressif/tools/...
And ESP-IDF 5.2.1 rejects that newer toolchain.
From build logs:
Found assembler: /Users/andriifilippov/.espressif/tools/xtensa-esp-elf/esp-14.2.0_20260121/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc

but my external IDF is:
/Users/andriifilippov/Documents/TempIDF/esp-idf-v5.2.1
and then IDF 5.2.1 complains:
Tool doesn't match supported version from list ['esp-13.2.0_20230928']
I have feeling it takes some paths from custom v5.2.1 and some from currentIDF: v5.5.4 and mix it together.

Doctor comman
Doc.txt

even minimal settings.json didn't pass:

{
  "idf.extensionActivationMode": "always",
  "idf.espIdfPath": "/Users/andriifilippov/Documents/TempIDF/esp-idf-v5.2.1",
  "idf.toolsPath": "/Users/andriifilippov/.espressif",
  "idf.pythonBinPath": "/Users/andriifilippov/.espressif/python_env/idf5.2_py3.14_env/bin/python3",
  "idf.customExtraVars": {
    "IDF_TARGET": "esp32",
    "IDF_PATH": "/Users/andriifilippov/Documents/TempIDF/esp-idf-v5.2.1",
    "IDF_TOOLS_PATH": "/Users/andriifilippov/.espressif",
    "IDF_PYTHON_ENV_PATH": "/Users/andriifilippov/.espressif/python_env/idf5.2_py3.14_env"
  }
}

Copilot AI review requested due to automatic review settings April 3, 2026 06:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

src/utils.ts:1072

  • isBinInPath derives the PATH key name from process.env instead of the provided env object, and then immediately does env[pathNameInEnv].split(...). If the passed env uses a different PATH key casing (or is a partial env without that key), this will throw at runtime. Prefer detecting the PATH key from Object.keys(env) (with a default of "PATH") and guard when the PATH value is missing.
  let pathNameInEnv: string = Object.keys(process.env).find(
    (k) => k.toUpperCase() == "PATH"
  );
  const pathDirs = env[pathNameInEnv].split(path.delimiter);
  for (const pathDir of pathDirs) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 79 to 86
@@ -98,6 +85,15 @@ export async function isIdfSetupValid(
const missingTools = failedToolsResult.map((t) => t.name).join(", ");
return [false, `Missing required tools: ${missingTools}`];
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

failedToolsResult currently filters out the requested tools (cmake, ninja) due to indexOf(tInfo.name) === -1, which means missing cmake/ninja will never be reported and the setup can be marked valid even when these tools are absent. Adjust the filter to include the requested tool names (or remove the name check entirely) so missing required tools are correctly detected.

Copilot uses AI. Check for mistakes.
"idf.currentSetup",
workspaceFolder
) as string;
const doesIdfSetupToUseExist = await pathExists(idfConfigurationName);
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

idfConfigurationName is read from settings and then passed directly to pathExists(...). If the setting is unset, readParameter(...) can yield undefined/empty, which can throw or produce misleading results. Guard for a falsy value before calling pathExists (and only attempt to match idfSetups when it’s a non-empty path).

Suggested change
const doesIdfSetupToUseExist = await pathExists(idfConfigurationName);
let doesIdfSetupToUseExist = false;
if (idfConfigurationName) {
doesIdfSetupToUseExist = await pathExists(idfConfigurationName);
}

Copilot uses AI. Check for mistakes.
Comment on lines 45 to 53
const idfToolsManager = new IdfToolsManager(
toolsJson,
platformInfo,
OutputChannel.init(),
reportedResult.configurationSettings.espIdfPath
);
const verifiedPkgs = await idfToolsManager.getRequiredToolsInfo(
reportedResult.configurationSettings.toolsPath,
reportedResult.configurationSettings.customExtraPaths
);
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

getRequiredToolsInfo(...) now expects a PATH-like string, but reportedResult.configurationSettings.customExtraPaths can be undefined when no CURRENT_IDF_CONFIGURATION is set (see getConfigurationSettings, which assigns it from currentEnvVars["PATH"]). Passing undefined can lead to incorrect PATH mutation (e.g., prefixing with "undefined") and false tool verification failures. Consider falling back to reportedResult.configurationSettings.systemEnvPath (or an empty string) when customExtraPaths is not set.

Copilot uses AI. Check for mistakes.
@@ -111,7 +111,7 @@ suite("Doctor Command tests", () => {
test("Wrong esp-idf py requirements", async () => {
reportObj.configurationSettings.pythonBinPath = "/my/wrong/python/path";
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This test relies on reportObj.configurationSettings.espIdfPath having been set by earlier tests (it isn’t set in this test before calling checkEspIdfRequirements). That makes the assertion order-dependent and harder to maintain. Set espIdfPath explicitly in this test (and/or reset reportObj in setup) so the test is self-contained.

Suggested change
reportObj.configurationSettings.pythonBinPath = "/my/wrong/python/path";
reportObj.configurationSettings.pythonBinPath = "/my/wrong/python/path";
reportObj.configurationSettings.espIdfPath = "/some/non-existing-path";

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +169
if (
pathToPigweed &&
!modifiedEnv[pathNameInEnv].split(delimiter).includes(pathToPigweed)
) {
modifiedEnv[pathNameInEnv] += delimiter + pathToPigweed;
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

At the Pigweed PATH injection, modifiedEnv[pathNameInEnv].split(...) is called without first ensuring the PATH value exists. If PATH is missing/empty in the environment (or was removed by earlier processing), this will throw. Add a guard (e.g., ensure modifiedEnv[pathNameInEnv] is a string before splitting/appending).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants