From 676ebcd34e90a90201f73025a609f846f088ac0f Mon Sep 17 00:00:00 2001 From: mixelpixx Date: Fri, 2 Oct 2026 01:47:45 -0400 Subject: [PATCH] feat!: give Arduino Agent its own app identity Arduino Agent shared every identity value with the official Arduino IDE: productName, appId and Electron userData (`arduino-ide`). Its single-instance lock is keyed on userData, so with both installed, starting one handed the launch to whichever was already running. That included the bridge's auto-launch, which then waited for an MCP server that never came. - productName "Arduino Agent": `Arduino Agent.exe` / `Arduino Agent.app` / `arduino-agent`. - appId io.github.mixelpixx.arduino-agent. It was required before shipping any installer: NSIS/MSI derive their upgrade GUIDs from appId, so an installer built with Arduino's would have removed the official IDE. - Package name arduino-agent (release.yml, scripts/package.js), giving its own userData folder and single-instance lock. On first launch, arduino-ide-electron-main.js copies Local Storage, IndexedDB and config.json from the old folder once, before the lock is taken. ~/.arduinoIDE, Arduino15 and the sketchbook stay shared on purpose. - Own log folder (%APPDATA%\Arduino Agent), MCP server name "arduino-agent", uriScheme arduino-agent, new installer sidebar artwork. - Release assets are named arduino-agent-.zip, with the old arduino-ide-mcp-.zip uploaded alongside so existing links work. - Bridge 0.3.1: an ARDUINO_AGENT_PATH naming the pre-0.7.0 `Arduino IDE` executable falls back to the renamed one, so existing MCP configs keep working. - Docs: download names, executable names, coexistence and upgrade notes. Also fixes BUILDING-WINDOWS.md running rebuild:electron after the production build (it must run before) and its packaging command missing the release metadata. BREAKING CHANGE: the executable, app ID and Electron user-data folder are renamed. The window layout is migrated, and old ARDUINO_AGENT_PATH values keep working through the bridge fallback, but should be updated. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 18 +++++-- CLAUDE.md | 9 ++-- README.md | 37 +++++++------ .../theia/electron-main-application.ts | 6 +-- arduino-mcp-extension/README.md | 2 +- arduino-mcp-extension/bridge/README.md | 10 ++-- .../bridge/arduino-agent-bridge.js | 23 +++++++- arduino-mcp-extension/src/node/mcp-server.ts | 4 +- .../test/bridge/bridge.test.js | 30 +++++++++++ docs/BUILDING-WINDOWS.md | 16 ++++-- docs/development.md | 6 +-- electron-app/arduino-ide-electron-main.js | 51 ++++++++++++++++++ electron-app/package.json | 6 +-- electron-app/resources/installerSidebar.bmp | Bin 207296 -> 155798 bytes electron-app/scripts/package.js | 6 +-- electron-app/scripts/post-package.js | 6 +-- electron-app/scripts/windowsCustomSign.js | 2 +- 17 files changed, 178 insertions(+), 54 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43c14ea5c55..cf5de8cc587 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -164,13 +164,15 @@ jobs: # scripts/package.js, but with Arduino Agent's version: it is the version # in the window title and About dialog, and buildDate is what makes the # app load its bundled VS Code plugins (arduino-ide-electron-main.js). + # The name gives the app its own userData folder (and single-instance + # lock), separate from the official Arduino IDE's `arduino-ide`. shell: bash run: | version=$(node -p "require('../arduino-mcp-extension/package.json').version") cli_version=$(node -p "require('../arduino-ide-extension/package.json').arduino['arduino-cli'].version") node ../node_modules/electron-builder/cli.js --dir --publish never \ -c.electronVersion=30.1.2 \ - -c.extraMetadata.name=arduino-ide \ + -c.extraMetadata.name=arduino-agent \ -c.extraMetadata.main=./arduino-ide-electron-main.js \ -c.extraMetadata.version="$version" \ -c.extraMetadata.theia.frontend.config.appVersion="$version" \ @@ -183,7 +185,9 @@ jobs: run: | $src = Get-ChildItem -Directory electron-app/dist | Where-Object { $_.Name -like '*-unpacked' } | Select-Object -First 1 - Compress-Archive -Path "$($src.FullName)/*" -DestinationPath "arduino-ide-mcp-${{ matrix.platform }}.zip" + Compress-Archive -Path "$($src.FullName)/*" -DestinationPath "arduino-agent-${{ matrix.platform }}.zip" + # Pre-0.7.0 asset name, kept so existing download links keep working. + Copy-Item "arduino-agent-${{ matrix.platform }}.zip" "arduino-ide-mcp-${{ matrix.platform }}.zip" - name: Zip artifact (Linux/macOS) if: runner.os != 'Windows' @@ -193,7 +197,9 @@ jobs: src=$(ls -d electron-app/dist/*-unpacked 2>/dev/null | head -1 || true) if [ -z "$src" ]; then src=$(ls -d electron-app/dist/mac* 2>/dev/null | head -1); fi if [ -z "$src" ]; then echo "No build output found under electron-app/dist"; ls -la electron-app/dist; exit 1; fi - ( cd "$src" && zip -ry "$GITHUB_WORKSPACE/arduino-ide-mcp-${{ matrix.platform }}.zip" . ) + ( cd "$src" && zip -ry "$GITHUB_WORKSPACE/arduino-agent-${{ matrix.platform }}.zip" . ) + # Pre-0.7.0 asset name, kept so existing download links keep working. + cp "arduino-agent-${{ matrix.platform }}.zip" "arduino-ide-mcp-${{ matrix.platform }}.zip" - name: Upload to draft release uses: softprops/action-gh-release@v2 @@ -207,10 +213,12 @@ jobs: Not affiliated with or endorsed by Arduino SA. Each archive contains the unpacked application for its platform - unzip and run - `Arduino IDE` (`Arduino IDE.exe` on Windows). The MCP server starts on + `Arduino Agent` (`Arduino Agent.exe` on Windows). The MCP server starts on `http://127.0.0.1:3847`; the connection config (with the auth token) is printed to the IDE console on launch. Artifacts are unsigned; on macOS you may need to allow the app in System Settings > Privacy & Security. - files: arduino-ide-mcp-${{ matrix.platform }}.zip + files: | + arduino-agent-${{ matrix.platform }}.zip + arduino-ide-mcp-${{ matrix.platform }}.zip diff --git a/CLAUDE.md b/CLAUDE.md index 30db39c3f88..1ccf8131a92 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,8 +30,8 @@ classes are `any` in our extension: no `override`, no inherited fields. ## Fast backend-only iteration (Windows dev box) The MCP extension is bundled into `electron-app/lib/backend/main.js`. To test -a backend change against the installed app at `C:\Arduino` without full -packaging: +a backend change against an installed app (`` below, the unzipped +release folder) without full packaging: 1. `npm run --prefix arduino-mcp-extension build` 2. In `electron-app/`: `node ../node_modules/@theia/cli/bin/theia build @@ -39,8 +39,9 @@ packaging: file — piping through tail/grep has repeatedly swallowed the real error). If it dies with ENOTEMPTY on `lib/backend/native-webpack-plugin`, delete that directory and rerun (transient Windows file-lock race). -3. Kill "Arduino IDE" processes, copy `electron-app/lib/backend/main.js` over - `C:\Arduino\resources\app\lib\backend\main.js`, relaunch. +3. Kill "Arduino Agent" processes ("Arduino IDE" before 0.7.0), copy + `electron-app/lib/backend/main.js` over + `\resources\app\lib\backend\main.js`, relaunch. 4. Confirm the copy landed by grepping the installed main.js for a distinctive new string, and check `/health` uptime is small (a stale uptime means the old process survived the kill). diff --git a/README.md b/README.md index d04893da6eb..a1c878ead55 100644 --- a/README.md +++ b/README.md @@ -39,20 +39,26 @@ making the IDE a first-class participant in the conversation: Unsigned development builds of the **[latest release](https://github.com/mixelpixx/Arduino-Agent/releases/latest)** — these links always point at the newest version: -- [**Windows x64**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-ide-mcp-windows.zip) -- [**macOS**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-ide-mcp-macos.zip) -- [**Linux x64**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-ide-mcp-linux.zip) - -Unzip and run `Arduino IDE` (`Arduino IDE.exe` on Windows). The window, About -box and icon say **Arduino Agent**; only the executable keeps upstream's name for -now. Arduino Agent doesn't check Arduino's update server; get new versions here. -Release notes and older builds are on the -[Releases](https://github.com/mixelpixx/Arduino-Agent/releases) page. - -> **Have the official Arduino IDE installed too?** Both currently share settings -> and a single-instance lock, so starting one while the other is running hands -> off to the one already open. Close one before starting the other. Separating -> them properly is planned for v0.7.0. +- [**Windows x64**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-agent-windows.zip) +- [**macOS**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-agent-macos.zip) +- [**Linux x64**](https://github.com/mixelpixx/Arduino-Agent/releases/latest/download/arduino-agent-linux.zip) + +Unzip and run **Arduino Agent** (`Arduino Agent.exe` on Windows, +`Arduino Agent.app` on macOS, `arduino-agent` on Linux). Arduino Agent doesn't +check Arduino's update server; get new versions here. Release notes and older +builds are on the [Releases](https://github.com/mixelpixx/Arduino-Agent/releases) +page. + +> **Got the official Arduino IDE too?** They run side by side as separate apps. +> They share what should be shared, your sketchbook, installed boards and +> libraries, and preferences (`~/.arduinoIDE`), but each keeps its own window +> state and opens independently. +> +> **Upgrading from 0.6.x?** The executable was called `Arduino IDE` before 0.7.0. +> Your window layout and per-sketch board selections carry over on first launch, +> and an MCP config whose `ARDUINO_AGENT_PATH` still names `Arduino IDE.exe` +> keeps working (the bridge finds the renamed executable), but update it when +> convenient. > These are unsigned dev builds. On macOS you may need to allow the app under > **System Settings → Privacy & Security**; on Windows, dismiss SmartScreen with @@ -100,7 +106,8 @@ Release notes and older builds are on the > > Releases after v0.6.1 ship the bridge inside the app: `` is the > unzipped folder on Windows/Linux; on macOS the path is - > `Arduino IDE.app/Contents/Resources/mcp-bridge/bridge/arduino-agent-bridge.js`. + > `Arduino Agent.app/Contents/Resources/mcp-bridge/bridge/arduino-agent-bridge.js` + > (`Arduino IDE.app` in 0.6.2). > From a source checkout, use `arduino-mcp-extension/bridge/arduino-agent-bridge.js` > after building the extension. It needs no token configuration (it reads > `~/.arduinoIDE/mcp-token` itself) and no dependencies. See diff --git a/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts b/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts index b6d0ff2941c..234ff55d591 100644 --- a/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts +++ b/arduino-ide-extension/src/electron-main/theia/electron-main-application.ts @@ -84,7 +84,7 @@ function enableFileLogger() { process.env['XDG_CONFIG_HOME'] = xdgConfigHome; } setupFileLog({ - appName: 'Arduino IDE', + appName: 'Arduino Agent', // Arduino Agent: own log folder, not the official IDE's maxSize: 10 * 1024 * 1024, }); for (const name of consoleLogFunctionNames) { @@ -893,7 +893,7 @@ async function updateFrontendApplicationConfigFromPackageJson( } const fallbackFrontendAppConfig: FrontendApplicationConfig = { - applicationName: 'Arduino IDE', + applicationName: 'Arduino Agent', // Arduino Agent defaultTheme: { light: 'arduino-theme', dark: 'arduino-theme-dark', @@ -903,7 +903,7 @@ const fallbackFrontendAppConfig: FrontendApplicationConfig = { defaultLocale: '', electron: { showWindowEarly: true, - uriScheme: 'arduino-ide', + uriScheme: 'arduino-agent', // Arduino Agent }, reloadOnReconnect: true, }; diff --git a/arduino-mcp-extension/README.md b/arduino-mcp-extension/README.md index 0c385c23edb..d60fc28ec3d 100644 --- a/arduino-mcp-extension/README.md +++ b/arduino-mcp-extension/README.md @@ -253,7 +253,7 @@ Expected response: ```json { "status": "ok", - "server": "arduino-ide-mcp", + "server": "arduino-agent", "version": "0.5.0", "uptime": 123, "auth": true diff --git a/arduino-mcp-extension/bridge/README.md b/arduino-mcp-extension/bridge/README.md index 1038ced373f..5cf3d8e6b48 100644 --- a/arduino-mcp-extension/bridge/README.md +++ b/arduino-mcp-extension/bridge/README.md @@ -30,7 +30,7 @@ is closed: "arduino": { "command": "node", "args": ["/path/to/mcp-bridge/bridge/arduino-agent-bridge.js"], - "env": { "ARDUINO_AGENT_PATH": "/path/to/Arduino IDE executable" } + "env": { "ARDUINO_AGENT_PATH": "/path/to/Arduino Agent executable" } } } } @@ -41,7 +41,7 @@ Where to find it: | Running from | Bridge path | |--------------|-------------| | Release, Windows / Linux | `/resources/mcp-bridge/bridge/arduino-agent-bridge.js` | -| Release, macOS | `Arduino IDE.app/Contents/Resources/mcp-bridge/bridge/arduino-agent-bridge.js` | +| Release, macOS | `Arduino Agent.app/Contents/Resources/mcp-bridge/bridge/arduino-agent-bridge.js` (`Arduino IDE.app` in 0.6.2) | | Source checkout | `arduino-mcp-extension/bridge/arduino-agent-bridge.js`, after `yarn build` in `arduino-mcp-extension` | Releases after v0.6.1 include the bridge; earlier zips don't, so use a checkout @@ -60,7 +60,7 @@ All optional, set as environment variables: |----------|---------|---------| | `ARDUINO_MCP_URL` | `http://127.0.0.1:3847/mcp` | MCP endpoint to forward to | | `ARDUINO_MCP_TOKEN` | *(reads the token file)* | Override the auth token | -| `ARDUINO_AGENT_PATH` | *(unset — never launches)* | Path to the IDE executable. When set, a tool call that needs the IDE while it is closed starts it, waits for its MCP server and then runs the call. Concurrent calls share one launch; if the IDE never answers, the bridge doesn't start it again until it has been seen running. | +| `ARDUINO_AGENT_PATH` | *(unset — never launches)* | Path to the IDE executable. When set, a tool call that needs the IDE while it is closed starts it, waits for its MCP server and then runs the call. Concurrent calls share one launch; if the IDE never answers, the bridge doesn't start it again until it has been seen running. A path written for a pre-0.7.0 release (`Arduino IDE.exe`, `Arduino IDE.app/...`) that no longer exists falls back to the renamed `Arduino Agent` executable. | | `ARDUINO_MCP_LAUNCH_TIMEOUT` | `120` | Seconds to wait for a started IDE's MCP server | | `ARDUINO_MCP_WATCH_INTERVAL` | `5` | Seconds between checks for the IDE coming up (a local TCP connect) | | `ARDUINO_MCP_DEBUG` | *(off)* | Set to `1` for verbose logging on stderr | @@ -72,8 +72,8 @@ Example on Windows: "mcpServers": { "arduino": { "command": "node", - "args": ["C:/Arduino/resources/mcp-bridge/bridge/arduino-agent-bridge.js"], - "env": { "ARDUINO_AGENT_PATH": "C:/Arduino/Arduino IDE.exe" } + "args": ["C:/Arduino Agent/resources/mcp-bridge/bridge/arduino-agent-bridge.js"], + "env": { "ARDUINO_AGENT_PATH": "C:/Arduino Agent/Arduino Agent.exe" } } } } diff --git a/arduino-mcp-extension/bridge/arduino-agent-bridge.js b/arduino-mcp-extension/bridge/arduino-agent-bridge.js index 03b8220f549..598a521884c 100644 --- a/arduino-mcp-extension/bridge/arduino-agent-bridge.js +++ b/arduino-mcp-extension/bridge/arduino-agent-bridge.js @@ -62,7 +62,7 @@ const path = require('path'); const { spawn } = require('child_process'); const PROTOCOL_VERSION = '2024-11-05'; -const BRIDGE_VERSION = '0.3.0'; +const BRIDGE_VERSION = '0.3.1'; const ENDPOINT = process.env.ARDUINO_MCP_URL || 'http://127.0.0.1:3847/mcp'; const ARDUINO_DIR = path.join(os.homedir(), '.arduinoIDE'); const TOKEN_FILE = path.join(ARDUINO_DIR, 'mcp-token'); @@ -142,6 +142,25 @@ function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } +/** + * ARDUINO_AGENT_PATH, following the 0.7.0 rename of the executable from + * `Arduino IDE` to `Arduino Agent` (`Arduino IDE.exe`, or on macOS + * `Arduino IDE.app/Contents/MacOS/Arduino IDE`). When a path written for an + * older release no longer exists but the renamed one does, use that, so + * existing MCP configs keep working after an upgrade. + */ +function resolveAgentExecutable(exe) { + if (!exe || fs.existsSync(exe) || !exe.includes('Arduino IDE')) return exe; + const candidates = [ + path.join(path.dirname(exe), path.basename(exe).split('Arduino IDE').join('Arduino Agent')), + exe.split('Arduino IDE').join('Arduino Agent'), + ]; + const renamed = candidates.find((p) => fs.existsSync(p)); + if (!renamed) return exe; + warn(`ARDUINO_AGENT_PATH points at ${exe}, which no longer exists; using ${renamed} instead (the executable was renamed in Arduino Agent 0.7.0 - update the setting)`); + return renamed; +} + /** The message shown when a tool needs the IDE and it is not reachable. */ function offlineMessage(detail) { const lines = [ @@ -358,7 +377,7 @@ class Upstream { } async launchAndWaitOnce(onWaiting) { - const exe = process.env.ARDUINO_AGENT_PATH; + const exe = resolveAgentExecutable(process.env.ARDUINO_AGENT_PATH); if (this.launchGaveUp) { return { ok: false, diff --git a/arduino-mcp-extension/src/node/mcp-server.ts b/arduino-mcp-extension/src/node/mcp-server.ts index b72d66c4a90..bd5d444496a 100644 --- a/arduino-mcp-extension/src/node/mcp-server.ts +++ b/arduino-mcp-extension/src/node/mcp-server.ts @@ -666,7 +666,7 @@ export class ArduinoMCPServer { res.end( JSON.stringify({ status: 'ok', - server: 'arduino-ide-mcp', + server: 'arduino-agent', version: EXTENSION_VERSION, uptime: Math.floor((Date.now() - this.startTime) / 1000), auth: this.requireAuth, @@ -802,7 +802,7 @@ export class ArduinoMCPServer { */ private createMCPServerInstance(): Server { const server = new Server( - { name: 'arduino-ide-mcp', version: EXTENSION_VERSION }, + { name: 'arduino-agent', version: EXTENSION_VERSION }, { capabilities: { tools: {}, prompts: {} }, // Workflow guidance delivered to every client at initialize. diff --git a/arduino-mcp-extension/test/bridge/bridge.test.js b/arduino-mcp-extension/test/bridge/bridge.test.js index d93e4d9a24c..939b1c10d99 100644 --- a/arduino-mcp-extension/test/bridge/bridge.test.js +++ b/arduino-mcp-extension/test/bridge/bridge.test.js @@ -278,6 +278,36 @@ test('an IDE that never answers gives a clear error and is not started twice', a } }); +test('an ARDUINO_AGENT_PATH naming the pre-0.7.0 "Arduino IDE" executable finds the renamed one', async () => { + // A renamed node binary stands in for the renamed IDE executable. + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'arduino-bridge-rename-')); + const ext = process.platform === 'win32' ? '.exe' : ''; + const renamed = path.join(dir, `Arduino Agent${ext}`); + try { + fs.linkSync(process.execPath, renamed); + } catch { + fs.copyFileSync(process.execPath, renamed); + } + const port = await freePort(); + const bridge = startBridge(port, { + ARDUINO_AGENT_PATH: path.join(dir, `Arduino IDE${ext}`), + ARDUINO_MCP_LAUNCH_TIMEOUT: '10', + }); + let ide; + try { + await bridge.init(); + const pending = bridge.request('tools/call', { name: 'execute_tool', arguments: { tool_name: 'arduino_context', params: {} } }, 15000); + await new Promise((r) => setTimeout(r, 1000)); + ide = await fakeIde(port, { tools: [] }); + const res = await pending; + assert.strictEqual(res.result.isError, undefined); + assert.strictEqual(textOf(res), 'ran execute_tool'); + } finally { + bridge.close(); + await ide?.close(); + } +}); + test('a wrong ARDUINO_AGENT_PATH is reported, not waited on', async () => { const bridge = startBridge(await freePort(), { ARDUINO_AGENT_PATH: path.join(os.tmpdir(), 'no-such-dir', 'Arduino IDE.exe'), diff --git a/docs/BUILDING-WINDOWS.md b/docs/BUILDING-WINDOWS.md index cd076647078..94221bc1b00 100644 --- a/docs/BUILDING-WINDOWS.md +++ b/docs/BUILDING-WINDOWS.md @@ -63,12 +63,20 @@ To produce an installable app (unpacked, unsigned): ```bash cd electron-app +# Rebuild native modules against Electron's ABI. This must come BEFORE the +# production build, which bundles whatever pty.node is present (see CLAUDE.md). +yarn exec theia rebuild:electron # Production bundle (bundled backend + minified frontend) yarn exec theia build --config webpack.config.js --mode production -# Rebuild native modules against Electron's ABI -yarn exec theia rebuild:electron -# Package to electron-app/dist/win-unpacked -yarn exec electron-builder --dir --publish never +# Package to electron-app/dist/win-unpacked. Use bash (PowerShell mis-tokenizes +# -c.extraMetadata.main). The metadata matches the "Package (unpacked)" step in +# .github/workflows/release.yml; without `name` and `main` the app gets the +# wrong user-data folder and skips its bundled plugins. +node ../node_modules/electron-builder/cli.js --dir --publish never \ + -c.electronVersion=30.1.2 \ + -c.extraMetadata.name=arduino-agent \ + -c.extraMetadata.main=./arduino-ide-electron-main.js \ + -c.extraMetadata.theia.frontend.config.buildDate="$(date -u +%Y-%m-%dT%H:%M:%SZ)" ``` The MCP server starts automatically at `http://127.0.0.1:3847` when the IDE diff --git a/docs/development.md b/docs/development.md index 84cd32c667a..b6870e8912d 100644 --- a/docs/development.md +++ b/docs/development.md @@ -200,6 +200,6 @@ This project is built on [GitHub Actions](https://github.com/arduino/arduino-ide [Get](https://arduino.github.io/arduino-cli/installation) the desired version of `arduino-cli` for your platform and manually replace the one inside the IDE. The CLI can be found inside the IDE at: - - Windows: `C:\path\to\Arduino IDE\resources\app\lib\backend\resources\arduino-cli.exe`, - - macOS: `/path/to/Arduino IDE.app/Contents/Resources/app/lib/backend/resources/arduino-cli`, and - - Linux: `/path/to/Arduino IDE/resources/app/lib/backend/resources/arduino-cli`. + - Windows: `C:\path\to\Arduino Agent\resources\app\lib\backend\resources\arduino-cli.exe`, + - macOS: `/path/to/Arduino Agent.app/Contents/Resources/app/lib/backend/resources/arduino-cli`, and + - Linux: `/path/to/Arduino Agent/resources/app/lib/backend/resources/arduino-cli`. diff --git a/electron-app/arduino-ide-electron-main.js b/electron-app/arduino-ide-electron-main.js index 68f506e84e4..eca93548e3d 100644 --- a/electron-app/arduino-ide-electron-main.js +++ b/electron-app/arduino-ide-electron-main.js @@ -1,9 +1,60 @@ // @ts-check 'use strict'; +const fs = require('fs'); const os = require('os'); const path = require('path'); const config = require('./package.json').theia.frontend.config; + +/** + * Since 0.7.0 Arduino Agent keeps its Electron user data in its own folder + * (`arduino-agent`, from the package name) instead of the official Arduino + * IDE's (`arduino-ide`), so the two no longer share a single-instance lock or + * window state. On first start, carry over what lived in the shared folder: + * the shell layout and per-sketch board selections (Local Storage, IndexedDB) + * and the sketches to reopen (config.json). Settings, the MCP token and the + * sketchbook are in ~/.arduinoIDE and stay shared on purpose. + * + * Must run before the backend module is required: it takes the + * single-instance lock on the userData folder at load time. + */ +function migrateUserDataFromArduinoIde() { + const { app } = require('electron'); + const userData = app.getPath('userData'); + const legacy = path.join(app.getPath('appData'), 'arduino-ide'); + const marker = path.join(userData, '.migrated-from-arduino-ide'); + if ( + path.resolve(userData) === path.resolve(legacy) || + !fs.existsSync(legacy) || + fs.existsSync(marker) + ) { + return; + } + try { + // A folder that already has its own data is never overwritten. + if (!fs.existsSync(path.join(userData, 'Local Storage'))) { + for (const entry of ['Local Storage', 'IndexedDB', 'config.json']) { + const from = path.join(legacy, entry); + if (fs.existsSync(from)) { + fs.cpSync(from, path.join(userData, entry), { + recursive: true, + // LevelDB lock files belong to whichever app has the store open. + filter: (src) => path.basename(src) !== 'LOCK', + }); + } + } + } + fs.mkdirSync(userData, { recursive: true }); + fs.writeFileSync(marker, `${new Date().toISOString()}\n`); + } catch (err) { + console.error(`Could not migrate user data from ${legacy}:`, err); + } +} + +// Only bundled releases (they have `buildDate`) ever used the shared folder. +if (config.buildDate) { + migrateUserDataFromArduinoIde(); +} // `buildDate` is only available in the bundled application. if (config.buildDate) { // `plugins` folder inside IDE2. IDE2 is shipped with these VS Code extensions. Such as cortex-debug, vscode-cpp, and translations. diff --git a/electron-app/package.json b/electron-app/package.json index 856f641ac3a..302e8d00194 100644 --- a/electron-app/package.json +++ b/electron-app/package.json @@ -69,7 +69,7 @@ "validatePreferencesSchema": false, "electron": { "showWindowEarly": true, - "uriScheme": "arduino-ide" + "uriScheme": "arduino-agent" }, "reloadOnReconnect": true, "preferences": { @@ -106,8 +106,8 @@ "author": "mixelpixx", "description": "Arduino Agent: the Arduino IDE with a built-in MCP server", "build": { - "appId": "cc.arduino.IDE2", - "productName": "Arduino IDE", + "appId": "io.github.mixelpixx.arduino-agent", + "productName": "Arduino Agent", "asar": false, "detectUpdateChannel": false, "generateUpdatesFilesForAllChannels": true, diff --git a/electron-app/resources/installerSidebar.bmp b/electron-app/resources/installerSidebar.bmp index 28887c2a15edafc9fc3eb240ce121c50d64d87a0..ef5e2a6a0097e784de440a08a545b6a1587cbb46 100644 GIT binary patch literal 155798 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 fwux}!woQadx9uzAP diff --git a/electron-app/scripts/package.js b/electron-app/scripts/package.js index 9e3593e6443..4e036e4a03d 100644 --- a/electron-app/scripts/package.js +++ b/electron-app/scripts/package.js @@ -27,9 +27,9 @@ async function run() { electronVersion, '-c.extraMetadata.version', version, - // overrides the `name` in the `package.json` to keep the `localStorage` location. (https://github.com/arduino/arduino-ide/pull/2144#pullrequestreview-1554005028) + // Arduino Agent: its own `name`, so its userData (localStorage, single-instance lock) is separate from the official IDE. arduino-ide-electron-main.js migrates the old data once. '-c.extraMetadata.name', - 'arduino-ide', + 'arduino-agent', `-c.${platform}.artifactName`, artifactName, '-c.extraMetadata.theia.frontend.config.appVersion', @@ -102,7 +102,7 @@ async function getVersion() { async function getArtifactName(version) { const { platform, arch } = process; version = isNightly ? `nightly-${await timestamp()}` : version; - const name = 'arduino-ide'; + const name = 'arduino-agent'; switch (platform) { case 'win32': { if (arch === 'x64') { diff --git a/electron-app/scripts/post-package.js b/electron-app/scripts/post-package.js index b346f558f85..fd90a7f33f3 100644 --- a/electron-app/scripts/post-package.js +++ b/electron-app/scripts/post-package.js @@ -131,7 +131,7 @@ async function copyFilesToBuildArtifacts() { case 'linux': { filesToCopy.push( ...glob - .sync('**/arduino-ide*.{zip,AppImage}', { cwd }) + .sync('**/arduino-agent*.{zip,AppImage}', { cwd }) .map((p) => path.join(cwd, p)) ); break; @@ -139,7 +139,7 @@ async function copyFilesToBuildArtifacts() { case 'win32': { filesToCopy.push( ...glob - .sync('**/arduino-ide*.{exe,msi,zip}', { cwd }) + .sync('**/arduino-agent*.{exe,msi,zip}', { cwd }) .map((p) => path.join(cwd, p)) ); break; @@ -147,7 +147,7 @@ async function copyFilesToBuildArtifacts() { case 'darwin': { filesToCopy.push( ...glob - .sync('**/arduino-ide*.{dmg,zip}', { cwd }) + .sync('**/arduino-agent*.{dmg,zip}', { cwd }) .map((p) => path.join(cwd, p)) ); break; diff --git a/electron-app/scripts/windowsCustomSign.js b/electron-app/scripts/windowsCustomSign.js index 5e9585bc246..d7600509b5c 100644 --- a/electron-app/scripts/windowsCustomSign.js +++ b/electron-app/scripts/windowsCustomSign.js @@ -18,7 +18,7 @@ exports.default = async function (configuration) { CONTAINER_NAME ) { childProcess.execSync( - `"${SIGNTOOL_PATH}" sign -d "Arduino IDE" -f "${INSTALLER_CERT_WINDOWS_CER}" -csp "eToken Base Cryptographic Provider" -k "[{{${CERT_PASSWORD}}}]=${CONTAINER_NAME}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "${filePath}"`, + `"${SIGNTOOL_PATH}" sign -d "Arduino Agent" -f "${INSTALLER_CERT_WINDOWS_CER}" -csp "eToken Base Cryptographic Provider" -k "[{{${CERT_PASSWORD}}}]=${CONTAINER_NAME}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v "${filePath}"`, { stdio: 'inherit' } ); } else {