codex-plus-patcher 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/package.json +2 -1
- package/src/cli.js +97 -0
- package/src/patches/26.616.41845-4198.js +2 -0
- package/src/patches/26.616.51431-4212.js +2 -0
- package/src/patches/26.616.71553-4265.js +6 -0
- package/src/patches/26.616.81150-4306.js +7 -0
- package/src/patches/lib/common-patches.js +140 -3
- package/src/patches/lib/project-selector-shortcut-patch.js +54 -0
- package/src/runtime/assets.js +4 -0
- package/src/runtime/plugins/devTools.js +33 -0
- package/src/runtime/plugins/projectPathHeader.js +116 -0
- package/src/runtime/plugins/projectSelectorShortcut.js +207 -0
- package/src/runtime/runtime.js +91 -6
package/README.md
CHANGED
|
@@ -29,7 +29,10 @@ patches plus readable runtime plugins:
|
|
|
29
29
|
- add diagnostic detail for selected app-shell errors
|
|
30
30
|
- add user-message bubble color controls in Appearance settings
|
|
31
31
|
- add adaptive project colors for sidebar projects, grouped threads, pinned threads, user-message accents, and the composer
|
|
32
|
+
- show the active project path in the thread header with a copy action
|
|
32
33
|
- add the `Toggle sidebar blur` command palette entry to blur sidebar chat and project names for the current session
|
|
34
|
+
- add an `Open Developer Tools` panels command for opening the current Codex window's DevTools
|
|
35
|
+
- add the `Focus project selector` command and `CmdOrCtrl+.` shortcut for new-chat project selection
|
|
33
36
|
- add a fullscreen Mermaid diagram viewer with zoom controls
|
|
34
37
|
|
|
35
38
|
The generated app includes a readable Codex Plus runtime under
|
|
@@ -112,6 +115,13 @@ Print the machine-readable result:
|
|
|
112
115
|
codex-plus-patcher apply --dry-run --json
|
|
113
116
|
```
|
|
114
117
|
|
|
118
|
+
Inspect menu-related patch markers in a generated app:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
codex-plus-patcher menu-diagnostics \
|
|
122
|
+
--asar "~/Applications/Codex Plus.app/Contents/Resources/app.asar"
|
|
123
|
+
```
|
|
124
|
+
|
|
115
125
|
For local development of the CLI wrapper:
|
|
116
126
|
|
|
117
127
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-plus-patcher",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Patch queue tool for building a local Codex Plus.app from an installed Codex.app.",
|
|
6
6
|
"repository": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"license": "Apache-2.0",
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"fzf": "0.5.2",
|
|
31
32
|
"ora": "^9.4.0"
|
|
32
33
|
}
|
|
33
34
|
}
|
package/src/cli.js
CHANGED
|
@@ -62,6 +62,7 @@ function helpText() {
|
|
|
62
62
|
return `Usage:
|
|
63
63
|
codex-plus-patcher
|
|
64
64
|
codex-plus-patcher apply [options]
|
|
65
|
+
codex-plus-patcher menu-diagnostics --asar <path> [--json]
|
|
65
66
|
codex-plus-patcher asar-list --asar <path> [--contains <text>] [--json]
|
|
66
67
|
codex-plus-patcher asar-cat --asar <path> --file <asar-path> [--json]
|
|
67
68
|
|
|
@@ -156,6 +157,67 @@ function readAsarFile({ asar, file }) {
|
|
|
156
157
|
return { asar, file, size, content };
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
function readPackedEntry(archive, node) {
|
|
161
|
+
if (node.unpacked) return null;
|
|
162
|
+
const size = Number(node.size || 0);
|
|
163
|
+
const start = archive.dataStart + Number(node.offset || 0);
|
|
164
|
+
return archive.buffer.subarray(start, start + size).toString("utf8");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function menuDiagnostics({ asar }) {
|
|
168
|
+
if (!asar) throw new Error("--asar is required");
|
|
169
|
+
const archive = readAsar(asar);
|
|
170
|
+
const files = walkFiles(archive.header);
|
|
171
|
+
const commandId = "codexPlusOpenDevTools";
|
|
172
|
+
const menuTitle = "Open Developer Tools";
|
|
173
|
+
const commandMetadataFiles = [];
|
|
174
|
+
const nativeBridgeFiles = [];
|
|
175
|
+
const runtimePluginFiles = [];
|
|
176
|
+
const applicationMenuFiles = [];
|
|
177
|
+
|
|
178
|
+
for (const [file, node] of files) {
|
|
179
|
+
if (!file.endsWith(".js")) continue;
|
|
180
|
+
const content = readPackedEntry(archive, node);
|
|
181
|
+
if (content == null) continue;
|
|
182
|
+
const hasDevToolsCommand = content.includes(commandId);
|
|
183
|
+
const hasMenuTitle = content.includes(menuTitle);
|
|
184
|
+
const hasToggleBottomPanel = content.includes("Toggle Bottom Panel") || content.includes("toggleBottomPanel");
|
|
185
|
+
const hasPanelsGroup = content.includes("commandMenuGroupKey:`panels`") || content.includes('commandMenuGroupKey:"panels"');
|
|
186
|
+
const hasNativeBridge = content.includes("devtools/open") || content.includes("CPXOpenDevTools");
|
|
187
|
+
const hasRuntimePlugin = file.endsWith("/devTools.js") || content.includes('id: "devTools"');
|
|
188
|
+
const hasApplicationMenu = content.includes("Menu.setApplicationMenu") || content.includes("refreshApplicationMenu");
|
|
189
|
+
|
|
190
|
+
if (hasPanelsGroup || hasDevToolsCommand || file.includes("electron-menu-shortcuts")) {
|
|
191
|
+
commandMetadataFiles.push({
|
|
192
|
+
file,
|
|
193
|
+
hasDevToolsCommand,
|
|
194
|
+
hasMenuTitle,
|
|
195
|
+
hasToggleBottomPanel,
|
|
196
|
+
hasPanelsGroup,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (hasNativeBridge) nativeBridgeFiles.push({ file, hasDevToolsOpenRequest: content.includes("devtools/open"), hasOpenDevToolsCall: content.includes("openDevTools") });
|
|
200
|
+
if (hasRuntimePlugin) runtimePluginFiles.push({ file, hasDevToolsCommand, hasDevToolsOpenRequest: content.includes("devtools/open") });
|
|
201
|
+
if (hasApplicationMenu) applicationMenuFiles.push({ file, hasDiagnosticsHook: content.includes("CPXLogMenuDiagnostics"), hasDevToolsCommand });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
asar,
|
|
206
|
+
commandId,
|
|
207
|
+
menuTitle,
|
|
208
|
+
commandMetadataFiles,
|
|
209
|
+
nativeBridgeFiles,
|
|
210
|
+
runtimePluginFiles,
|
|
211
|
+
applicationMenuFiles,
|
|
212
|
+
summary: {
|
|
213
|
+
commandMetadataFilesWithCommand: commandMetadataFiles.filter((entry) => entry.hasDevToolsCommand).map((entry) => entry.file),
|
|
214
|
+
nativeBridgeFilesWithRequest: nativeBridgeFiles.filter((entry) => entry.hasDevToolsOpenRequest).map((entry) => entry.file),
|
|
215
|
+
runtimePluginFilesWithCommand: runtimePluginFiles.filter((entry) => entry.hasDevToolsCommand).map((entry) => entry.file),
|
|
216
|
+
applicationMenuFilesWithDiagnostics: applicationMenuFiles.filter((entry) => entry.hasDiagnosticsHook).map((entry) => entry.file),
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
159
221
|
function formatAsarListResult(result) {
|
|
160
222
|
return result.files.length > 0 ? `${result.files.join("\n")}\n` : "";
|
|
161
223
|
}
|
|
@@ -164,6 +226,34 @@ function formatAsarCatResult(result) {
|
|
|
164
226
|
return result.content;
|
|
165
227
|
}
|
|
166
228
|
|
|
229
|
+
function formatMenuDiagnosticsResult(result) {
|
|
230
|
+
const lines = [
|
|
231
|
+
`ASAR: ${result.asar}`,
|
|
232
|
+
`Command: ${result.commandId}`,
|
|
233
|
+
"",
|
|
234
|
+
"Command metadata bundles:",
|
|
235
|
+
...result.commandMetadataFiles.map((entry) =>
|
|
236
|
+
`- ${entry.file}: command=${entry.hasDevToolsCommand ? "yes" : "no"}, title=${entry.hasMenuTitle ? "yes" : "no"}, bottomPanel=${entry.hasToggleBottomPanel ? "yes" : "no"}, panels=${entry.hasPanelsGroup ? "yes" : "no"}`,
|
|
237
|
+
),
|
|
238
|
+
"",
|
|
239
|
+
"Native bridge bundles:",
|
|
240
|
+
...result.nativeBridgeFiles.map((entry) =>
|
|
241
|
+
`- ${entry.file}: request=${entry.hasDevToolsOpenRequest ? "yes" : "no"}, openDevTools=${entry.hasOpenDevToolsCall ? "yes" : "no"}`,
|
|
242
|
+
),
|
|
243
|
+
"",
|
|
244
|
+
"Runtime plugin bundles:",
|
|
245
|
+
...result.runtimePluginFiles.map((entry) =>
|
|
246
|
+
`- ${entry.file}: command=${entry.hasDevToolsCommand ? "yes" : "no"}, request=${entry.hasDevToolsOpenRequest ? "yes" : "no"}`,
|
|
247
|
+
),
|
|
248
|
+
"",
|
|
249
|
+
"Application menu bundles:",
|
|
250
|
+
...result.applicationMenuFiles.map((entry) =>
|
|
251
|
+
`- ${entry.file}: diagnosticsHook=${entry.hasDiagnosticsHook ? "yes" : "no"}, command=${entry.hasDevToolsCommand ? "yes" : "no"}`,
|
|
252
|
+
),
|
|
253
|
+
];
|
|
254
|
+
return `${lines.join("\n")}\n`;
|
|
255
|
+
}
|
|
256
|
+
|
|
167
257
|
function formatError(error, { debug = false } = {}) {
|
|
168
258
|
if (debug || process.env.CODEX_PLUS_PATCHER_DEBUG === "1") return error.stack || error.message || String(error);
|
|
169
259
|
return `Error: ${error.message || String(error)}`;
|
|
@@ -232,6 +322,11 @@ async function main() {
|
|
|
232
322
|
process.stdout.write(args.json ? `${JSON.stringify(result, null, 2)}\n` : formatAsarCatResult(result));
|
|
233
323
|
return;
|
|
234
324
|
}
|
|
325
|
+
if (args.command === "menu-diagnostics") {
|
|
326
|
+
const result = menuDiagnostics(args);
|
|
327
|
+
process.stdout.write(args.json ? `${JSON.stringify(result, null, 2)}\n` : formatMenuDiagnosticsResult(result));
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
235
330
|
if (args.command !== "apply") throw new Error(`Unknown command: ${args.command}`);
|
|
236
331
|
|
|
237
332
|
const patchSets = await loadPatchSets(args);
|
|
@@ -266,10 +361,12 @@ module.exports = {
|
|
|
266
361
|
formatAsarCatResult,
|
|
267
362
|
formatAsarListResult,
|
|
268
363
|
formatError,
|
|
364
|
+
formatMenuDiagnosticsResult,
|
|
269
365
|
formatResult,
|
|
270
366
|
helpText,
|
|
271
367
|
listAsarFiles,
|
|
272
368
|
loadPatchSets,
|
|
369
|
+
menuDiagnostics,
|
|
273
370
|
parseArgs,
|
|
274
371
|
readAsarFile,
|
|
275
372
|
requirePatchSetModule,
|
|
@@ -15,6 +15,8 @@ module.exports = buildCodexPlusPatchSet({
|
|
|
15
15
|
"threadSidePanelTabs": "webview/assets/thread-side-panel-tabs-D0dd27Zf.js",
|
|
16
16
|
"userMessageAttachments": "webview/assets/user-message-attachments-CgyXEK9U.js",
|
|
17
17
|
"composer": "webview/assets/composer-CCuv6v-2.js",
|
|
18
|
+
"localActiveWorkspaceRootDropdown": "webview/assets/local-active-workspace-root-dropdown-ymhXI2RF.js",
|
|
19
|
+
"runCommand": "webview/assets/run-command-D6apgII3.js",
|
|
18
20
|
"localTaskRow": "webview/assets/local-task-row-vTrSC6Rc.js",
|
|
19
21
|
"keyboardShortcutsSearchInput": "webview/assets/keyboard-shortcuts-search-input-DjVpifwp.js",
|
|
20
22
|
"src": "src-C7fSIbpz.js",
|
|
@@ -15,6 +15,8 @@ module.exports = buildCodexPlusPatchSet({
|
|
|
15
15
|
"threadSidePanelTabs": "webview/assets/thread-side-panel-tabs-D0dd27Zf.js",
|
|
16
16
|
"userMessageAttachments": "webview/assets/user-message-attachments-CgyXEK9U.js",
|
|
17
17
|
"composer": "webview/assets/composer-CCuv6v-2.js",
|
|
18
|
+
"localActiveWorkspaceRootDropdown": "webview/assets/local-active-workspace-root-dropdown-ymhXI2RF.js",
|
|
19
|
+
"runCommand": "webview/assets/run-command-D6apgII3.js",
|
|
18
20
|
"localTaskRow": "webview/assets/local-task-row-vTrSC6Rc.js",
|
|
19
21
|
"keyboardShortcutsSearchInput": "webview/assets/keyboard-shortcuts-search-input-DjVpifwp.js",
|
|
20
22
|
"src": "src-C7fSIbpz.js",
|
|
@@ -11,10 +11,16 @@ module.exports = buildCodexPlusPatchSet({
|
|
|
11
11
|
"appShell": "webview/assets/app-shell-0b-x_r3Z.js",
|
|
12
12
|
"errorBoundary": "webview/assets/error-boundary-BOla93vo.js",
|
|
13
13
|
"generalSettings": "webview/assets/general-settings-U7DFIZBC.js",
|
|
14
|
+
"header": "webview/assets/header-DgzE38hF.js",
|
|
15
|
+
"threadPageHeader": "webview/assets/thread-page-header-D_hZ50OA.js",
|
|
16
|
+
"localConversationPage": "webview/assets/local-conversation-page-dVDt8SxG.js",
|
|
17
|
+
"threadContext": "webview/assets/thread-context-B0hBrRyZ.js",
|
|
14
18
|
"sidebarProjectHoverCardSourceRows": "webview/assets/sidebar-project-hover-card-source-rows-DtE7St1r.js",
|
|
15
19
|
"threadSidePanelTabs": "webview/assets/thread-side-panel-tabs-CLuB2SaS.js",
|
|
16
20
|
"userMessageAttachments": "webview/assets/user-message-attachments-5G1ZKim-.js",
|
|
17
21
|
"composer": "webview/assets/composer-DlMDPaCL.js",
|
|
22
|
+
"localActiveWorkspaceRootDropdown": "webview/assets/local-active-workspace-root-dropdown-B28GluSz.js",
|
|
23
|
+
"runCommand": "webview/assets/run-command-B0E8hx7Q.js",
|
|
18
24
|
"localTaskRow": "webview/assets/local-task-row-CoPNn6SW.js",
|
|
19
25
|
"mermaidDiagramShell": "webview/assets/mermaid-diagram-shell-BO-t9BGx.js",
|
|
20
26
|
"keyboardShortcutsSearchInput": "webview/assets/keyboard-shortcuts-search-input-C1dmntOi.js",
|
|
@@ -7,14 +7,21 @@ module.exports = buildCodexPlusPatchSet({
|
|
|
7
7
|
"asarSha256": "7f45c6a6bad9c6fabe2226e8f7e0aae3792eca8c59f24305b5f2996ee4b37e40",
|
|
8
8
|
"files": {
|
|
9
9
|
"main": ".vite/build/main-dSxbxAhH.js",
|
|
10
|
+
"electronCommandSource": ".vite/build/src-DBVh5FZA.js",
|
|
10
11
|
"appMain": "webview/assets/app-main-Dldh3K_n.js",
|
|
11
12
|
"appShell": "webview/assets/app-shell-0b-x_r3Z.js",
|
|
12
13
|
"errorBoundary": "webview/assets/error-boundary-BOla93vo.js",
|
|
13
14
|
"generalSettings": "webview/assets/general-settings-U7DFIZBC.js",
|
|
15
|
+
"header": "webview/assets/header-DgzE38hF.js",
|
|
16
|
+
"threadPageHeader": "webview/assets/thread-page-header-D_hZ50OA.js",
|
|
17
|
+
"localConversationPage": "webview/assets/local-conversation-page-dVDt8SxG.js",
|
|
18
|
+
"threadContext": "webview/assets/thread-context-B0hBrRyZ.js",
|
|
14
19
|
"sidebarProjectHoverCardSourceRows": "webview/assets/sidebar-project-hover-card-source-rows-DtE7St1r.js",
|
|
15
20
|
"threadSidePanelTabs": "webview/assets/thread-side-panel-tabs-CLuB2SaS.js",
|
|
16
21
|
"userMessageAttachments": "webview/assets/user-message-attachments-5G1ZKim-.js",
|
|
17
22
|
"composer": "webview/assets/composer-DlMDPaCL.js",
|
|
23
|
+
"localActiveWorkspaceRootDropdown": "webview/assets/local-active-workspace-root-dropdown-B28GluSz.js",
|
|
24
|
+
"runCommand": "webview/assets/run-command-B0E8hx7Q.js",
|
|
18
25
|
"localTaskRow": "webview/assets/local-task-row-CoPNn6SW.js",
|
|
19
26
|
"mermaidDiagramShell": "webview/assets/mermaid-diagram-shell-BO-t9BGx.js",
|
|
20
27
|
"keyboardShortcutsSearchInput": "webview/assets/keyboard-shortcuts-search-input-C1dmntOi.js",
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const { codexPlusRuntimeAssets } = require("../../runtime/assets");
|
|
2
2
|
const { replaceOnce } = require("./replace");
|
|
3
3
|
const { makePatchSet } = require("./make-patch-set");
|
|
4
|
+
const {
|
|
5
|
+
patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut,
|
|
6
|
+
patchRunCommandProjectSelectorShortcut,
|
|
7
|
+
} = require("./project-selector-shortcut-patch");
|
|
4
8
|
|
|
5
9
|
function buildCodexPlusPatchSet(config) {
|
|
6
10
|
const oldTitle = "<title>Codex</title>";
|
|
@@ -11,14 +15,22 @@ function buildCodexPlusPatchSet(config) {
|
|
|
11
15
|
const files = config.files;
|
|
12
16
|
const anchors = config.anchors;
|
|
13
17
|
const mainFile = files.main;
|
|
18
|
+
const electronCommandSourceFile = files.electronCommandSource;
|
|
14
19
|
const appMainFile = files.appMain;
|
|
15
20
|
const appShellFile = files.appShell;
|
|
16
21
|
const errorBoundaryFile = files.errorBoundary;
|
|
17
22
|
const generalSettingsFile = files.generalSettings;
|
|
18
23
|
const sidebarProjectHoverCardSourceRowsFile = files.sidebarProjectHoverCardSourceRows;
|
|
24
|
+
const headerFile = files.header;
|
|
25
|
+
const threadPageHeaderFile = files.threadPageHeader;
|
|
26
|
+
const localConversationPageFile = files.localConversationPage;
|
|
27
|
+
const threadContextFile = files.threadContext;
|
|
28
|
+
const threadContextImportFile = threadContextFile?.split("/").pop();
|
|
19
29
|
const threadSidePanelTabsFile = files.threadSidePanelTabs;
|
|
20
30
|
const userMessageAttachmentsFile = files.userMessageAttachments;
|
|
21
31
|
const composerFile = files.composer;
|
|
32
|
+
const localActiveWorkspaceRootDropdownFile = files.localActiveWorkspaceRootDropdown;
|
|
33
|
+
const runCommandFile = files.runCommand;
|
|
22
34
|
const localTaskRowFile = files.localTaskRow;
|
|
23
35
|
const mermaidDiagramShellFile = files.mermaidDiagramShell;
|
|
24
36
|
const electronMenuShortcutsFile = files.electronMenuShortcuts;
|
|
@@ -133,8 +145,11 @@ function CPXDiagnosticDetails(e){return window.CodexPlus?.ui?.errors?.renderDeta
|
|
|
133
145
|
const codexPlusMermaidHelpers = `
|
|
134
146
|
function CPXMermaidDiagramProps(e){return window.CodexPlus?.ui?.mermaid?.diagramProps?.(e)}`;
|
|
135
147
|
|
|
148
|
+
const codexPlusThreadHeaderHelpers = `
|
|
149
|
+
function CPXThreadHeaderAccessories(e){return window.CodexPlus?.ui?.threadHeader?.renderAccessories?.(e)??null}`;
|
|
150
|
+
|
|
136
151
|
const codexPlusNativeMainHelpers = `
|
|
137
|
-
function CPXOpenMermaidViewer(e){let t=e?.html;if(typeof t!==\`string\`||t.length===0)return{ok:!1};let n=(0,s.join)((0,o.tmpdir)(),\`codex-plus-mermaid-\${(0,u.randomUUID)()}.html\`);(0,l.writeFileSync)(n,t,\`utf8\`);let r=new a.BrowserWindow({height:900,resizable:!0,show:!0,title:\`Mermaid diagram viewer\`,webPreferences:{contextIsolation:!0,nodeIntegration:!1,sandbox:!0},width:1400});return r.webContents.setWindowOpenHandler(e=>{try{let t=new URL(e.url);if(t.protocol===\`https:\`&&t.hostname===\`mermaid.live\`)a.shell.openExternal(e.url)}catch{}return{action:\`deny\`}}),r.on(\`closed\`,()=>{try{(0,l.unlinkSync)(n)}catch{}}),r.loadURL((0,S.pathToFileURL)(n).toString()).catch(()=>{}),{ok:!0}}function CPXRegisterNativeRequest(e){return a.ipcMain.handle(\`codex_plus:native-request\`,async(t,n)=>{if(!e.isTrustedIpcEvent(t))return{ok:!1};switch(n?.method){case\`mermaid/openViewer\`:return CPXOpenMermaidViewer(n.params);default:return{ok:!1}}})}`;
|
|
152
|
+
let CPXNativeMenuItems=[],CPXRefreshApplicationMenu=null;function CPXMenuSnapshot(e){return e?.items?.map(e=>({id:e.id,label:e.label,enabled:e.enabled,visible:e.visible,accelerator:e.accelerator,submenu:CPXMenuSnapshot(e.submenu)}))}function CPXLogMenuDiagnostics(){try{let e=CPXMenuSnapshot(a.Menu.getApplicationMenu())??[],t=JSON.stringify(e),n=t.includes(\`codexPlusOpenDevTools\`)||t.includes(\`Open Developer Tools\`);if(process.env.CODEX_PLUS_MENU_DIAGNOSTICS===\`1\`||!n)console.log(\`[Codex Plus menu diagnostics] \${JSON.stringify({hasOpenDeveloperTools:n,menu:e})}\`)}catch(e){console.log(\`[Codex Plus menu diagnostics] \${JSON.stringify({error:String(e?.message??e)})}\`)}}function CPXOpenDevTools(e){try{let t=e?.sender;if(typeof t?.openDevTools!==\`function\`)return{ok:!1};return t.openDevTools(),{ok:!0}}catch{return{ok:!1}}}function CPXFocusedEvent(){let e=a.BrowserWindow.getFocusedWindow();return e&&!e.isDestroyed()?{sender:e.webContents}:null}function CPXRunNativeMenuRequest(e){switch(e?.method){case\`devtools/open\`:return CPXOpenDevTools(CPXFocusedEvent());default:return{ok:!1}}}function CPXNativeMenuTemplateItems(e){return CPXNativeMenuItems.filter(t=>t.menuId===e).map(e=>({id:e.id,label:e.label,click:()=>{CPXRunNativeMenuRequest(e.nativeRequest)}}))}function CPXRegisterNativeMenuItem(e){if(e?.id==null||e?.menuId==null||e?.label==null||e?.nativeRequest?.method==null)return{ok:!1};let t={id:String(e.id),menuId:String(e.menuId),label:String(e.label),nativeRequest:{method:String(e.nativeRequest.method),params:e.nativeRequest.params},afterId:e.afterId==null?null:String(e.afterId),afterLabel:e.afterLabel==null?null:String(e.afterLabel)};CPXNativeMenuItems=CPXNativeMenuItems.filter(e=>e.id!==t.id),CPXNativeMenuItems.push(t);try{CPXRefreshApplicationMenu?.()}catch{}return CPXLogMenuDiagnostics(),{ok:!0}}function CPXOpenMermaidViewer(e){let t=e?.html;if(typeof t!==\`string\`||t.length===0)return{ok:!1};let n=(0,s.join)((0,o.tmpdir)(),\`codex-plus-mermaid-\${(0,u.randomUUID)()}.html\`);(0,l.writeFileSync)(n,t,\`utf8\`);let r=new a.BrowserWindow({height:900,resizable:!0,show:!0,title:\`Mermaid diagram viewer\`,webPreferences:{contextIsolation:!0,nodeIntegration:!1,sandbox:!0},width:1400});return r.webContents.setWindowOpenHandler(e=>{try{let t=new URL(e.url);if(t.protocol===\`https:\`&&t.hostname===\`mermaid.live\`)a.shell.openExternal(e.url)}catch{}return{action:\`deny\`}}),r.on(\`closed\`,()=>{try{(0,l.unlinkSync)(n)}catch{}}),r.loadURL((0,S.pathToFileURL)(n).toString()).catch(()=>{}),{ok:!0}}function CPXRegisterNativeRequest(e){return a.ipcMain.handle(\`codex_plus:native-request\`,async(t,n)=>{if(!e.isTrustedIpcEvent(t))return{ok:!1};switch(n?.method){case\`native-menu/register-item\`:return CPXRegisterNativeMenuItem(n.params);case\`devtools/open\`:return CPXOpenDevTools(t);case\`mermaid/openViewer\`:return CPXOpenMermaidViewer(n.params);default:return{ok:!1}}})}`;
|
|
138
153
|
|
|
139
154
|
function patchThreadSidePanelTabs(text) {
|
|
140
155
|
let patched = replaceOnce(
|
|
@@ -384,6 +399,91 @@ function patchSidebarProjectHoverCardSourceRows(text) {
|
|
|
384
399
|
);
|
|
385
400
|
}
|
|
386
401
|
|
|
402
|
+
function patchHeader(text) {
|
|
403
|
+
let patched = replaceOnce(
|
|
404
|
+
text,
|
|
405
|
+
`import{Z as r,a as i,s as a}from"./app-scope-CWE-zIhQ.js";`,
|
|
406
|
+
`import{Z as r,a as i,a as CPX_readAtom,s as a}from"./app-scope-CWE-zIhQ.js";`,
|
|
407
|
+
"thread header atom reader alias import anchor",
|
|
408
|
+
);
|
|
409
|
+
patched = replaceOnce(
|
|
410
|
+
patched,
|
|
411
|
+
`import{t as ee}from"./tooltip-B-u9JAuV.js";`,
|
|
412
|
+
`import{t as ee,t as CPX_Tooltip}from"./tooltip-B-u9JAuV.js";`,
|
|
413
|
+
"thread header tooltip alias import anchor",
|
|
414
|
+
);
|
|
415
|
+
patched = replaceOnce(
|
|
416
|
+
patched,
|
|
417
|
+
`import{t as _e}from"./dock-DAmmeMut.js";`,
|
|
418
|
+
`import{t as _e}from"./dock-DAmmeMut.js";import{n as CPX_headerCwd,i as CPX_headerHostId}from"./${threadContextImportFile}";`,
|
|
419
|
+
"thread header context import anchor",
|
|
420
|
+
);
|
|
421
|
+
patched = replaceOnce(
|
|
422
|
+
patched,
|
|
423
|
+
"function lt(e){let t=(0,Z.c)(68),",
|
|
424
|
+
`${codexPlusThreadHeaderHelpers}function lt(e){let t=(0,Z.c)(72),`,
|
|
425
|
+
"thread header accessory helper insertion anchor",
|
|
426
|
+
);
|
|
427
|
+
patched = replaceOnce(
|
|
428
|
+
patched,
|
|
429
|
+
"let C;t[36]!==c||t[37]!==g||t[38]!==i?(C=(0,Q.jsx)(`div`,{className:`mr-3 line-clamp-1 flex min-w-0 flex-1 items-center gap-1 truncate`,style:{viewTransitionName:`header-title`},children:i?(0,Q.jsxs)(`div`,{className:`flex min-w-0 flex-1 items-center gap-1`,children:[(0,Q.jsx)(mt,{onClick:c}),(0,Q.jsx)(x,{color:`ghostActive`,type:`button`,onClick:u,className:`min-w-0 flex-1 truncate !px-0 !py-0 text-left text-sm text-token-foreground hover:!bg-transparent hover:opacity-80 electron:font-medium`,children:(0,Q.jsx)(`span`,{className:`truncate`,children:i})})]}):(0,Q.jsx)(`span`,{className:`text-token-description-foreground`,children:(0,Q.jsx)(pt,{mergedTasks:g,onBack:c,showBackButton:!0})})}),t[36]=c,t[37]=g,t[38]=i,t[39]=C):C=t[39];",
|
|
430
|
+
"let CPX_headerContext={cwd:CPX_readAtom(CPX_headerCwd),hostId:CPX_readAtom(CPX_headerHostId)},CPX_headerAccessories=CPXThreadHeaderAccessories({context:CPX_headerContext,deps:{jsx:Q.jsx,jsxs:Q.jsxs,Tooltip:CPX_Tooltip}});let C;t[36]!==c||t[37]!==g||t[38]!==i||t[68]!==CPX_headerAccessories?(C=(0,Q.jsx)(`div`,{className:`mr-3 line-clamp-1 flex min-w-0 flex-1 items-center gap-1 truncate`,style:{viewTransitionName:`header-title`},children:i?(0,Q.jsxs)(`div`,{className:`flex min-w-0 flex-1 items-center gap-1`,children:[(0,Q.jsx)(mt,{onClick:c}),(0,Q.jsx)(x,{color:`ghostActive`,type:`button`,onClick:u,className:`min-w-0 flex-1 truncate !px-0 !py-0 text-left text-sm text-token-foreground hover:!bg-transparent hover:opacity-80 electron:font-medium`,children:(0,Q.jsx)(`span`,{className:`truncate`,children:i})}),CPX_headerAccessories]}):(0,Q.jsx)(`span`,{className:`text-token-description-foreground`,children:(0,Q.jsx)(pt,{mergedTasks:g,onBack:c,showBackButton:!0})})}),t[36]=c,t[37]=g,t[38]=i,t[68]=CPX_headerAccessories,t[39]=C):C=t[39];",
|
|
431
|
+
"thread header accessory render anchor",
|
|
432
|
+
);
|
|
433
|
+
patched = replaceOnce(
|
|
434
|
+
patched,
|
|
435
|
+
"t[53]!==A||t[54]!==b||t[55]!==S||t[56]!==C?(M=(0,Q.jsxs)(`div`,{className:b,children:[S,C,A]}),t[53]=A,t[54]=b,t[55]=S,t[56]=C,t[57]=M):M=t[57]",
|
|
436
|
+
"t[53]!==A||t[54]!==b||t[55]!==S||t[56]!==C?(M=(0,Q.jsxs)(`div`,{className:b,children:[S,C,A]}),t[53]=A,t[54]=b,t[55]=S,t[56]=C,t[57]=M):M=t[57]",
|
|
437
|
+
"thread header accessory mount anchor",
|
|
438
|
+
);
|
|
439
|
+
return patched;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function patchThreadPageHeader(text) {
|
|
443
|
+
let patched = text;
|
|
444
|
+
patched = replaceOnce(
|
|
445
|
+
patched,
|
|
446
|
+
"function c(e){let t=(0,o.c)(21),",
|
|
447
|
+
`${codexPlusThreadHeaderHelpers}function c(e){let t=(0,o.c)(24),`,
|
|
448
|
+
"thread page header helper insertion anchor",
|
|
449
|
+
);
|
|
450
|
+
patched = replaceOnce(
|
|
451
|
+
patched,
|
|
452
|
+
"let t=(0,o.c)(24),{start:c,startActions:l,env:u,secondary:d,trailing:f,hostConfig:p}=e,m;",
|
|
453
|
+
"let t=(0,o.c)(24),{start:c,startActions:l,env:u,secondary:d,trailing:f,hostConfig:p,cwd:CPX_headerCwd}=e,CPX_headerContext={cwd:CPX_headerCwd,hostId:p?.id??null,header:{env:u,hostDisplayName:p?.display_name??null,startText:typeof c==`string`?c:null,secondaryText:typeof d==`string`?d:null,hasTrailing:f!=null}},CPX_headerAccessories=CPXThreadHeaderAccessories({context:CPX_headerContext,deps:{jsx:s.jsx,jsxs:s.jsxs}}),m;",
|
|
454
|
+
"thread page header accessory render anchor",
|
|
455
|
+
);
|
|
456
|
+
patched = replaceOnce(
|
|
457
|
+
patched,
|
|
458
|
+
"t[8]!==l||t[9]!==v||t[10]!==y||t[11]!==b?(x=(0,s.jsxs)(`div`,{className:`text-md flex min-w-0 items-center gap-2 truncate text-base electron:font-medium`,children:[v,y,b,l]}),t[8]=l,t[9]=v,t[10]=y,t[11]=b,t[12]=x):x=t[12]",
|
|
459
|
+
"t[8]!==l||t[9]!==v||t[10]!==y||t[11]!==b||t[21]!==CPX_headerAccessories?(x=(0,s.jsxs)(`div`,{className:`text-md flex min-w-0 items-center gap-2 truncate text-base electron:font-medium`,children:[v,y,b,CPX_headerAccessories,l]}),t[8]=l,t[9]=v,t[10]=y,t[11]=b,t[21]=CPX_headerAccessories,t[12]=x):x=t[12]",
|
|
460
|
+
"thread page header accessory mount anchor",
|
|
461
|
+
);
|
|
462
|
+
return patched;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function patchLocalConversationPageHeader(text) {
|
|
466
|
+
let patched = replaceOnce(
|
|
467
|
+
text,
|
|
468
|
+
"function Tt(e){let t=(0,Y.c)(42),",
|
|
469
|
+
`${codexPlusThreadHeaderHelpers}function Tt(e){let t=(0,Y.c)(45),`,
|
|
470
|
+
"local conversation header helper insertion anchor",
|
|
471
|
+
);
|
|
472
|
+
patched = replaceOnce(
|
|
473
|
+
patched,
|
|
474
|
+
"let t=(0,Y.c)(45),{conversationId:n,getConversationMarkdown:r,markdownParentConversationId:a,title:o,titleSuffix:s,cwd:c,canPin:l,hideProjectMetadata:d,hideForkActions:f}=e,p=l===void 0?!0:l,m=d===void 0?!1:d,h=A(),g;",
|
|
475
|
+
"let t=(0,Y.c)(45),{conversationId:n,getConversationMarkdown:r,markdownParentConversationId:a,title:o,titleSuffix:s,cwd:c,canPin:l,hideProjectMetadata:d,hideForkActions:f}=e,CPX_headerContext={cwd:c,hostId:u(i(O,n)).id,header:{surface:`local-conversation`,titleText:typeof o==`string`?o:null}},CPX_headerAccessories=CPXThreadHeaderAccessories({context:CPX_headerContext,deps:{jsx:Z.jsx,jsxs:Z.jsxs}}),p=l===void 0?!0:l,m=d===void 0?!1:d,h=A(),g;",
|
|
476
|
+
"local conversation header accessory render anchor",
|
|
477
|
+
);
|
|
478
|
+
patched = replaceOnce(
|
|
479
|
+
patched,
|
|
480
|
+
"t[38]!==F||t[39]!==I||t[40]!==L?(z=(0,Z.jsx)(`div`,{className:`draggable grid w-full min-w-0 grid-cols-[minmax(0,1fr)] items-center gap-x-4 electron:h-toolbar extension:py-row-y`,children:(0,Z.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 truncate text-base electron:font-medium`,children:[F,I,L,R]})}),t[38]=F,t[39]=I,t[40]=L,t[41]=z):z=t[41]",
|
|
481
|
+
"t[38]!==F||t[39]!==I||t[40]!==L||t[42]!==CPX_headerAccessories?(z=(0,Z.jsx)(`div`,{className:`draggable grid w-full min-w-0 grid-cols-[minmax(0,1fr)] items-center gap-x-4 electron:h-toolbar extension:py-row-y`,children:(0,Z.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 truncate text-base electron:font-medium`,children:[F,I,L,CPX_headerAccessories,R]})}),t[38]=F,t[39]=I,t[40]=L,t[42]=CPX_headerAccessories,t[41]=z):z=t[41]",
|
|
482
|
+
"local conversation header accessory mount anchor",
|
|
483
|
+
);
|
|
484
|
+
return patched;
|
|
485
|
+
}
|
|
486
|
+
|
|
387
487
|
const codexPlusProjectColorHelpers = `
|
|
388
488
|
function CPXHostProjectRowProps(e){return window.CodexPlus?.ui?.sidebar?.projectRowProps?.({project:e})}function CPXHostThreadRowProps(e){return window.CodexPlus?.ui?.sidebar?.threadRowProps?.({project:e})}function CPXHostUserBubbleProps(e){return window.CodexPlus?.ui?.message?.userBubbleProps?.(e)}function CPXHostComposerSurfaceProps(e){return window.CodexPlus?.ui?.composer?.surfaceProps?.(e)}`;
|
|
389
489
|
|
|
@@ -497,7 +597,7 @@ function patchElectronMenuShortcuts(text) {
|
|
|
497
597
|
return replaceOnce(
|
|
498
598
|
text,
|
|
499
599
|
"{id:`toggleSidebar`,titleIntlId:`codex.command.toggleSidebar`,descriptionIntlId:`codex.commandDescription.toggleSidebar`,commandMenuGroupKey:`panels`,commandMenu:!0,electron:{menuTitle:`Toggle Sidebar`,menuTitleIntlId:`codex.commandMenuTitle.toggleSidebar`,defaultKeybindings:[{key:`CmdOrCtrl+B`}]}},{id:`toggleBottomPanel`,",
|
|
500
|
-
"{id:`toggleSidebar`,titleIntlId:`codex.command.toggleSidebar`,descriptionIntlId:`codex.commandDescription.toggleSidebar`,commandMenuGroupKey:`panels`,commandMenu:!0,electron:{menuTitle:`Toggle Sidebar`,menuTitleIntlId:`codex.commandMenuTitle.toggleSidebar`,defaultKeybindings:[{key:`CmdOrCtrl+B`}]}},...(window.CodexPlus?.ui?.commands?.commandMetadata?.()??[]),{id:`toggleBottomPanel`,",
|
|
600
|
+
"{id:`toggleSidebar`,titleIntlId:`codex.command.toggleSidebar`,descriptionIntlId:`codex.commandDescription.toggleSidebar`,commandMenuGroupKey:`panels`,commandMenu:!0,electron:{menuTitle:`Toggle Sidebar`,menuTitleIntlId:`codex.commandMenuTitle.toggleSidebar`,defaultKeybindings:[{key:`CmdOrCtrl+B`}]}},{id:`codexPlus.focusProjectSelector`,title:`Focus project selector`,description:`Focus or open the new chat project selector`,commandMenuGroupKey:`workspace`,commandMenu:!0,electron:{menuTitle:`Focus project selector`,defaultKeybindings:[{key:`CmdOrCtrl+.`}]}},...(window.CodexPlus?.ui?.commands?.commandMetadata?.()?.filter?.(e=>e.id!==`codexPlus.focusProjectSelector`)??[]),{id:`toggleBottomPanel`,",
|
|
501
601
|
"sidebar blur command palette metadata anchor",
|
|
502
602
|
);
|
|
503
603
|
}
|
|
@@ -583,6 +683,27 @@ function patchMainNativeBridge(text) {
|
|
|
583
683
|
);
|
|
584
684
|
}
|
|
585
685
|
|
|
686
|
+
function patchMainMenuDiagnostics(text) {
|
|
687
|
+
let patched = replaceOnce(
|
|
688
|
+
text,
|
|
689
|
+
"He={...b(`toggleSidePanel`),click:async()=>{let e=await y();e&&_.sendMessageToWindow(e,{type:`toggle-diff-panel`})}},Ue=",
|
|
690
|
+
"He={...b(`toggleSidePanel`),click:async()=>{let e=await y();e&&_.sendMessageToWindow(e,{type:`toggle-diff-panel`})}},Ue=",
|
|
691
|
+
"codex plus menu template helper presence anchor",
|
|
692
|
+
);
|
|
693
|
+
patched = replaceOnce(
|
|
694
|
+
patched,
|
|
695
|
+
"He,We,{type:`separator`}",
|
|
696
|
+
"He,We,...CPXNativeMenuTemplateItems(`view-menu`),{type:`separator`}",
|
|
697
|
+
"codex plus view menu template items anchor",
|
|
698
|
+
);
|
|
699
|
+
return replaceOnce(
|
|
700
|
+
patched,
|
|
701
|
+
"me.refreshApplicationMenu(),w(`application menu refreshed`,A),",
|
|
702
|
+
"CPXRefreshApplicationMenu=()=>me.refreshApplicationMenu(),me.refreshApplicationMenu(),CPXLogMenuDiagnostics(),w(`application menu refreshed`,A),",
|
|
703
|
+
"codex plus menu diagnostics refresh anchor",
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
|
|
586
707
|
return makePatchSet({
|
|
587
708
|
id: config.id,
|
|
588
709
|
codexVersion: config.codexVersion,
|
|
@@ -636,6 +757,14 @@ return makePatchSet({
|
|
|
636
757
|
[composerFile, patchComposerProjectColors],
|
|
637
758
|
],
|
|
638
759
|
},
|
|
760
|
+
...(headerFile ? [{
|
|
761
|
+
id: "project-path-header",
|
|
762
|
+
fileTransforms: [
|
|
763
|
+
[headerFile, patchHeader],
|
|
764
|
+
...(threadPageHeaderFile ? [[threadPageHeaderFile, patchThreadPageHeader]] : []),
|
|
765
|
+
...(localConversationPageFile ? [[localConversationPageFile, patchLocalConversationPageHeader]] : []),
|
|
766
|
+
],
|
|
767
|
+
}] : []),
|
|
639
768
|
{
|
|
640
769
|
id: "sidebar-name-blur",
|
|
641
770
|
fileTransforms: [
|
|
@@ -644,11 +773,19 @@ return makePatchSet({
|
|
|
644
773
|
[keyboardShortcutsSearchInputFile, patchKeyboardShortcutsSearchInput],
|
|
645
774
|
],
|
|
646
775
|
},
|
|
647
|
-
|
|
776
|
+
{
|
|
777
|
+
id: "project-selector-shortcut",
|
|
778
|
+
fileTransforms: [
|
|
779
|
+
[localActiveWorkspaceRootDropdownFile, patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut],
|
|
780
|
+
[runCommandFile, patchRunCommandProjectSelectorShortcut],
|
|
781
|
+
],
|
|
782
|
+
},
|
|
783
|
+
...(mainFile ? [{
|
|
648
784
|
id: "codex-plus-native-bridge",
|
|
649
785
|
fileTransforms: [
|
|
650
786
|
[preloadFile, patchPreloadNativeBridge],
|
|
651
787
|
[mainFile, patchMainNativeBridge],
|
|
788
|
+
...(electronCommandSourceFile ? [[mainFile, patchMainMenuDiagnostics]] : []),
|
|
652
789
|
],
|
|
653
790
|
}] : []),
|
|
654
791
|
...(mermaidDiagramShellFile ? [{
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const { replaceOnce } = require("./replace");
|
|
2
|
+
|
|
3
|
+
function patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut(text) {
|
|
4
|
+
let patched = replaceOnce(
|
|
5
|
+
text,
|
|
6
|
+
"Ne=r();function Pe(e){let t=(0,Ne.c)(42),",
|
|
7
|
+
"Ne=r();function CPXProjectSelectorFuzzyFilter(e,t){let n=String(t??``).trim().toLowerCase();return window.CodexPlus?.ui?.projectSelector?.fuzzyFilter?.(e,t)??(n?e.filter(e=>[e.label,e.repositoryData?.rootFolder??``,e.path??``,e.hostDisplayName??``].some(e=>String(e??``).toLowerCase().includes(n))):e)}function CPXProjectSelectorFuzzyHighlight(e,t){return window.CodexPlus?.ui?.projectSelector?.fuzzyHighlight?.({text:e,query:t,jsx:H.jsx})??e}function CPXProjectSelectorAcceptFirst(e,t,n,r){let i=t?.[0];if(e?.key!==`Enter`||String(r??``).trim().length===0||i==null)return;e.preventDefault?.(),e.stopPropagation?.(),n(i.projectId)}function Pe(e){let t=(0,Ne.c)(42),",
|
|
8
|
+
"project selector fuzzy search adapter insertion anchor",
|
|
9
|
+
);
|
|
10
|
+
patched = replaceOnce(
|
|
11
|
+
patched,
|
|
12
|
+
"let e=h.trim().toLowerCase();v=n.filter(t=>{if(!e)return!0;let n=t.repositoryData?.rootFolder??``;return[t.label,n,t.path??``,t.hostDisplayName??``].some(t=>t.toLowerCase().includes(e))});",
|
|
13
|
+
"v=CPXProjectSelectorFuzzyFilter(n,h);",
|
|
14
|
+
"project selector fuzzy search filter anchor",
|
|
15
|
+
);
|
|
16
|
+
patched = replaceOnce(
|
|
17
|
+
patched,
|
|
18
|
+
"S=(0,H.jsx)(ve,{value:h,onChange:o,placeholder:s,className:`mb-1`})",
|
|
19
|
+
"S=(0,H.jsx)(ve,{value:h,onChange:o,onKeyDown:e=>CPXProjectSelectorAcceptFirst(e,v,i,h),placeholder:s,className:`mb-1`})",
|
|
20
|
+
"project selector accept first match keydown anchor",
|
|
21
|
+
);
|
|
22
|
+
patched = replaceOnce(
|
|
23
|
+
patched,
|
|
24
|
+
"(0,H.jsx)(`span`,{className:`truncate`,children:e.label})",
|
|
25
|
+
"(0,H.jsx)(`span`,{className:`truncate`,children:CPXProjectSelectorFuzzyHighlight(e.label,h)})",
|
|
26
|
+
"project selector fuzzy search highlight anchor",
|
|
27
|
+
);
|
|
28
|
+
patched = replaceOnce(
|
|
29
|
+
patched,
|
|
30
|
+
"function Ie(e){let t=(0,Ne.c)(81),",
|
|
31
|
+
"function CPXProjectSelectorTrigger(e,t){return Me.isValidElement(e)?Me.cloneElement(e,{...e.props,\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":t}):e}function Ie(e){let t=(0,Ne.c)(81),",
|
|
32
|
+
"project selector shortcut helper insertion anchor",
|
|
33
|
+
);
|
|
34
|
+
return replaceOnce(
|
|
35
|
+
patched,
|
|
36
|
+
"at=(0,H.jsx)(ye,{open:f,onOpenChange:g,onCloseAutoFocus:Y,align:tt,disabled:O,triggerButton:X,contentWidth:`workspace`,contentMaxHeight:`tall`,children:$})",
|
|
37
|
+
"at=(0,H.jsx)(ye,{open:f,onOpenChange:g,onCloseAutoFocus:Y,align:tt,disabled:O,triggerButton:CPXProjectSelectorTrigger(X,k),contentWidth:`workspace`,contentMaxHeight:`tall`,children:$})",
|
|
38
|
+
"project selector shortcut final dropdown trigger anchor",
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function patchRunCommandProjectSelectorShortcut(text) {
|
|
43
|
+
return replaceOnce(
|
|
44
|
+
text,
|
|
45
|
+
"],[`openFolder`,()=>{r()}],[`toggleSidebar`,",
|
|
46
|
+
"],[`codexPlus.focusProjectSelector`,()=>{window.CodexPlus?.commands?.run?.(`codexPlus.focusProjectSelector`)}],[`openFolder`,()=>{r()}],[`toggleSidebar`,",
|
|
47
|
+
"project selector shortcut command dispatch anchor",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut,
|
|
53
|
+
patchRunCommandProjectSelectorShortcut,
|
|
54
|
+
};
|
package/src/runtime/assets.js
CHANGED
|
@@ -11,7 +11,11 @@ const runtimeFiles = [
|
|
|
11
11
|
["webview/assets/codex-plus/plugins/diagnosticErrors.js", "plugins/diagnosticErrors.js"],
|
|
12
12
|
["webview/assets/codex-plus/plugins/userBubbleColors.js", "plugins/userBubbleColors.js"],
|
|
13
13
|
["webview/assets/codex-plus/plugins/projectColors.js", "plugins/projectColors.js"],
|
|
14
|
+
["webview/assets/codex-plus/plugins/projectPathHeader.js", "plugins/projectPathHeader.js"],
|
|
14
15
|
["webview/assets/codex-plus/plugins/sidebarNameBlur.js", "plugins/sidebarNameBlur.js"],
|
|
16
|
+
["webview/assets/codex-plus/plugins/devTools.js", "plugins/devTools.js"],
|
|
17
|
+
["webview/assets/codex-plus/vendor/fzf.umd.js", "../../node_modules/fzf/dist/fzf.umd.js"],
|
|
18
|
+
["webview/assets/codex-plus/plugins/projectSelectorShortcut.js", "plugins/projectSelectorShortcut.js"],
|
|
15
19
|
["webview/assets/codex-plus/plugins/mermaidFullscreen.js", "plugins/mermaidFullscreen.js"],
|
|
16
20
|
];
|
|
17
21
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
const CodexPlus = window.CodexPlus;
|
|
3
|
+
CodexPlus.registerPlugin(
|
|
4
|
+
CodexPlus.definePlugin({
|
|
5
|
+
id: "devTools",
|
|
6
|
+
name: "Developer Tools",
|
|
7
|
+
description: "Registers the Open Developer Tools command.",
|
|
8
|
+
required: true,
|
|
9
|
+
commands: [
|
|
10
|
+
{
|
|
11
|
+
id: "codexPlusOpenDevTools",
|
|
12
|
+
title: "Open Developer Tools",
|
|
13
|
+
description: "Open DevTools for the current Codex window",
|
|
14
|
+
menu: { groups: ["panels"] },
|
|
15
|
+
palette: { enabled: true, keywords: ["devtools", "developer", "console"] },
|
|
16
|
+
shortcut: { defaultKeybindings: [] },
|
|
17
|
+
run() {
|
|
18
|
+
return CodexPlus.native.request("devtools/open").catch(() => ({ ok: false }));
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
start(api) {
|
|
23
|
+
api.nativeMenus.registerItem({
|
|
24
|
+
id: "codexPlusOpenDevTools",
|
|
25
|
+
menuId: "view-menu",
|
|
26
|
+
afterLabel: "Find",
|
|
27
|
+
label: "Open Developer Tools",
|
|
28
|
+
nativeRequest: { method: "devtools/open" },
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
})();
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
(function (globalObject) {
|
|
2
|
+
function pathFromContext(context) {
|
|
3
|
+
const value = context?.cwd ?? context?.project?.cwd ?? context?.project?.path ?? null;
|
|
4
|
+
if (typeof value !== "string") return "";
|
|
5
|
+
return value.trim();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function middleTruncate(value, maxLength = 46) {
|
|
9
|
+
const text = String(value || "");
|
|
10
|
+
if (text.length <= maxLength) return text;
|
|
11
|
+
if (maxLength <= 5) return text.slice(0, maxLength);
|
|
12
|
+
const keep = maxLength - 3;
|
|
13
|
+
const start = Math.ceil(keep / 2);
|
|
14
|
+
const end = Math.floor(keep / 2);
|
|
15
|
+
return `${text.slice(0, start)}...${text.slice(text.length - end)}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function formatPathLabel(value, maxLength = 54, tailSegments = 3) {
|
|
19
|
+
const text = String(value || "");
|
|
20
|
+
if (text.length <= maxLength) return text;
|
|
21
|
+
const parts = text.split("/").filter(Boolean);
|
|
22
|
+
const tail = parts.slice(-tailSegments).join("/");
|
|
23
|
+
if (!tail) return middleTruncate(text, maxLength);
|
|
24
|
+
const prefix = "…";
|
|
25
|
+
const label = `${prefix}/${tail}`;
|
|
26
|
+
return label.length <= maxLength ? label : `${prefix}/${parts.slice(-2).join("/")}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function copyPath(path) {
|
|
30
|
+
return globalObject?.navigator?.clipboard?.writeText?.(path);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function diagnose(event, details) {
|
|
34
|
+
globalObject?.CodexPlus?.diagnostics?.log?.(`projectPathHeader.${event}`, details);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ProjectPathAccessory({ context, jsx, jsxs, Tooltip }) {
|
|
38
|
+
const path = pathFromContext(context);
|
|
39
|
+
if (!path) {
|
|
40
|
+
diagnose("render.skip", {
|
|
41
|
+
reason: "missing-cwd",
|
|
42
|
+
contextKeys: context && typeof context === "object" ? Object.keys(context) : [],
|
|
43
|
+
});
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const label = formatPathLabel(path);
|
|
47
|
+
diagnose("render.chip", { path, label, tooltip: typeof Tooltip === "function" });
|
|
48
|
+
const chip = jsxs("div", {
|
|
49
|
+
"data-codex-plus-project-path-header": "",
|
|
50
|
+
className:
|
|
51
|
+
"no-drag ml-1 flex min-w-0 items-center gap-1 overflow-hidden rounded border border-token-border px-1.5 py-0.5 text-xs text-token-description-foreground",
|
|
52
|
+
style: { flexShrink: 999, maxWidth: "min(24rem, 28vw)" },
|
|
53
|
+
title: path,
|
|
54
|
+
children: [
|
|
55
|
+
jsx("span", { className: "min-w-0 truncate", children: label }),
|
|
56
|
+
jsx("button", {
|
|
57
|
+
type: "button",
|
|
58
|
+
className:
|
|
59
|
+
"flex h-4 w-4 shrink-0 items-center justify-center rounded text-token-input-placeholder-foreground hover:bg-token-list-hover-background hover:text-token-foreground",
|
|
60
|
+
"aria-label": "Copy project path",
|
|
61
|
+
title: "Copy project path",
|
|
62
|
+
onClick(event) {
|
|
63
|
+
event?.preventDefault?.();
|
|
64
|
+
event?.stopPropagation?.();
|
|
65
|
+
copyPath(path);
|
|
66
|
+
},
|
|
67
|
+
children: jsx("svg", {
|
|
68
|
+
"aria-hidden": "true",
|
|
69
|
+
className: "h-3 w-3",
|
|
70
|
+
fill: "none",
|
|
71
|
+
stroke: "currentColor",
|
|
72
|
+
strokeLinecap: "round",
|
|
73
|
+
strokeLinejoin: "round",
|
|
74
|
+
strokeWidth: "2",
|
|
75
|
+
viewBox: "0 0 24 24",
|
|
76
|
+
children: [
|
|
77
|
+
jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
78
|
+
jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" }),
|
|
79
|
+
],
|
|
80
|
+
}),
|
|
81
|
+
}),
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
if (typeof Tooltip === "function") return jsx(Tooltip, { tooltipContent: path, children: chip });
|
|
85
|
+
return chip;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const exportsObject = {
|
|
89
|
+
ProjectPathAccessory,
|
|
90
|
+
copyPath,
|
|
91
|
+
formatPathLabel,
|
|
92
|
+
middleTruncate,
|
|
93
|
+
pathFromContext,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
97
|
+
module.exports = exportsObject;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const CodexPlus = globalObject?.CodexPlus;
|
|
101
|
+
if (!CodexPlus) return;
|
|
102
|
+
|
|
103
|
+
CodexPlus.registerPlugin(
|
|
104
|
+
CodexPlus.definePlugin({
|
|
105
|
+
id: "projectPathHeader",
|
|
106
|
+
name: "Project Path Header",
|
|
107
|
+
description: "Shows the active project path in the thread header.",
|
|
108
|
+
required: true,
|
|
109
|
+
exports: exportsObject,
|
|
110
|
+
start(api) {
|
|
111
|
+
diagnose("start", { hasThreadHeader: Boolean(api.ui.threadHeader) });
|
|
112
|
+
api.ui.threadHeader.addAccessory(ProjectPathAccessory);
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
})(typeof window !== "undefined" ? window : globalThis);
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
const CodexPlus = window.CodexPlus;
|
|
3
|
+
const triggerSelector = "[data-codex-plus-project-selector-trigger]";
|
|
4
|
+
let keydownHandler = null;
|
|
5
|
+
|
|
6
|
+
function normalizeForFzf(value) {
|
|
7
|
+
const source = String(value ?? "");
|
|
8
|
+
const map = [];
|
|
9
|
+
let text = "";
|
|
10
|
+
let inSeparator = false;
|
|
11
|
+
|
|
12
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
13
|
+
const char = source[index];
|
|
14
|
+
if (/[\s-]/.test(char)) {
|
|
15
|
+
if (!inSeparator) {
|
|
16
|
+
text += " ";
|
|
17
|
+
map.push(index);
|
|
18
|
+
inSeparator = true;
|
|
19
|
+
}
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
text += char;
|
|
23
|
+
map.push(index);
|
|
24
|
+
inSeparator = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { map, text };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function projectSearchText(project) {
|
|
31
|
+
return [
|
|
32
|
+
project?.label,
|
|
33
|
+
project?.repositoryData?.rootFolder,
|
|
34
|
+
project?.path,
|
|
35
|
+
project?.hostDisplayName,
|
|
36
|
+
].map((value) => normalizeForFzf(value).text.trim()).filter(Boolean).join(" ");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function fzfConstructor() {
|
|
40
|
+
return window.fzf?.Fzf;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function fallbackFilter(items, query) {
|
|
44
|
+
const needle = normalizeForFzf(query).text.trim().toLowerCase();
|
|
45
|
+
if (!needle) return items;
|
|
46
|
+
return items.filter((item) => projectSearchText(item).toLowerCase().includes(needle));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function fuzzyFilter(items, query) {
|
|
50
|
+
const list = Array.isArray(items) ? items : [];
|
|
51
|
+
const normalizedQuery = normalizeForFzf(query).text.trim();
|
|
52
|
+
if (!normalizedQuery) return list;
|
|
53
|
+
|
|
54
|
+
const Fzf = fzfConstructor();
|
|
55
|
+
if (typeof Fzf !== "function") return fallbackFilter(list, query);
|
|
56
|
+
|
|
57
|
+
return new Fzf(
|
|
58
|
+
list.map((project) => ({ project, searchText: projectSearchText(project) })),
|
|
59
|
+
{ selector: (entry) => entry.searchText },
|
|
60
|
+
).find(normalizedQuery).map((entry) => entry.item.project);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function labelPositions(text, query) {
|
|
64
|
+
const Fzf = fzfConstructor();
|
|
65
|
+
if (typeof Fzf !== "function") return null;
|
|
66
|
+
|
|
67
|
+
const normalizedText = normalizeForFzf(text);
|
|
68
|
+
const normalizedQuery = normalizeForFzf(query).text.trim();
|
|
69
|
+
if (!normalizedText.text || !normalizedQuery) return null;
|
|
70
|
+
|
|
71
|
+
const [entry] = new Fzf([normalizedText.text]).find(normalizedQuery);
|
|
72
|
+
if (!entry || typeof entry.positions?.forEach !== "function") return null;
|
|
73
|
+
|
|
74
|
+
const positions = [];
|
|
75
|
+
entry.positions.forEach((index) => positions.push(index));
|
|
76
|
+
return positions.map((index) => normalizedText.map[index]).filter((index) => Number.isInteger(index));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function fuzzyHighlight({ text, query, jsx }) {
|
|
80
|
+
if (typeof jsx !== "function") return text;
|
|
81
|
+
|
|
82
|
+
const positions = labelPositions(text, query);
|
|
83
|
+
if (positions == null || positions.length === 0) return text;
|
|
84
|
+
|
|
85
|
+
const matchedIndices = new Set(positions);
|
|
86
|
+
const parts = [];
|
|
87
|
+
let index = 0;
|
|
88
|
+
let key = 0;
|
|
89
|
+
const style = {
|
|
90
|
+
color: "var(--color-token-text-link-foreground, #2563eb)",
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
while (index < text.length) {
|
|
94
|
+
const isMatched = matchedIndices.has(index);
|
|
95
|
+
const start = index;
|
|
96
|
+
while (index < text.length && matchedIndices.has(index) === isMatched) index += 1;
|
|
97
|
+
|
|
98
|
+
const value = text.slice(start, index);
|
|
99
|
+
parts.push(
|
|
100
|
+
isMatched
|
|
101
|
+
? jsx("strong", {
|
|
102
|
+
className: "font-semibold",
|
|
103
|
+
style,
|
|
104
|
+
children: value,
|
|
105
|
+
}, key++)
|
|
106
|
+
: value,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return parts;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function dispatchMouseEvent(target, type) {
|
|
114
|
+
if (typeof target.dispatchEvent !== "function") return false;
|
|
115
|
+
const EventConstructor = type === "pointerdown"
|
|
116
|
+
? window.PointerEvent || window.MouseEvent
|
|
117
|
+
: window.MouseEvent;
|
|
118
|
+
if (typeof EventConstructor !== "function") return false;
|
|
119
|
+
target.dispatchEvent(new EventConstructor(type, {
|
|
120
|
+
bubbles: true,
|
|
121
|
+
button: 0,
|
|
122
|
+
buttons: type === "pointerdown" || type === "mousedown" ? 1 : 0,
|
|
123
|
+
cancelable: true,
|
|
124
|
+
ctrlKey: false,
|
|
125
|
+
view: window,
|
|
126
|
+
}));
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function visibleTriggerCandidates() {
|
|
131
|
+
return Array.from(document.querySelectorAll(triggerSelector)).filter((trigger) => {
|
|
132
|
+
if (!(trigger instanceof HTMLElement)) return false;
|
|
133
|
+
if (trigger.disabled || trigger.getAttribute("aria-disabled") === "true") return false;
|
|
134
|
+
const rect = trigger.getBoundingClientRect?.();
|
|
135
|
+
return rect && rect.width > 0 && rect.height > 0;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function triggerPriority(trigger) {
|
|
140
|
+
const variant = trigger.getAttribute("data-codex-plus-project-selector-variant");
|
|
141
|
+
if (variant === "default") return 0;
|
|
142
|
+
if (variant == null || variant === "") return 1;
|
|
143
|
+
return 2;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function projectSelectorTrigger() {
|
|
147
|
+
const [trigger] = visibleTriggerCandidates().sort((left, right) => {
|
|
148
|
+
const priority = triggerPriority(left) - triggerPriority(right);
|
|
149
|
+
if (priority !== 0) return priority;
|
|
150
|
+
const leftRect = left.getBoundingClientRect();
|
|
151
|
+
const rightRect = right.getBoundingClientRect();
|
|
152
|
+
return rightRect.top - leftRect.top || rightRect.left - leftRect.left;
|
|
153
|
+
});
|
|
154
|
+
return trigger ?? null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function focusProjectSelector() {
|
|
158
|
+
const trigger = projectSelectorTrigger();
|
|
159
|
+
if (trigger == null) return false;
|
|
160
|
+
trigger.focus?.();
|
|
161
|
+
const dispatched = [
|
|
162
|
+
dispatchMouseEvent(trigger, "pointerdown"),
|
|
163
|
+
dispatchMouseEvent(trigger, "mousedown"),
|
|
164
|
+
dispatchMouseEvent(trigger, "mouseup"),
|
|
165
|
+
dispatchMouseEvent(trigger, "click"),
|
|
166
|
+
].some(Boolean);
|
|
167
|
+
if (!dispatched) trigger.click?.();
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
CodexPlus.registerPlugin(
|
|
172
|
+
CodexPlus.definePlugin({
|
|
173
|
+
id: "projectSelectorShortcut",
|
|
174
|
+
name: "Project Selector Shortcut",
|
|
175
|
+
description: "Registers the Focus project selector command.",
|
|
176
|
+
required: true,
|
|
177
|
+
commands: [
|
|
178
|
+
{
|
|
179
|
+
id: "codexPlus.focusProjectSelector",
|
|
180
|
+
title: "Focus project selector",
|
|
181
|
+
description: "Focus or open the new chat project selector",
|
|
182
|
+
menu: { groups: ["suggested", "workspace"] },
|
|
183
|
+
palette: { enabled: true, keywords: ["project", "selector", "new chat"] },
|
|
184
|
+
shortcut: { defaultKeybindings: [{ key: "CmdOrCtrl+." }] },
|
|
185
|
+
run: focusProjectSelector,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
start(api) {
|
|
189
|
+
api.ui.projectSelector = {
|
|
190
|
+
fuzzyFilter,
|
|
191
|
+
fuzzyHighlight,
|
|
192
|
+
};
|
|
193
|
+
keydownHandler = (event) => {
|
|
194
|
+
if (event.defaultPrevented || event.key !== "." || (!event.metaKey && !event.ctrlKey) || event.altKey || event.shiftKey) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (api.commands.run("codexPlus.focusProjectSelector")) event.preventDefault();
|
|
198
|
+
};
|
|
199
|
+
document.addEventListener("keydown", keydownHandler, true);
|
|
200
|
+
},
|
|
201
|
+
stop() {
|
|
202
|
+
if (keydownHandler) document.removeEventListener("keydown", keydownHandler, true);
|
|
203
|
+
keydownHandler = null;
|
|
204
|
+
},
|
|
205
|
+
}),
|
|
206
|
+
);
|
|
207
|
+
})();
|
package/src/runtime/runtime.js
CHANGED
|
@@ -9,6 +9,27 @@
|
|
|
9
9
|
const styleElements = new Map();
|
|
10
10
|
const settingsListeners = new Map();
|
|
11
11
|
const storagePrefix = "codex-plus:plugin:";
|
|
12
|
+
const diagnosticEvents = [];
|
|
13
|
+
|
|
14
|
+
function diagnosticsEnabled() {
|
|
15
|
+
try {
|
|
16
|
+
return globalObject.localStorage?.getItem("codex-plus:diagnostics") === "1";
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function diagnose(event, details = {}) {
|
|
23
|
+
const entry = { event, details, time: new Date().toISOString() };
|
|
24
|
+
diagnosticEvents.push(entry);
|
|
25
|
+
if (diagnosticEvents.length > 200) diagnosticEvents.shift();
|
|
26
|
+
if (diagnosticsEnabled()) {
|
|
27
|
+
try {
|
|
28
|
+
console.info("[Codex Plus]", event, details);
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
return entry;
|
|
32
|
+
}
|
|
12
33
|
|
|
13
34
|
function safeId(id) {
|
|
14
35
|
if (typeof id !== "string" || id.trim() === "") throw new Error("Codex Plus plugin ids must be non-empty strings");
|
|
@@ -258,6 +279,34 @@
|
|
|
258
279
|
return null;
|
|
259
280
|
}
|
|
260
281
|
|
|
282
|
+
function ThreadHeaderAccessoryHost({ accessory, context, deps }) {
|
|
283
|
+
const rendered = accessory?.({ context, ...deps }) ?? null;
|
|
284
|
+
diagnose("threadHeader.accessoryHost.render", {
|
|
285
|
+
accessoryName: accessory?.name || null,
|
|
286
|
+
cwd: typeof context?.cwd === "string" ? context.cwd : null,
|
|
287
|
+
rendered: rendered != null,
|
|
288
|
+
});
|
|
289
|
+
return rendered;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function renderThreadHeaderAccessories({ context, deps } = {}) {
|
|
293
|
+
const jsx = deps?.jsx;
|
|
294
|
+
if (typeof jsx !== "function") {
|
|
295
|
+
diagnose("threadHeader.render.skip", { reason: "missing-jsx" });
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
diagnose("threadHeader.render", {
|
|
299
|
+
accessoryCount: CodexPlus.ui.threadHeader.accessories.length,
|
|
300
|
+
cwd: typeof context?.cwd === "string" ? context.cwd : null,
|
|
301
|
+
hostId: context?.hostId ?? null,
|
|
302
|
+
header: context?.header ?? null,
|
|
303
|
+
});
|
|
304
|
+
const rendered = CodexPlus.ui.threadHeader.accessories.map((accessory, index) =>
|
|
305
|
+
jsx(ThreadHeaderAccessoryHost, { accessory, context, deps }, `thread-header-accessory:${index}`),
|
|
306
|
+
);
|
|
307
|
+
return rendered.length === 0 ? null : rendered;
|
|
308
|
+
}
|
|
309
|
+
|
|
261
310
|
function registerStyle(pluginId, cssText) {
|
|
262
311
|
if (typeof document === "undefined") return null;
|
|
263
312
|
const id = `codex-plus-style-${safeId(pluginId)}`;
|
|
@@ -288,6 +337,7 @@
|
|
|
288
337
|
for (const command of plugin.commands || []) registerCommand({ ...command, plugin: plugin.id });
|
|
289
338
|
if (plugin.styles) registerStyle(plugin.id, plugin.styles);
|
|
290
339
|
if (plugin.required || plugin.enabledByDefault) startPlugin(plugin.id);
|
|
340
|
+
diagnose("plugin.register", { id: plugin.id, started: startedPlugins.has(plugin.id) });
|
|
291
341
|
return plugin;
|
|
292
342
|
}
|
|
293
343
|
|
|
@@ -296,6 +346,7 @@
|
|
|
296
346
|
if (!plugin || startedPlugins.has(id)) return;
|
|
297
347
|
plugin.start?.(CodexPlus);
|
|
298
348
|
startedPlugins.add(id);
|
|
349
|
+
diagnose("plugin.start", { id });
|
|
299
350
|
}
|
|
300
351
|
|
|
301
352
|
function stopPlugin(id) {
|
|
@@ -305,6 +356,10 @@
|
|
|
305
356
|
startedPlugins.delete(id);
|
|
306
357
|
}
|
|
307
358
|
|
|
359
|
+
function registerNativeMenuItem(item) {
|
|
360
|
+
return CodexPlus.native.request("native-menu/register-item", item).catch(() => ({ ok: false }));
|
|
361
|
+
}
|
|
362
|
+
|
|
308
363
|
const CodexPlus = {
|
|
309
364
|
definePlugin,
|
|
310
365
|
registerPlugin,
|
|
@@ -330,6 +385,15 @@
|
|
|
330
385
|
composer: { surfaceDecorators: [], decorateSurface(fn) { this.surfaceDecorators.push(fn); return fn; }, surfaceProps(props) { return applyDecorators(props, this.surfaceDecorators); } },
|
|
331
386
|
about: { buildInfo: [], addBuildInfo(fn) { this.buildInfo.push(fn); return fn; } },
|
|
332
387
|
errors: { boundaryDecorators: [], decorateBoundary(fn) { this.boundaryDecorators.push(fn); return fn; }, renderDetails: renderErrorDetails },
|
|
388
|
+
threadHeader: {
|
|
389
|
+
accessories: [],
|
|
390
|
+
addAccessory(fn) {
|
|
391
|
+
this.accessories.push(fn);
|
|
392
|
+
diagnose("threadHeader.addAccessory", { accessoryName: fn?.name || null, accessoryCount: this.accessories.length });
|
|
393
|
+
return fn;
|
|
394
|
+
},
|
|
395
|
+
renderAccessories: renderThreadHeaderAccessories,
|
|
396
|
+
},
|
|
333
397
|
mermaid: {
|
|
334
398
|
diagramDecorators: [],
|
|
335
399
|
decorateDiagram(fn) { this.diagramDecorators.push(fn); return fn; },
|
|
@@ -337,12 +401,20 @@
|
|
|
337
401
|
},
|
|
338
402
|
},
|
|
339
403
|
commands: { register: registerCommand, run: runCommand, all: () => Array.from(commands.values()), menuItems: (group) => Array.from(commands.values()).filter((command) => commandGroups(command).includes(group)) },
|
|
404
|
+
nativeMenus: { registerItem: registerNativeMenuItem },
|
|
340
405
|
settings: { define: defineSettings },
|
|
341
406
|
native: { async request(method, params) { return globalObject.codexPlusNative?.request?.(method, params) ?? globalObject.CodexPlusHost?.nativeRequest?.(method, params); } },
|
|
342
407
|
styles: { register: registerStyle, setRootVars },
|
|
408
|
+
diagnostics: {
|
|
409
|
+
log: diagnose,
|
|
410
|
+
snapshot() { return diagnosticEvents.slice(); },
|
|
411
|
+
clear() { diagnosticEvents.splice(0, diagnosticEvents.length); },
|
|
412
|
+
enabled: diagnosticsEnabled,
|
|
413
|
+
},
|
|
343
414
|
};
|
|
344
415
|
|
|
345
416
|
globalObject.CodexPlus = CodexPlus;
|
|
417
|
+
globalObject.CodexPlusDiagnostics = CodexPlus.diagnostics;
|
|
346
418
|
globalObject.CodexPlusHost ||= {};
|
|
347
419
|
globalObject.CodexPlusHost.register = registerHostModule;
|
|
348
420
|
|
|
@@ -352,18 +424,31 @@
|
|
|
352
424
|
"plugins/diagnosticErrors.js",
|
|
353
425
|
"plugins/userBubbleColors.js",
|
|
354
426
|
"plugins/projectColors.js",
|
|
427
|
+
"plugins/projectPathHeader.js",
|
|
355
428
|
"plugins/sidebarNameBlur.js",
|
|
429
|
+
"plugins/devTools.js",
|
|
430
|
+
"vendor/fzf.umd.js",
|
|
431
|
+
"plugins/projectSelectorShortcut.js",
|
|
356
432
|
"plugins/mermaidFullscreen.js",
|
|
357
433
|
];
|
|
358
434
|
|
|
359
435
|
if (typeof document !== "undefined") {
|
|
360
436
|
const base = new URL(".", document.currentScript?.src || globalObject.location?.href || "");
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
437
|
+
if (document.readyState === "loading" && typeof document.write === "function") {
|
|
438
|
+
diagnose("plugins.load", { mode: "document.write", count: pluginFiles.length });
|
|
439
|
+
for (const file of pluginFiles) {
|
|
440
|
+
const src = new URL(file, base).href.replace(/"/g, """);
|
|
441
|
+
document.write(`<script src="${src}"><\/script>`);
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
diagnose("plugins.load", { mode: "appendChild", count: pluginFiles.length });
|
|
445
|
+
for (const file of pluginFiles) {
|
|
446
|
+
const script = document.createElement("script");
|
|
447
|
+
script.src = new URL(file, base).href;
|
|
448
|
+
script.async = false;
|
|
449
|
+
script.defer = false;
|
|
450
|
+
document.head?.appendChild(script);
|
|
451
|
+
}
|
|
367
452
|
}
|
|
368
453
|
}
|
|
369
454
|
})();
|