From e851ae61dc05ededd4023b3aaced70c32bcc2fbf Mon Sep 17 00:00:00 2001 From: abose Date: Thu, 5 Mar 2026 15:34:27 +0530 Subject: [PATCH 1/2] fix(ai): crash when sending clipboard-pasted images in AI chat DataTransferItem.type becomes invalid after the paste event handler returns, but the code read it inside an async FileReader.onload callback, resulting in an empty media_type that crashed the Claude Code subprocess (exit code 1). - Capture mediaType from blob.type synchronously before FileReader - Add server-side fallback: infer media type from base64 magic bytes - Add stderr logging for Claude Code subprocess diagnostics --- src-node/claude-code-agent.js | 22 ++++++++++++++++++++-- src/core-ai/AIChatPanel.js | 6 +++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src-node/claude-code-agent.js b/src-node/claude-code-agent.js index 921c286a0c..f779b957ea 100644 --- a/src-node/claude-code-agent.js +++ b/src-node/claude-code-agent.js @@ -318,6 +318,7 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, const queryOptions = { cwd: projectPath || process.cwd(), maxTurns: undefined, + stderr: (data) => console.log("[AI stderr]", data), allowedTools: [ "Read", "Edit", "Write", "Glob", "Grep", "Bash", "AskUserQuestion", "Task", @@ -584,10 +585,27 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, let sdkPrompt = prompt; if (images && images.length > 0) { const contentBlocks = [{ type: "text", text: prompt }]; - images.forEach(function (img) { + images.forEach(function (img, idx) { + // Infer media type from base64 header if missing + let mediaType = img.mediaType; + if (!mediaType && img.base64Data) { + if (img.base64Data.startsWith("iVBOR")) { + mediaType = "image/png"; + } else if (img.base64Data.startsWith("/9j/")) { + mediaType = "image/jpeg"; + } else if (img.base64Data.startsWith("R0lGOD")) { + mediaType = "image/gif"; + } else if (img.base64Data.startsWith("UklGR")) { + mediaType = "image/webp"; + } else { + mediaType = "image/png"; + } + } + _log("Image[" + idx + "]:", "mediaType=" + mediaType, + "base64Len=" + (img.base64Data ? img.base64Data.length : "null")); contentBlocks.push({ type: "image", - source: { type: "base64", media_type: img.mediaType, data: img.base64Data } + source: { type: "base64", media_type: mediaType, data: img.base64Data } }); }); sdkPrompt = (async function* () { diff --git a/src/core-ai/AIChatPanel.js b/src/core-ai/AIChatPanel.js index 1d542c8ad5..e73948ebcc 100644 --- a/src/core-ai/AIChatPanel.js +++ b/src/core-ai/AIChatPanel.js @@ -443,6 +443,10 @@ define(function (require, exports, module) { } imageFound = true; const blob = item.getAsFile(); + // Capture mediaType synchronously — DataTransferItem properties + // become invalid after the paste event handler returns, but + // the File object's type persists across the async boundary. + const mediaType = blob.type || item.type; const reader = new FileReader(); reader.onload = function (ev) { const dataUrl = ev.target.result; @@ -454,7 +458,7 @@ define(function (require, exports, module) { _addImageIfUnique(resized.dataUrl, resized.mediaType, resized.base64Data); }); } else { - _addImageIfUnique(dataUrl, item.type, base64Data); + _addImageIfUnique(dataUrl, mediaType, base64Data); } }; reader.readAsDataURL(blob); From 42553421a452693a69f2c5d9ead983da96bc82a2 Mon Sep 17 00:00:00 2001 From: abose Date: Thu, 5 Mar 2026 15:54:16 +0530 Subject: [PATCH 2/2] fix: docusaurus build break --- docs/API-Reference/view/SidebarTabs.md | 17 +++- docs/API-Reference/widgets/NotificationUI.md | 99 ++++++++++++++++++-- src/view/SidebarTabs.js | 8 +- 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/docs/API-Reference/view/SidebarTabs.md b/docs/API-Reference/view/SidebarTabs.md index 430d35d52a..3503e9e151 100644 --- a/docs/API-Reference/view/SidebarTabs.md +++ b/docs/API-Reference/view/SidebarTabs.md @@ -33,7 +33,7 @@ cached jQuery/DOM references held by extensions remain valid. * [.removeTab(id)](#module_view/SidebarTabs..removeTab) ⇒ boolean * [.setActiveTab(id)](#module_view/SidebarTabs..setActiveTab) * [.getActiveTab()](#module_view/SidebarTabs..getActiveTab) ⇒ string - * [.getAllTabs()](#module_view/SidebarTabs..getAllTabs) ⇒ Array.<{id: string, label: string, iconClass: string, priority: number}> + * [.TabDescriptor](#module_view/SidebarTabs..TabDescriptor) ⇒ Array.<TabDescriptor> @@ -146,9 +146,18 @@ tab, hides all others. Get the currently active tab id. **Kind**: inner method of [view/SidebarTabs](#module_view/SidebarTabs) - + -### view/SidebarTabs.getAllTabs() ⇒ Array.<{id: string, label: string, iconClass: string, priority: number}> +### view/SidebarTabs.TabDescriptor ⇒ Array.<TabDescriptor> Get an array of all registered tab descriptors. -**Kind**: inner method of [view/SidebarTabs](#module_view/SidebarTabs) +**Kind**: inner typedef of [view/SidebarTabs](#module_view/SidebarTabs) +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| id | string | Unique tab identifier | +| label | string | Display text shown in the tab bar | +| iconClass | string | Icon class string | +| priority | number | Sort priority (lower = further left) | + diff --git a/docs/API-Reference/widgets/NotificationUI.md b/docs/API-Reference/widgets/NotificationUI.md index 13bbe3631e..08bed134b0 100644 --- a/docs/API-Reference/widgets/NotificationUI.md +++ b/docs/API-Reference/widgets/NotificationUI.md @@ -6,12 +6,43 @@ const NotificationUI = brackets.getModule("widgets/NotificationUI") ## widgets/NotificationUI -The global NotificationUI can be used to create popup notifications over dom elements or generics app notifications. A global `window.EventManager` object is made available in phoenix that can be called anytime after AppStart. This global can be triggered from anywhere without using require context. ## Usage ### Simple example For Eg. Let's say we have to create a popup notification over the HTML element with ID `showInfileTree`. We can do this with the following +The global NotificationUI can be used to create popup notifications over dom elements or generics app notifications. + +A global `window.EventManager` object is made available in phoenix that can be called anytime after AppStart. +This global can be triggered from anywhere without using require context. + +## Usage +### Simple example +For Eg. Let's say we have to create a popup notification over the HTML element with ID `showInfileTree`. +We can do this with the following **Example** -```js const NotificationUI = brackets.getModule("widgets/NotificationUI"); // or use window.NotificationUI global object has the same effect. let notification = NotificationUI.createFromTemplate("Click me to locate the file in file tree", "showInfileTree",{}); notification.done(()=>{ console.log("notification is closed in ui."); }) ``` ### Advanced example Another advanced example where you can specify html and interactive components in the notification +```js +const NotificationUI = brackets.getModule("widgets/NotificationUI"); +// or use window.NotificationUI global object has the same effect. +let notification = NotificationUI.createFromTemplate("Click me to locate the file in file tree", "showInfileTree",{}); +notification.done(()=>{ + console.log("notification is closed in ui."); +}) +``` +### Advanced example +Another advanced example where you can specify html and interactive components in the notification **Example** -```js // note that you can even provide an HTML Element node with // custom event handlers directly here instead of HTML text. let notification1 = NotificationUI.createFromTemplate( "
Click me to locate the file in file tree
", "showInfileTree",{ allowedPlacements: ['top', 'bottom'], dismissOnClick: false, autoCloseTimeS: 300 // auto close the popup after 5 minutes }); // do stuff notification1.done((closeReason)=>{ console.log("notification is closed in ui reason:", closeReason); }) ``` The `createFromTemplate` API can be configured with numerous options. See API options below. +```js +// note that you can even provide an HTML Element node with +// custom event handlers directly here instead of HTML text. +let notification1 = NotificationUI.createFromTemplate( + "
Click me to locate the file in file tree
", "showInfileTree",{ + allowedPlacements: ['top', 'bottom'], + dismissOnClick: false, + autoCloseTimeS: 300 // auto close the popup after 5 minutes + }); +// do stuff +notification1.done((closeReason)=>{ + console.log("notification is closed in ui reason:", closeReason); +}) +``` +The `createFromTemplate` API can be configured with numerous options. See API options below. * [widgets/NotificationUI](#module_widgets/NotificationUI) * [.API](#module_widgets/NotificationUI..API) @@ -20,6 +51,7 @@ The global NotificationUI can be used to create popup notifications over dom ele * [.createFromTemplate(title, template, [elementID], [options])](#module_widgets/NotificationUI..createFromTemplate) ⇒ Notification * [.createToastFromTemplate(title, template, [options])](#module_widgets/NotificationUI..createToastFromTemplate) ⇒ Notification * [.showToastOn(containerOrSelector, template, [options])](#module_widgets/NotificationUI..showToastOn) ⇒ Notification + * [.showHUD(iconClass, label, [options])](#module_widgets/NotificationUI..showHUD) ⇒ Notification @@ -60,7 +92,21 @@ Closing notification reason. ### widgets/NotificationUI.createFromTemplate(title, template, [elementID], [options]) ⇒ Notification -Creates a new notification popup from given template. The template can either be a string or a jQuery object representing a DOM node that is *not* in the current DOM. Creating a notification popup ```js // note that you can even provide an HTML Element node with // custom event handlers directly here instead of HTML text. let notification1 = NotificationUI.createFromTemplate( "
Click me to locate the file in file tree
", "showInfileTree",{ allowedPlacements: ['top', 'bottom'], dismissOnClick: false, autoCloseTimeS: 300 // auto close the popup after 5 minutes }); ``` +Creates a new notification popup from given template. +The template can either be a string or a jQuery object representing a DOM node that is *not* in the current DOM. + +Creating a notification popup + +```js +// note that you can even provide an HTML Element node with +// custom event handlers directly here instead of HTML text. +let notification1 = NotificationUI.createFromTemplate( + "
Click me to locate the file in file tree
", "showInfileTree",{ + allowedPlacements: ['top', 'bottom'], + dismissOnClick: false, + autoCloseTimeS: 300 // auto close the popup after 5 minutes + }); +``` **Kind**: inner method of [widgets/NotificationUI](#module_widgets/NotificationUI) **Returns**: Notification - Object with a done handler that resolves when the notification closes. @@ -75,7 +121,20 @@ Creates a new notification popup from given template. The template can either be ### widgets/NotificationUI.createToastFromTemplate(title, template, [options]) ⇒ Notification -Creates a new toast notification popup from given title and html message. The message can either be a string or a jQuery object representing a DOM node that is *not* in the current DOM. Creating a toast notification popup ```js // note that you can even provide an HTML Element node with // custom event handlers directly here instead of HTML text. let notification1 = NotificationUI.createToastFromTemplate( "Title here", "
Click me to locate the file in file tree
", { dismissOnClick: false, autoCloseTimeS: 300 // auto close the popup after 5 minutes }); ``` +Creates a new toast notification popup from given title and html message. +The message can either be a string or a jQuery object representing a DOM node that is *not* in the current DOM. + +Creating a toast notification popup + +```js +// note that you can even provide an HTML Element node with +// custom event handlers directly here instead of HTML text. +let notification1 = NotificationUI.createToastFromTemplate( "Title here", + "
Click me to locate the file in file tree
", { + dismissOnClick: false, + autoCloseTimeS: 300 // auto close the popup after 5 minutes + }); +``` **Kind**: inner method of [widgets/NotificationUI](#module_widgets/NotificationUI) **Returns**: Notification - Object with a done handler that resolves when the notification closes. @@ -89,7 +148,15 @@ Creates a new toast notification popup from given title and html message. The me ### widgets/NotificationUI.showToastOn(containerOrSelector, template, [options]) ⇒ Notification -Shows a small, transient inline toast notification inside a given DOM container. The toast is centered at the bottom of the container and auto-dismisses. ```js NotificationUI.showToastOn(document.getElementById("my-panel"), "Hello!", { autoCloseTimeS: 5, dismissOnClick: true }); ``` +Shows a small, transient inline toast notification inside a given DOM container. +The toast is centered at the bottom of the container and auto-dismisses. + +```js +NotificationUI.showToastOn(document.getElementById("my-panel"), "Hello!", { + autoCloseTimeS: 5, + dismissOnClick: true +}); +``` **Kind**: inner method of [widgets/NotificationUI](#module_widgets/NotificationUI) **Returns**: Notification - Object with a done handler that resolves when the toast closes. @@ -100,3 +167,23 @@ Shows a small, transient inline toast notification inside a given DOM container. | template | string \| Element | HTML string or DOM Element for the toast content. | | [options] | Object | optional, supported options: * `autoCloseTimeS` - Time in seconds after which the toast auto-closes. Default is 5. * `dismissOnClick` - If true, clicking the toast dismisses it. Default is true. | + + +### widgets/NotificationUI.showHUD(iconClass, label, [options]) ⇒ Notification +Shows a large, centered HUD overlay (like macOS volume/brightness indicator) with an icon and label. +The HUD fades in/out and auto-dismisses. Only one HUD is shown at a time — calling this while a +previous HUD is visible replaces it instantly. + +```js +NotificationUI.showHUD("fa-solid fa-magnifying-glass-plus", "110%"); +``` + +**Kind**: inner method of [widgets/NotificationUI](#module_widgets/NotificationUI) +**Returns**: Notification - Object with a done handler that resolves when the HUD closes. + +| Param | Type | Description | +| --- | --- | --- | +| iconClass | string | Font Awesome class string for the icon (e.g. "fa-solid fa-magnifying-glass-plus"). | +| label | string | Text to display below the icon (e.g. "110%"). | +| [options] | Object | optional, supported options: * `autoCloseTimeS` - Time in seconds after which the HUD auto-closes. Default is 1. | + diff --git a/src/view/SidebarTabs.js b/src/view/SidebarTabs.js index bd44689e0b..a4fdbcbcac 100644 --- a/src/view/SidebarTabs.js +++ b/src/view/SidebarTabs.js @@ -460,7 +460,13 @@ define(function (require, exports, module) { /** * Get an array of all registered tab descriptors. - * @return {Array.<{id: string, label: string, iconClass: string, priority: number}>} + * @typedef {Object} TabDescriptor + * @property {string} id - Unique tab identifier + * @property {string} label - Display text shown in the tab bar + * @property {string} iconClass - Icon class string + * @property {number} priority - Sort priority (lower = further left) + * + * @return {Array} */ function getAllTabs() { return _tabs.map(function (tab) {