Skip to content

Commit 50fbcb3

Browse files
committed
deploy: 606b7d0
1 parent fc7f6e7 commit 50fbcb3

File tree

73 files changed

+1624
-140
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1624
-140
lines changed

appConfig.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ window.AppConfig = {
3333
"app_update_url": "https://updates.phcode.io/tauri/update-latest-experimental-build.json",
3434
"extensionTakedownURL": "https://updates.phcode.io/extension_takedown.json",
3535
"linting.enabled_by_default": true,
36-
"build_timestamp": "2025-10-25T13:08:25.351Z",
36+
"build_timestamp": "2025-10-25T16:15:18.651Z",
3737
"googleAnalyticsID": "G-P4HJFPDB76",
3838
"googleAnalyticsIDDesktop": "G-VE5BXWJ0HF",
3939
"mixPanelID": "49c4d164b592be2350fc7af06a259bf3",
@@ -45,7 +45,7 @@ window.AppConfig = {
4545
"bugsnagEnv": "development"
4646
},
4747
"name": "Phoenix Code",
48-
"version": "4.1.2-21665",
48+
"version": "4.1.2-21670",
4949
"apiVersion": "4.1.2",
5050
"homepage": "https://core.ai",
5151
"issues": {

assets/default-project/en.zip

0 Bytes
Binary file not shown.

assets/sample-projects/HTML5.zip

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

assets/sample-projects/explore.zip

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

brackets-min.js

Lines changed: 189 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113787,6 +113787,8 @@ define("nls/root/strings", {
113787113787
"EXTENSION_VERIFIED_SORT": "Verified",
113788113788
"EXTENSION_STAR": "Star",
113789113789
"EXTENSION_STAR_SORT": "Star Rating",
113790+
"ERROR_UNINSTALLING_EXTENSION_TITLE": "Error Uninstalling Extension",
113791+
"ERROR_UNINSTALLING_EXTENSION_MESSAGE": "Failed to uninstall extension {0}",
113790113792
// For NOT_FOUND_ERR, see generic strings above
113791113793
"EXTENSION_MANAGER_TITLE": "Extension Manager",
113792113794
"EXTENSION_MANAGER_ERROR_LOAD": "Unable to access the extension registry. Please try again later.",
@@ -114154,10 +114156,12 @@ define("nls/root/strings", {
114154114156
"DOWNLOAD_ERROR": "Error occurred while downloading.",
114155114157
"NETWORK_SLOW_OR_DISCONNECTED": "Network is disconnected or too slow.",
114156114158
"RESTART_BUTTON": "Restart",
114159+
"RESTART_APP_BUTTON": "Restart {APP_NAME}",
114157114160
"LATER_BUTTON": "Later",
114158114161
"DESCRIPTION_AUTO_UPDATE": "Enable/disable {APP_NAME} Auto-update",
114159114162
"AUTOUPDATE_ERROR": "Error!",
114160114163
"AUTOUPDATE_IN_PROGRESS": "An update is already in progress.",
114164+
"REMOVING": "Removing\u2026",
114161114165

114162114166
"NUMBER_WITH_PERCENTAGE": "{0}%",
114163114167
// Strings for Related Files
@@ -114706,6 +114710,10 @@ define("nls/root/strings", {
114706114710
"LICENSE_ACTIVATE_FAIL_APPLY": "'Failed to apply license to device'",
114707114711
"LICENSE_ENTER_KEY": "Please enter a license key",
114708114712
"LICENSE_REAPPLY_TO_DEVICE": "Already activated? Reapply system-wide",
114713+
// Deprecated Extensions Dialog
114714+
"DEPRECATED_EXTENSIONS_TITLE": "Deprecated Extensions Detected",
114715+
"DEPRECATED_EXTENSIONS_MESSAGE": "The following installed extensions are now natively supported by {APP_NAME} and can be safely uninstalled from the Extension Manager:",
114716+
"DEPRECATED_EXTENSIONS_LEARN_MORE": "Now built-in — learn more",
114709114717
// AI CONTROL
114710114718
"AI_LOGIN_DIALOG_TITLE": "Sign In to Use AI Edits",
114711114719
"AI_LOGIN_DIALOG_MESSAGE": "Please log in to use AI-powered edits",
@@ -176575,11 +176583,57 @@ define("utils/ExtensionLoader", function (require, exports, module) {
176575176583
UrlParams = require("utils/UrlParams").UrlParams,
176576176584
NodeUtils = require("utils/NodeUtils"),
176577176585
PathUtils = require("thirdparty/path-utils/path-utils"),
176578-
DefaultExtensions = JSON.parse(require("text!extensions/default/DefaultExtensions.json"));
176586+
DefaultExtensions = JSON.parse(require("text!extensions/default/DefaultExtensions.json")),
176587+
Dialogs = require("widgets/Dialogs"),
176588+
PreferencesManager = require("preferences/PreferencesManager"),
176589+
Mustache = require("thirdparty/mustache/mustache"),
176590+
Strings = require("strings"),
176591+
StringUtils = require("utils/StringUtils"),
176592+
Metrics = require("utils/Metrics"),
176593+
DeprecatedExtensionsTemplate = `<div class="deprecated-extensions-dialog modal">
176594+
<div class="modal-header">
176595+
<h1 class="dialog-title">{{Strings.DEPRECATED_EXTENSIONS_TITLE}}</h1>
176596+
</div>
176597+
<div class="modal-body">
176598+
<p class="dialog-message">{{Strings.DEPRECATED_EXTENSIONS_MESSAGE}}</p>
176599+
176600+
<div class="deprecated-extensions-list" style="margin-top: 16px;">
176601+
{{#extensions}}
176602+
<div class="deprecated-extension-item" style="margin-bottom: 12px; padding: 12px; display: flex; justify-content: space-between; align-items: flex-start;">
176603+
<div style="flex: 1;">
176604+
<div class="extension-info" style="margin-bottom: 6px;">
176605+
<i class="fa fa-exclamation-triangle" style="color: #f5a623; margin-right: 8px;"></i>
176606+
<strong>{{name}}</strong>
176607+
</div>
176608+
<div class="extension-alternative" style="margin-left: 24px;">
176609+
<a href="{{docUrl}}" target="_blank" rel="noopener">
176610+
{{Strings.DEPRECATED_EXTENSIONS_LEARN_MORE}}
176611+
<i class="fa fa-external-link" style="margin-left: 4px; font-size: 11px;"></i>
176612+
</a>
176613+
</div>
176614+
</div>
176615+
<div style="margin-left: 12px;">
176616+
<button class="btn btn-mini uninstall-extension-btn" data-extension-id="{{id}}">
176617+
{{Strings.REMOVE}}
176618+
</button>
176619+
</div>
176620+
</div>
176621+
{{/extensions}}
176622+
</div>
176623+
</div>
176624+
<div class="modal-footer">
176625+
<button class="dialog-button btn primary" data-button-id="ok">{{Strings.OK}}</button>
176626+
</div>
176627+
</div>
176628+
`,
176629+
CommandManager = require("command/CommandManager");
176579176630

176580176631
// takedown/dont load extensions that are compromised at app start - start
176581176632
const EXTENSION_TAKEDOWN_LOCALSTORAGE_KEY = "PH_EXTENSION_TAKEDOWN_LIST";
176582176633

176634+
// deprecated extensions dialog state key
176635+
const STATE_DEPRECATED_EXTENSIONS_DIALOG_SHOWN = "deprecatedExtensionsDialogShown";
176636+
176583176637
function _getTakedownListLS() {
176584176638
try{
176585176639
let list = localStorage.getItem(EXTENSION_TAKEDOWN_LOCALSTORAGE_KEY);
@@ -176595,7 +176649,7 @@ define("utils/ExtensionLoader", function (require, exports, module) {
176595176649
return [];
176596176650
}
176597176651

176598-
const loadedExtensionIDs = new Set();
176652+
const loadedExtensionIDs = new Map();
176599176653
let takedownExtensionList = new Set(_getTakedownListLS());
176600176654

176601176655
const EXTENSION_TAKEDOWN_URL = brackets.config.extensionTakedownURL;
@@ -176609,16 +176663,16 @@ define("utils/ExtensionLoader", function (require, exports, module) {
176609176663

176610176664
if (takedownExtensionList.size < loadedExtensionIDs.size) {
176611176665
smaller = takedownExtensionList;
176612-
larger = loadedExtensionIDs;
176666+
larger = Array.from(loadedExtensionIDs.keys());
176613176667
} else {
176614-
smaller = loadedExtensionIDs;
176668+
smaller = Array.from(loadedExtensionIDs.keys());
176615176669
larger = takedownExtensionList;
176616176670
}
176617176671

176618176672
const matches = [];
176619176673

176620176674
for (const id of smaller) {
176621-
if (larger.has(id)) {
176675+
if (larger.has ? larger.has(id) : larger.includes(id)) {
176622176676
matches.push(id);
176623176677
}
176624176678
}
@@ -177034,7 +177088,11 @@ define("utils/ExtensionLoader", function (require, exports, module) {
177034177088
}
177035177089

177036177090
if(metadata.name) {
177037-
loadedExtensionIDs.add(metadata.name);
177091+
loadedExtensionIDs.set(metadata.name, {
177092+
loadedFromDisc: !!config.nativeDir,
177093+
extensionPath: config.nativeDir || config.baseUrl,
177094+
extensionName: metadata.title || metadata.name
177095+
});
177038177096
}
177039177097

177040177098
// No special handling for themes... Let the promise propagate into the ExtensionManager
@@ -177539,6 +177597,8 @@ define("utils/ExtensionLoader", function (require, exports, module) {
177539177597

177540177598
promise.always(function () {
177541177599
_init = true;
177600+
// Check for deprecated extensions after all extensions have loaded
177601+
_checkAndShowDeprecatedExtensionsDialog();
177542177602
});
177543177603

177544177604
return promise;
@@ -177553,6 +177613,128 @@ define("utils/ExtensionLoader", function (require, exports, module) {
177553177613
return takedownExtensionList.has(extensionID);
177554177614
}
177555177615

177616+
/**
177617+
* Uninstall a deprecated extension
177618+
* @param {string} extensionID - The ID of the extension to uninstall
177619+
* @return {Promise} A promise that resolves when the extension is uninstalled successfully
177620+
*/
177621+
async function uninstallExtension(extensionID) {
177622+
const extensionInfo = loadedExtensionIDs.get(extensionID);
177623+
177624+
if (!extensionInfo) {
177625+
throw new Error(`Extension ${extensionID} not found in loaded extensions`);
177626+
}
177627+
177628+
if (!extensionInfo.loadedFromDisc) {
177629+
throw new Error(`Cannot uninstall built-in extension: ${extensionID}`);
177630+
}
177631+
177632+
const extensionDir = FileSystem.getDirectoryForPath(extensionInfo.extensionPath);
177633+
await extensionDir.unlinkAsync();
177634+
}
177635+
177636+
/**
177637+
* Check if any deprecated extensions are installed and show a dialog once per extension
177638+
* @private
177639+
*/
177640+
function _checkAndShowDeprecatedExtensionsDialog() {
177641+
// Get deprecated extensions config
177642+
let needsRestart = false;
177643+
const deprecatedExtensionsConfig = DefaultExtensions.deprecatedExtensions;
177644+
if (!deprecatedExtensionsConfig || !deprecatedExtensionsConfig.extensionIDsAndDocs) {
177645+
return;
177646+
}
177647+
177648+
const deprecatedExtensionIDs = deprecatedExtensionsConfig.extensionIDsAndDocs;
177649+
177650+
// Get the state object that tracks which deprecated extensions we've already shown
177651+
let shownDeprecatedExtensions = PreferencesManager.stateManager.get(STATE_DEPRECATED_EXTENSIONS_DIALOG_SHOWN);
177652+
if (!shownDeprecatedExtensions || typeof shownDeprecatedExtensions !== 'object') {
177653+
shownDeprecatedExtensions = {};
177654+
}
177655+
177656+
// Check which deprecated extensions are loaded and not yet shown
177657+
const deprecatedExtensionsFound = [];
177658+
for (const extensionID of loadedExtensionIDs.keys()) {
177659+
if (deprecatedExtensionIDs[extensionID] && !shownDeprecatedExtensions[extensionID]) {
177660+
const extensionInfo = loadedExtensionIDs.get(extensionID);
177661+
const extensionName = extensionInfo && extensionInfo.extensionName;
177662+
deprecatedExtensionsFound.push({
177663+
id: extensionID,
177664+
name: extensionName || extensionID,
177665+
docUrl: deprecatedExtensionIDs[extensionID]
177666+
});
177667+
}
177668+
}
177669+
177670+
// If no new deprecated extensions found, return
177671+
if (deprecatedExtensionsFound.length === 0) {
177672+
return;
177673+
}
177674+
177675+
// Show the dialog
177676+
const templateVars = {
177677+
extensions: deprecatedExtensionsFound,
177678+
Strings: Strings
177679+
};
177680+
177681+
const $template = $(Mustache.render(DeprecatedExtensionsTemplate, templateVars));
177682+
const dialog = Dialogs.showModalDialogUsingTemplate($template, false); // autoDismiss = false
177683+
177684+
// Wire up uninstall button click handlers
177685+
$template.on('click', '.uninstall-extension-btn', async function() {
177686+
const $button = $(this);
177687+
const extensionID = $button.data('extension-id');
177688+
const $extensionItem = $button.closest('.deprecated-extension-item');
177689+
177690+
// Disable button during uninstall
177691+
$button.prop('disabled', true);
177692+
$button.text(Strings.REMOVING);
177693+
177694+
try {
177695+
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "removeDep", extensionID);
177696+
await uninstallExtension(extensionID);
177697+
177698+
// Update the OK button to "Restart App"
177699+
const $okButton = $template.find('[data-button-id="ok"]');
177700+
$okButton.text(Strings.RESTART_APP_BUTTON);
177701+
177702+
// Strike through the extension name and disable/strike the uninstall button
177703+
$extensionItem.find('.extension-info strong').addClass('striked');
177704+
$button.remove();
177705+
needsRestart = true;
177706+
} catch (err) {
177707+
Metrics.countEvent(Metrics.EVENT_TYPE.EXTENSIONS, "removeDep", "fail");
177708+
logger.reportError(err, 'Failed to uninstall deprecated extension:' + extensionID);
177709+
177710+
// Show error dialog
177711+
const message = StringUtils.format(Strings.ERROR_UNINSTALLING_EXTENSION_MESSAGE, extensionID);
177712+
Dialogs.showErrorDialog(Strings.ERROR_UNINSTALLING_EXTENSION_TITLE, message);
177713+
177714+
// Re-enable button
177715+
$button.prop('disabled', false);
177716+
$button.text(Strings.REMOVE);
177717+
}
177718+
});
177719+
177720+
// Handle OK button click
177721+
$template.on('click', '[data-button-id="ok"]', function() {
177722+
if (needsRestart) {
177723+
// Reload the app to complete uninstallation
177724+
CommandManager.execute("debug.refreshWindow");
177725+
} else {
177726+
// Just close the dialog
177727+
dialog.close();
177728+
}
177729+
});
177730+
177731+
// Mark each extension as shown
177732+
for (const ext of deprecatedExtensionsFound) {
177733+
shownDeprecatedExtensions[ext.id] = true;
177734+
}
177735+
PreferencesManager.stateManager.set(STATE_DEPRECATED_EXTENSIONS_DIALOG_SHOWN, shownDeprecatedExtensions);
177736+
}
177737+
177556177738

177557177739
EventDispatcher.makeEventDispatcher(exports);
177558177740

@@ -177577,6 +177759,7 @@ define("utils/ExtensionLoader", function (require, exports, module) {
177577177759
exports.loadAllExtensionsInNativeDirectory = loadAllExtensionsInNativeDirectory;
177578177760
exports.loadExtensionFromNativeDirectory = loadExtensionFromNativeDirectory;
177579177761
exports.isExtensionTakenDown = isExtensionTakenDown;
177762+
exports.uninstallExtension = uninstallExtension;
177580177763
exports.testAllExtensionsInNativeDirectory = testAllExtensionsInNativeDirectory;
177581177764
exports.testAllDefaultExtensions = testAllDefaultExtensions;
177582177765
exports.EVENT_EXTENSION_LOADED = EVENT_EXTENSION_LOADED;

0 commit comments

Comments
 (0)