From f8c258d1c6a9164baa16db80e7871b089a6d5dc7 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 16 May 2026 11:58:38 +0530 Subject: [PATCH 1/3] feat(ai): execJsInEditor + editorPreferences + editorDocs + system prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three new MCP tools that broaden the AI's reach over the editor beyond the fixed controlEditor operations. Companion to phoenix-pro's browser handlers. mcp-editor-tools.js: - execJsInEditor: caller-supplied JS evaluated in Phoenix's own JS space (parent window — distinct from execJsInLivePreview which targets the iframe). Same shape as execJsInLivePreview (code + optional timeoutMs, floored at 5000, default 10000, no upper limit). Description lists the __PR helpers and points the model at editorDocs before writing non-trivial JS, plus a hint to use takeScreenshot (with arbitrary CSS selector) to verify mutations visually. - editorPreferences: list / get / set with explicit scope. Description teaches user-friendly scope names ("system-wide" / "for this project" / "just for this session") and tells the model to PICK a sensible scope per pref nature instead of reflexively offering all three. No platform-specific paths in the description — purely API-level. - editorDocs: returns absolute apiDocsPath (the build-mirrored API reference) + apiDocsURL + featureDocsURL + sourceRepoURL. Tool DOES NOT fetch content — it's just a "where to look" index so the model Read / Greps the bundled docs and WebFetches the live ones. - takeScreenshot description rewritten with a clean binary selector rule (live preview vs everything else) plus an arbitrary-CSS- selector option for verifying execJsInEditor mutations. - getEditorState response now appends a fallback hint pointing the model at takeScreenshot for any UI question the JSON doesn't answer (Problems panel, sidebar, etc.). claude-code-agent.js (system prompt + tool registration): - allowedTools + agents.researcher / agents.coder gain the three new mcp__phoenix-editor__ tool names. - New "live preview is" definition line so the model has a mental model of what the preview shows. - Broadened getEditorState trigger: ALWAYS call it first on any question that references the user's current work — not just "what file am I on" but also implicit-context phrasings like "the page", "this layout", "the nav bar", "scroll down on the page". Stops the model from blind whole-codebase grep when context is one tool call away. - Phoenix-vs-Claude-Code name-collision rule: when the user says "set / configure / change X" without naming a product, default to editorPreferences. Don't touch ~/.claude/, ~/.claude.json, or the built-in update-config skill unless the user explicitly mentions "Claude" / "Claude Code" / "SDK" / "agent". Skip and ask if genuinely ambiguous. - Per-tool entries for execJsInEditor, editorPreferences, editorDocs added to the tool list. build/api-docs-generator.js + .gitignore: - copyApiDocsToSrcNode() mirrors docs/API-Reference/ → src-node/apiDocs/ in a finally block so a partial generation (e.g. one source file's jsdoc errored mid-batch) still ships whatever made it. Cross-platform via fs.cp + path.join. - /src-node/apiDocs added to root .gitignore. strings.js: AI_CHAT_TOOL_EDITOR_JS ("Inspecting editor"), AI_CHAT_TOOL_EDITOR_PREFERENCES ("Editor preferences"), AI_CHAT_TOOL_EDITOR_DOCS ("Editor docs"). --- .gitignore | 5 + build/api-docs-generator.js | 29 +++++ src-node/claude-code-agent.js | 51 ++++++++- src-node/mcp-editor-tools.js | 210 +++++++++++++++++++++++++++++++++- src/nls/root/strings.js | 3 + 5 files changed, 291 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index e7cd8fdf27..16bd98b45a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,11 @@ Thumbs.db /src-node/node_modules /src-mdviewer/node_modules +# ignore API docs mirror copied from docs/API-Reference/ at build time +# (shipped as a bundled resource for the editorDocs MCP tool, not +# checked in) +/src-node/apiDocs + # ignore mdViewer build output /src/mdViewer /src/JSUtils/node_modules diff --git a/build/api-docs-generator.js b/build/api-docs-generator.js index bac0e639cb..126c9ccbd1 100644 --- a/build/api-docs-generator.js +++ b/build/api-docs-generator.js @@ -11,6 +11,10 @@ const globPromise = util.promisify(glob); // Constants const SRC_DIR = './src'; const MD_FILES_DIR = path.join('./docs', 'API-Reference'); +// Mirror the API reference into the src-node sidecar so the runtime +// MCP `editorDocs.api` tool can read version-matched docs from disk +// without going to the website. Git-ignored — see root .gitignore. +const SRC_NODE_API_DOCS_DIR = path.join('./src-node', 'apiDocs'); const BATCH_SIZE = 12; @@ -234,6 +238,25 @@ async function generateMarkdown(file, relativePath) { } +/** + * Mirror the freshly-generated API reference into src-node/apiDocs so + * the Node sidecar can ship it as a bundled resource for the AI's + * `editorDocs.api` MCP tool. Replaces any prior contents so we don't + * accumulate stale files when modules are removed. + */ +async function copyApiDocsToSrcNode() { + try { + await fs.rm(SRC_NODE_API_DOCS_DIR, { recursive: true, force: true }); + await fs.cp(MD_FILES_DIR, SRC_NODE_API_DOCS_DIR, { recursive: true }); + console.log(`Copied ${MD_FILES_DIR} -> ${SRC_NODE_API_DOCS_DIR}`); + } catch (error) { + // Don't fail the whole build for a copy step — the AI tool will + // just fall back to "API docs not bundled in this build" at + // runtime. Log loudly so the failure isn't silent. + console.error("Failed to mirror API docs into src-node:", error); + } +} + /** * Driver function */ @@ -260,6 +283,12 @@ async function driver() { console.log("All files processed successfully!"); } catch (error) { console.error("An error occurred:", error); + } finally { + // Always mirror whatever made it into docs/API-Reference, even if a + // single jsdoc failure aborted the batch loop. Otherwise the + // src-node mirror would silently stay stale (or non-existent) any + // time one source file has a jsdoc syntax glitch. + await copyApiDocsToSrcNode(); } } diff --git a/src-node/claude-code-agent.js b/src-node/claude-code-agent.js index 1db3490b84..79f7d2edd0 100644 --- a/src-node/claude-code-agent.js +++ b/src-node/claude-code-agent.js @@ -633,6 +633,9 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, "mcp__phoenix-editor__getEditorState", "mcp__phoenix-editor__takeScreenshot", "mcp__phoenix-editor__execJsInLivePreview", + "mcp__phoenix-editor__execJsInEditor", + "mcp__phoenix-editor__editorPreferences", + "mcp__phoenix-editor__editorDocs", "mcp__phoenix-editor__controlEditor", "mcp__phoenix-editor__resizeLivePreview", "mcp__phoenix-editor__wait", @@ -647,7 +650,8 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, tools: ["Read", "Glob", "Grep", "mcp__phoenix-editor__getEditorState", "mcp__phoenix-editor__takeScreenshot", - "mcp__phoenix-editor__execJsInLivePreview"] + "mcp__phoenix-editor__execJsInLivePreview", + "mcp__phoenix-editor__editorDocs"] }, "coder": { description: "Reads, edits, and writes code files." + @@ -658,7 +662,10 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, tools: ["Read", "Edit", "Write", "Glob", "Grep", "mcp__phoenix-editor__getEditorState", "mcp__phoenix-editor__takeScreenshot", - "mcp__phoenix-editor__execJsInLivePreview"] + "mcp__phoenix-editor__execJsInLivePreview", + "mcp__phoenix-editor__execJsInEditor", + "mcp__phoenix-editor__editorPreferences", + "mcp__phoenix-editor__editorDocs"] } }, mcpServers: { "phoenix-editor": editorMcpServer }, @@ -670,9 +677,15 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, "multiple Edit calls to make targeted changes rather than rewriting the entire " + "file with Write. This is critical because Write replaces the entire file content " + "which is slow and loses undo history." + - "\n\nWhen the user asks about the current file, open files, or what they are working on, " + - "call getEditorState first — it returns the active file path, working set, cursor position, " + - "and selection. Do NOT search the filesystem to answer these questions blindly." + + "\n\nALWAYS call getEditorState as your FIRST tool call on any question that " + + "references the user's current work — not just \"what file am I on\". This includes " + + "implicit-context questions like \"the page\", \"this layout\", \"the nav bar\", " + + "\"the button\", \"why is X behaving like this\", \"can you fix the styling\", " + + "\"scroll down on the page\", etc. The user is sitting in front of an editor and a " + + "live preview — without getEditorState you don't know which file they mean, which " + + "rules out targeted Read / Grep and makes you blindly grep the whole codebase. Run " + + "getEditorState first; THEN decide whether to Read the active file, Grep within it, " + + "or takeScreenshot the live preview to see what they're describing." + "\n\nAlways use full absolute paths for all file operations (Read, Edit, Write, " + "controlEditor). Never use relative paths." + "\n\nWhen a tool response mentions the user has typed a clarification, immediately " + @@ -723,6 +736,34 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale, "assume that. Rarely the user pins the preview to a specific file — if a " + "screenshot doesn't match the file you just edited, check " + "getEditorState.livePreviewFile to rule that out." + + "\n- execJsInEditor: eval JS in Phoenix's OWN JS space (parent window — NOT the live " + + "preview iframe). Use when controlEditor's fixed ops aren't enough — split panes, " + + "click dialog buttons, send synthetic key events, dispatch any CommandManager " + + "command, configure indentation, etc. `__PR` exposes the modules and helpers; see " + + "the tool description for the full list. Before writing non-trivial JS, call " + + "editorDocs and Read / Grep the bundled API reference so you call real APIs." + + "\n- editorPreferences: read or write Phoenix preferences. `list` enumerates every " + + "registered pref with id/type/default/current/description/scope; `get` for a single " + + "pref; `set` writes into user (global), project (.phcode.json in repo), or session " + + "(in-memory) scope." + + "\n- editorDocs: returns the on-disk path to the bundled API reference plus the " + + "feature-docs URL and the GitHub source repo URL. Call once near the start of any " + + "non-trivial editor-control task; then Read / Grep the apiDocsPath and WebFetch the " + + "featureDocsURL as needed. Do NOT search the codebase blindly when this exists." + + "\n\nName-collision rule: \"Phoenix Code\" (the editor the user is sitting inside) " + + "and \"Claude Code\" (the SDK / CLI you happen to run on) BOTH have settings, " + + "configs, auto-update toggles, themes, etc. When the user says \"set / change / " + + "configure / disable X\" without naming a product, they ALWAYS mean PHOENIX — " + + "your first action is editorPreferences.list (or .get/.set), not anything else.\n\n" + + "DO NOT INVOKE the built-in `update-config` skill, do not Read / Write / cat / Bash " + + "anything under ~/.claude/, ~/.claude.json, or any Claude Code / SDK config path, " + + "unless the user EXPLICITLY says \"Claude\" / \"Claude Code\" / \"SDK\" / \"agent\" / " + + "\"~/.claude\" in their message. The `update-config` skill modifies Claude Code's own " + + "config, NEVER Phoenix's — if your first instinct on a config / setting / pref / " + + "auto-update / theme question is to fire that skill, STOP and reach for " + + "editorPreferences instead.\n\n" + + "If a request is genuinely ambiguous (Phoenix has no matching pref), say so and ask " + + "the user which product they meant before changing anything." + "\n\nUse your best judgement for when to enter plan mode. Use it when the task " + "involves creating new applications, extensive modifications, or architectural " + "changes — propose a plan for user approval before writing code." + diff --git a/src-node/mcp-editor-tools.js b/src-node/mcp-editor-tools.js index b0a523feac..d0dac2729a 100644 --- a/src-node/mcp-editor-tools.js +++ b/src-node/mcp-editor-tools.js @@ -29,8 +29,19 @@ * Uses the Claude Code SDK's in-process MCP server support (createSdkMcpServer / tool). */ +const path = require("path"); +const fs = require("fs"); const { z } = require("zod"); +// Absolute path to the bundled API reference, mirrored from +// docs/API-Reference/ at build time by build/api-docs-generator.js. +// Git-ignored — see root .gitignore. Surfaced to the AI via the +// editorDocs MCP tool so it can Read / Grep these directly. +const PHOENIX_API_DOCS_DIR = path.join(__dirname, "apiDocs"); +const PHOENIX_FEATURE_DOCS_URL = "https://docs.phcode.dev/docs/intro"; +const PHOENIX_API_DOCS_URL = "https://docs.phcode.dev/api/getting-started"; +const PHOENIX_SOURCE_REPO_URL = "https://github.com/phcode-dev/phoenix"; + const CLARIFICATION_HINT = "IMPORTANT: The user has typed a follow-up clarification while you were working." + " Call the getUserClarification tool to read it before proceeding."; @@ -158,6 +169,10 @@ function createEditorMcpServer(sdkModule, nodeConnector, clarificationAccessors) "full editor." + "\n- For anything else — Problems panel, file tree, toolbar, search bar, any editor UI, or " + "\"what is the user looking at\" — omit the selector and capture the full editor window. " + + "\n- You can also pass any CSS selector to capture just that DOM node — e.g. " + + "'#problems-panel' to inspect inspector results, '.modal:visible' to inspect the active " + + "dialog, '#sidebar' to inspect the file tree. Useful right after execJsInEditor mutates " + + "the UI and you want to verify the change visually. " + "Note: live preview screenshots may include Phoenix toolbox overlays on selected elements. " + "Use purePreview=true to temporarily hide these overlays and render the page as it would appear in a real browser. " + "Use reload=true to force-reload the live preview before capturing — useful after editing JS, " + @@ -361,6 +376,196 @@ function createEditorMcpServer(sdkModule, nodeConnector, clarificationAccessors) } ); + const execJsInEditorTool = sdkModule.tool( + "execJsInEditor", + "Execute JavaScript in the Phoenix editor's OWN JS space (the parent window — NOT the live " + + "preview iframe). Use execJsInLivePreview when you need to run code inside the page being " + + "previewed; use this tool when you need to drive Phoenix itself: split panes, click dialog " + + "buttons, dispatch arbitrary CommandManager commands, configure indentation, send synthetic " + + "key events, etc. Same trust model as execJsInLivePreview — runs without a per-call prompt. " + + "\n\n" + + "The body is wrapped in `new AsyncFunction('__PR', 'KeyEvent', code)` so you can `await` " + + "freely. `__PR` exposes:\n" + + "- Modules: $, CommandManager, Commands, Dialogs, EditorManager, MainViewManager, " + + "DocumentManager, WorkspaceManager, FileSystem, FileViewController, ProjectManager, " + + "PreferencesManager. For anything else use `brackets.getModule(\"path/to/module\")`.\n" + + "- __PR.EDITING.{splitVertical, splitHorizontal, splitNone, isSplit, getFirstPaneEditor, " + + "getSecondPaneEditor, openFileInFirstPane(path,addToWS?), openFileInSecondPane(path,addToWS?), " + + "focusFirstPane, focusSecondPane, setEditorSpacing(useTabs,count,isAuto)}\n" + + "- __PR.awaitsFor(pollFn, msg?, timeoutMs?, pollInterval?) — poll until pollFn returns " + + "truthy or timeout (rejects).\n" + + "- __PR.waitForModalDialog(dialogClass?, name?, timeoutMs?) / waitForModalDialogClosed(...)\n" + + "- __PR.clickDialogButtonID(buttonID, dialogClass?) / clickDialogButton(selector, dialogClass?)\n" + + "- __PR.raiseKeyEvent(key, eventType?, element?, options?)\n" + + "- __PR.execCommand(commandID, arg?) — wraps CommandManager.execute in a native Promise.\n" + + "\n" + + "Whatever value (or Promise that resolves) your code returns is JSON-stringified and " + + "returned to you as `result`. If the return value isn't JSON-serializable you'll get a " + + "string repr. Errors are caught and returned as `error` — your call won't crash.\n" + + "\n" + + "Before writing non-trivial JS that touches Phoenix internals, call the editorDocs tool to " + + "find the local API reference path and Read / Grep the relevant module's .md file. " + + "Guessing at Phoenix internals will waste a turn. If the API docs don't cover what you " + + "need, the source is on GitHub at " + PHOENIX_SOURCE_REPO_URL + " — use the regular " + + "WebFetch tool against the relevant raw file.\n" + + "\n" + + "After running, call takeScreenshot if you want to visually verify what changed — " + + "pass no selector for the full editor, or pass a CSS selector (e.g. '#problems-panel', " + + "'.modal:visible', '#sidebar') to capture just that DOM node. This is the easiest way " + + "to confirm a UI mutation actually landed.\n" + + "\n" + + "Pass timeoutMs to bound how long to wait if the editor is wedged. Floored at 5000, no " + + "upper limit. Default 10000.", + { + code: z.string().describe("JavaScript code to execute in the Phoenix editor's JS space"), + timeoutMs: z.number().int().optional().describe( + "Max wait in milliseconds before giving up. " + + "Floored at 5000, no upper limit. Default 10000." + ) + }, + async function (args) { + let toolResult; + const timeoutMs = _resolveCallerTimeout(args.timeoutMs, 10000); + try { + const result = await _execPeerWithTimeout(nodeConnector, "execJsInEditor", { + code: args.code + }, "execJsInEditor", timeoutMs); + if (result && result.error) { + toolResult = { + content: [{ type: "text", text: "Error: " + result.error }], + isError: true + }; + } else { + toolResult = { + content: [{ type: "text", text: (result && result.result) || "undefined" }] + }; + } + } catch (err) { + toolResult = { + content: [{ type: "text", text: "Error executing JS in editor: " + err.message }], + isError: true + }; + } + return _maybeAppendHint(toolResult, hasClarification); + } + ); + + const editorPreferencesTool = sdkModule.tool( + "editorPreferences", + "Read and write Phoenix Code preferences. Three operations:\n" + + "- list: Returns every registered preference (id, type, defaultValue, currentValue, " + + "description, allowedValues if any, and the resolved scope of the current value).\n" + + "- get: Same fields for a single preference id.\n" + + "- set: Write a value into a specific scope. Calls PreferencesManager.save() after.\n\n" + + "Scope hierarchy (highest precedence wins on read): session → project → user → default.\n" + + "- default: built-in fallback declared by definePreference in source. READ-ONLY.\n" + + "- user: the user's global settings (persisted across all projects). User-friendly name " + + "when talking to the user: \"system-wide\" or \"globally\".\n" + + "- project: per-project settings (persisted with the project, travels with the repo). " + + "User-friendly name: \"for this project\" / \"in this repo\".\n" + + "- session: in-memory only, lasts until Phoenix restarts. User-friendly name: \"just for " + + "this session\". Useful for experimentation.\n\n" + + "WHEN TALKING TO THE USER: never say the raw scope words user / project / session — say " + + "\"system-wide\", \"for this project\", or \"just for this session\" instead. The raw " + + "names are only for the tool's scope parameter.\n\n" + + "PICKING THE RIGHT SCOPE: don't reflexively offer all three. Pick a sensible default " + + "based on what the preference does:\n" + + " - System / app-level concerns (auto-update, telemetry, font, theme, the \"do you want " + + "to install Node\" prompt): system-wide makes sense; project / session usually don't.\n" + + " - Code-style concerns (indent size, tabs vs spaces, word wrap, ruler): both " + + "system-wide AND for-this-project are reasonable; default to for-this-project (the " + + "convention travels with the repo). Mention system-wide only if the user implies it.\n" + + " - Experimentation / one-off (\"try this for now\"): just-this-session.\n" + + "If you're not sure which scope fits, use the preference's description / id to judge, " + + "and ask the user only when the call is genuinely unclear.\n\n" + + "Only preferences registered via definePreference are enumerated by `list`. Raw values " + + "in .phcode.json that were never defined won't appear.", + { + operation: z.enum(["list", "get", "set"]).describe("list / get / set"), + id: z.string().optional().describe("Preference id (required for get and set, e.g. 'spaceUnits')"), + value: z.any().optional().describe("New value (required for set)"), + scope: z.enum(["user", "project", "session"]).optional().describe( + "Required for set. Pick the scope that matches the preference's nature " + + "(see tool description). user = system-wide / global; project = " + + "per-project setting (persisted with the project); session = in-memory until " + + "next restart." + ) + }, + async function (args) { + let toolResult; + try { + const result = await _execPeerWithTimeout(nodeConnector, "editorPreferences", { + operation: args.operation, + id: args.id, + value: args.value, + scope: args.scope + }, "editorPreferences"); + if (result && result.error) { + toolResult = { + content: [{ type: "text", text: "Error: " + result.error }], + isError: true + }; + } else { + toolResult = { + content: [{ type: "text", text: JSON.stringify(result) }] + }; + } + } catch (err) { + toolResult = { + content: [{ type: "text", text: "Error in editorPreferences: " + err.message }], + isError: true + }; + } + return _maybeAppendHint(toolResult, hasClarification); + } + ); + + const editorDocsTool = sdkModule.tool( + "editorDocs", + "Returns the locations of Phoenix Code's documentation. This tool DOES NOT fetch content " + + "— it just hands you the absolute paths and URLs so you can read them with the standard " + + "Read / Grep / WebFetch tools (which is far more flexible than a fixed-shape doc API).\n\n" + + "The response includes:\n" + + "- apiDocsPath: absolute filesystem path to the bundled API reference (Markdown files, " + + "one per module). Read with the Read tool, or use Grep to find which module exposes a " + + "given function. Version-matched to this Phoenix build.\n" + + "- apiDocsAvailable: true if the directory exists; false if the build hasn't generated " + + "them yet (rare — fall back to the apiDocsURL).\n" + + "- apiDocsURL: live web copy of the API reference (latest version, may differ slightly " + + "from the bundled docs).\n" + + "- featureDocsURL: user-facing feature guides (\"how does Phoenix's X feature work\"). " + + "Fetch with WebFetch.\n" + + "- sourceRepoURL: GitHub repo for source-level lookups when the API docs don't cover " + + "something. Use WebFetch on raw.githubusercontent.com URLs to read individual files.\n\n" + + "Call this once near the start of any non-trivial editor-control task, then Read / " + + "Grep / WebFetch into the surfaces it returns.", + {}, + async function () { + let apiDocsAvailable = false; + try { + apiDocsAvailable = fs.existsSync(PHOENIX_API_DOCS_DIR); + } catch (e) { /* default false */ } + const payload = { + apiDocsPath: PHOENIX_API_DOCS_DIR, + apiDocsAvailable: apiDocsAvailable, + apiDocsURL: PHOENIX_API_DOCS_URL, + featureDocsURL: PHOENIX_FEATURE_DOCS_URL, + sourceRepoURL: PHOENIX_SOURCE_REPO_URL, + hint: apiDocsAvailable + ? "Read or Grep apiDocsPath to find the module you need (e.g. " + + "Grep for the function name across the directory). Use WebFetch on " + + "featureDocsURL for user-facing feature guides." + : "Bundled API docs not present in this build. Use WebFetch on " + + "apiDocsURL for the live API reference and on featureDocsURL for feature " + + "guides." + }; + const toolResult = { + content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] + }; + return _maybeAppendHint(toolResult, hasClarification); + } + ); + const getUserClarificationTool = sdkModule.tool( "getUserClarification", "Retrieve a follow-up clarification message the user typed while you were working. " + @@ -399,8 +604,9 @@ function createEditorMcpServer(sdkModule, nodeConnector, clarificationAccessors) return sdkModule.createSdkMcpServer({ name: "phoenix-editor", - tools: [getEditorStateTool, takeScreenshotTool, execJsInLivePreviewTool, controlEditorTool, - resizeLivePreviewTool, waitTool, getUserClarificationTool] + tools: [getEditorStateTool, takeScreenshotTool, execJsInLivePreviewTool, + execJsInEditorTool, editorPreferencesTool, editorDocsTool, + controlEditorTool, resizeLivePreviewTool, waitTool, getUserClarificationTool] }); } diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 08337e5343..128aebe561 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -2228,6 +2228,9 @@ define({ "AI_CHAT_TOOL_SCREENSHOT_LIVE_PREVIEW": "live preview", "AI_CHAT_TOOL_SCREENSHOT_FULL_EDITOR": "the full editor", "AI_CHAT_TOOL_LIVE_PREVIEW_JS": "Inspecting preview", + "AI_CHAT_TOOL_EDITOR_JS": "Inspecting editor", + "AI_CHAT_TOOL_EDITOR_PREFERENCES": "Editor preferences", + "AI_CHAT_TOOL_EDITOR_DOCS": "Editor docs", "AI_CHAT_TOOL_RESIZE_PREVIEW": "Resize preview", "AI_LIVE_PREVIEW_BANNER_TEXT": "AI is inspecting the live preview", "AI_LIVE_PREVIEW_BANNER_RESIZE": "AI resized preview to {0}", From d9f7909e4e4560c6a18b81fd13805c93dbb952f4 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 16 May 2026 12:02:11 +0530 Subject: [PATCH 2/3] chore: update pro deps --- tracking-repos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking-repos.json b/tracking-repos.json index e7356f4758..b4e6410886 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "877adc33ccbd76d0d817674ef5582caea8ad09ef" + "commitID": "8e34235568a346712bb69c046abd60d73ed72345" } } From ad08a03f07385be98f71b71423fe5d4ba3f81d41 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 16 May 2026 13:12:42 +0530 Subject: [PATCH 3/3] chore: update pro deps --- tracking-repos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking-repos.json b/tracking-repos.json index b4e6410886..ca7ccb83db 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "8e34235568a346712bb69c046abd60d73ed72345" + "commitID": "4b300958bc41b73646d0b95be83674fbdfc7e21a" } }