Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gulpfile.js/validate-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const glob = require('glob');
// Size limits for development builds (in MB). Same margin policy as the prod limits
// below: bump only enough to restore the headroom, so real size jumps still get caught.
const DEV_MAX_FILE_SIZE_MB = 6;
const DEV_MAX_TOTAL_SIZE_MB = 105; // dev dist is ~100 MB + 5 MB margin
const DEV_MAX_TOTAL_SIZE_MB = 110; // dev dist is ~105 MB + 5 MB margin
// Custom size limits for known large files (size in MB) For development builds
const LARGE_FILE_LIST_DEV = {
'dist/thirdparty/no-minify/language-worker.js.map': 10,
Expand Down
3 changes: 3 additions & 0 deletions phoenix-builder-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ for that local calendar day; run this command again on another day to renew it.
disconnect an already running session. Start the Builder MCP server separately using the setup
above; the script only manages the desktop app's permission file.

Once Builder is enabled at startup, production builds also show **Debug → Phoenix Code Diagnostic
Tools → Phoenix Builder MCP…** for connection settings and console logs.

### Optional remote machines

Use two independent MCP servers: **Phoenix Builder** for app interaction, screenshots and Jasmine tests, and **remote-control** for machine discovery, remote commands, file transfers, Git sync and agent coordination. Builder has no framework package dependency and opens no orchestrator agent session. Local Builder use needs no remote framework.
Expand Down
26 changes: 12 additions & 14 deletions src-node/ai-editor-tool-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -737,13 +737,16 @@ function getEditorToolSpecs(peerCall, options = {}) {
"askInLivePreview",
"Ask a visual question over the HTML live preview and wait for the answer. Prefer choices: each has id, " +
"label, optional description/color, and preview:{css or cssFile, optional scriptFile, selector, params}. Phoenix " +
"handles hover/focus previews, restore on leave, keyboard/touch, click-to-answer and cleanup. A click " +
"returns {choice:id,label}, closes the question, and retains the preview while you apply the choice to " +
"owns hover/focus previews, selection and cleanup: clicking a choice keeps its preview and fills the reply " +
"box; only the user's Send/Enter confirms. Hovering elsewhere is temporary; leaving restores the selection. " +
"Clearing the reply clears selection. Confirmation returns {choice:id,label}, closes the question, " +
"and retains the preview while you apply the choice to " +
"source. Runtime effects are restored before file preparation so live edits use the original DOM; " +
"CSS-only effects may remain until verification or turn end. Apply the chosen result before finishing. " +
"Without uiFile, Phoenix renders styled choice cards: no UI files or JavaScript needed. For expressive " +
"custom content write an HTML fragment with its own <style>, mark any option class='ph-choice' data-id='1' " +
"(hover and click) or class='ph-hover' (hover only). Design the full body freely; keep text readable. " +
"(hover and select) or class='ph-hover' (hover only). Style .ph-selected for a visible selected state; " +
"Phoenix toggles it and aria-pressed. Design the full body freely; keep text readable. " +
"Write reusable files in getEditorState's askInLivePreviewUiDir, outside the project. Shared cssFile " +
"templates use {{key}} from preview.params (merged over top-level params); reuse files and change params " +
"for follow-ups instead of regenerating UI/CSS. Inline css is useful for small previews. " +
Expand All @@ -762,16 +765,11 @@ function getEditorToolSpecs(peerCall, options = {}) {
"Helpers: preview.query(selector), hover(fn), css(text), html(selector,markup), on(selector,event,handler), " +
"interval(fn,ms), timeout(fn,ms), cleanup(fn), signal. Effects must stay in the temporary page; reload " +
"cannot undo storage or server writes. Optional top-level scriptFile controls the isolated question UI " +
"as function(root,phoenix,params){file text}; phoenix.preview(id,params) pins a preview so the user " +
"can try the page's controls; preview(null) clears it. Interactive previews NEED a separate " +
"Pin & try button using phoenix.preview and a dedicated Choose button using ph-choice or phoenix.answer. " +
"Example: a ph-hover card with data-id='1', a plain [data-try='1'] button wired in scriptFile to " +
"phoenix.preview('1'), and a separate ph-choice button data-id='1'. Do not put ph-choice on the whole " +
"card containing these controls, since a click on a child would submit. " +
"Include a brief hint explaining that pinning lets the user try controls before choosing; page controls " +
"need normal Preview mode, not Edit mode. Also phoenix.answer(id,params), cancel(). UI-supplied params " +
"are returned with the answer so you can persist the exact customized choice. " +
"Normal choices need no handlers. Question state survives page resets. Built-in frame supplies close, " +
"as function(root,phoenix,params){file text}; phoenix.select(id,params) selects a customized choice for " +
"confirmation; phoenix.cancel() cancels. Supplied params return with the confirmed choice. Normal choices " +
"need no handlers or extra buttons: the user clicks, tries the page, then sends the reply. Page controls " +
"need normal Preview mode, not Edit mode. Selection survives minimizing and cleanup reloads. " +
"Built-in frame supplies close, " +
"minimize, drag anywhere in the editor window, resize and a free-text answer. Files can be absolute " +
"or relative to askInLivePreviewUiDir. " +
"This is the complete contract; do not search for implementation. Result is answered, cancelled or error. " +
Expand Down Expand Up @@ -817,7 +815,7 @@ function getEditorToolSpecs(peerCall, options = {}) {
textColor: z.string().max(64).optional(),
accent: z.string().max(64).optional()
}).optional().describe("CSS colours for the frame, so the card matches the page; unset ones default to a " +
"light or dark card chosen from the page's background. accent colours the Send button"),
"light or dark card chosen from the page's background. accent colours selection and focus"),
timeoutS: z.number().int().min(10).max(1800).optional().describe("Seconds to wait for an answer, default 300")
},
async function (args) {
Expand Down
6 changes: 5 additions & 1 deletion src-node/claude-code-agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -1632,7 +1632,11 @@ async function _runQuery(requestId, prompt, projectPath, model, signal, locale,
// letting the SDK fail with a generic "oldText not
// found". Phoenix sees the buffer state the SDK
// can't, so this is a more useful failure.
if (oldString && (captured.content || "").indexOf(oldString) === -1) {
// Native Read presents LF text even when the disk file uses CRLF.
// Compare logical lines without changing the snapshot or SDK input.
const contentToMatch = (captured.content || "").replace(/\r\n/g, "\n");
const oldStringToMatch = oldString && oldString.replace(/\r\n/g, "\n");
if (oldStringToMatch && contentToMatch.indexOf(oldStringToMatch) === -1) {
const reason = "Edit FAILED: the text you wanted to replace is not " +
"present in the file. It may have been modified by the user " +
"or by another tool since you last read it. Read the file again " +
Expand Down
4 changes: 2 additions & 2 deletions src-node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions src-node/test/test-ai-file-permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const NodeConnector = require("../node-connector");
/**
* Exercise one bounded permission scenario with a fake SDK and browser connector.
* No installed CLI, network, credentials, user files or global agent state are used.
* @param {Object} params Mode, tool, target category and optional mode/answer scenario.
* @param {Object} params Mode, tool, target category and optional mode/answer scenario or edit text.
* @return {Promise<Object>} Hook decisions, SDK options and observed browser operations.
*/
async function exercise(params) {
Expand Down Expand Up @@ -50,7 +50,9 @@ async function exercise(params) {
switchedDuringPrep = true;
await exported.setPermissionMode({mode: params.switchDuringPrep});
}
return name === "captureFileContent" ? {content: params.stale ? "changed" : "before"} : {};
return name === "captureFileContent" ? {
content: params.fileContent !== undefined ? params.fileContent : (params.stale ? "changed" : "before")
} : {};
},
triggerPeer: function (name, data) {
events.push({name, data});
Expand Down Expand Up @@ -158,7 +160,8 @@ async function exercise(params) {
await postExit.hooks[0]();
}
}
const toolInput = {file_path: filePath, content: "after", old_string: "before", new_string: "after"};
const toolInput = {file_path: filePath, content: "after",
old_string: params.oldString !== undefined ? params.oldString : "before", new_string: "after"};
const hook = options.hooks.PreToolUse.find(entry => entry.matcher === tool).hooks[0];
const decision = await Promise.race([
hook({tool_name: tool, tool_input: toolInput}, "fixture-tool", {}), deadline
Expand Down
3 changes: 3 additions & 0 deletions src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ define(function (require, exports, module) {
require("JSUtils/Session");
require("JSUtils/ScopeManager");

// Shared setup policy/UI is lightweight; the language server clients themselves stay lazy.
require("languageTools/LSPInstallSupport");

// Language Tools (LSP) are desktop-only and loaded lazily by languageTools/LSPClient the
// first time a language server is started, so they are intentionally not required at boot.

Expand Down
4 changes: 3 additions & 1 deletion src/extensions/default/DebugCommands/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,10 @@ define(function (require, exports, module) {
diagnosticsSubmenu.addMenuItem(DEBUG_RUN_UNIT_TESTS);
CommandManager.register(Strings.CMD_BUILD_TESTS, DEBUG_BUILD_TESTS, TestBuilder.toggleTestBuilder, { supportsDesignMode: true });
diagnosticsSubmenu.addMenuItem(DEBUG_BUILD_TESTS);
if (AppConfig.config.environment === "dev") {
if (CommandManager.get("debug.phoenixBuilderConnect")) {
diagnosticsSubmenu.addMenuItem("debug.phoenixBuilderConnect");
}
if (AppConfig.config.environment === "dev") {
diagnosticsSubmenu.addMenuItem("debug.debugOverrides");
}
diagnosticsSubmenu.addMenuDivider();
Expand Down
Loading
Loading