codex-plus-patcher 0.6.0 → 0.7.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.
Files changed (40) hide show
  1. package/README.md +2 -1
  2. package/package.json +4 -2
  3. package/src/patches/lib/common-patches.js +46 -66
  4. package/src/patches/lib/hooks/about.js +7 -0
  5. package/src/patches/lib/hooks/diagnostics.js +7 -0
  6. package/src/patches/lib/hooks/mermaid.js +7 -0
  7. package/src/patches/lib/hooks/message-composer.js +7 -0
  8. package/src/patches/lib/hooks/native-main.js +7 -0
  9. package/src/patches/lib/hooks/project-selector.js +12 -0
  10. package/src/patches/lib/hooks/review.js +7 -0
  11. package/src/patches/lib/hooks/settings-commands.js +12 -0
  12. package/src/patches/lib/hooks/sidebar.js +12 -0
  13. package/src/patches/lib/hooks/thread-header.js +7 -0
  14. package/src/patches/lib/hooks/worker.js +7 -0
  15. package/src/patches/lib/project-selector-shortcut-patch.js +7 -6
  16. package/src/runtime/api/about.js +16 -0
  17. package/src/runtime/api/commands.js +85 -0
  18. package/src/runtime/api/composer.js +14 -0
  19. package/src/runtime/api/diagnostics.js +38 -0
  20. package/src/runtime/api/errors.js +20 -0
  21. package/src/runtime/api/index.js +79 -0
  22. package/src/runtime/api/mermaid.js +14 -0
  23. package/src/runtime/api/message.js +14 -0
  24. package/src/runtime/api/modules.js +57 -0
  25. package/src/runtime/api/native.js +14 -0
  26. package/src/runtime/api/patches.js +31 -0
  27. package/src/runtime/api/review.js +20 -0
  28. package/src/runtime/api/settings.js +76 -0
  29. package/src/runtime/api/sidebar.js +24 -0
  30. package/src/runtime/api/styles.js +28 -0
  31. package/src/runtime/api/threadHeader.js +41 -0
  32. package/src/runtime/assets.js +58 -17
  33. package/src/runtime/host/messageComposer.js +16 -0
  34. package/src/runtime/host/nativeMain.js +159 -0
  35. package/src/runtime/host/projectSelector.js +58 -0
  36. package/src/runtime/host/review.js +62 -0
  37. package/src/runtime/host/sidebar.js +21 -0
  38. package/src/runtime/host/threadHeader.js +9 -0
  39. package/src/runtime/{worker.js → host/worker.js} +7 -0
  40. package/src/runtime/runtime.js +23 -441
package/README.md CHANGED
@@ -39,7 +39,8 @@ The generated app includes a readable Codex Plus runtime under
39
39
  `webview/assets/codex-plus/`. Versioned ASAR patches install the runtime,
40
40
  built-in plugins, and the small Codex core hooks those plugins use. See
41
41
  [Runtime Plugin Support](docs/plugin-support.md) for the currently supported
42
- plugin interfaces.
42
+ plugin interfaces and [Plugin Architecture](docs/plugin-architecture.md) for
43
+ the layer rules.
43
44
 
44
45
  ## How It Works
45
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-plus-patcher",
3
- "version": "0.6.0",
3
+ "version": "0.7.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": {
@@ -21,7 +21,9 @@
21
21
  ],
22
22
  "scripts": {
23
23
  "test": "node --test",
24
- "check": "node scripts/check-syntax.js"
24
+ "check": "node scripts/check-syntax.js",
25
+ "check:pr": "node scripts/safe-automerge-pr.js --check",
26
+ "pr:automerge": "node scripts/safe-automerge-pr.js"
25
27
  },
26
28
  "engines": {
27
29
  "node": ">=20"
@@ -1,6 +1,16 @@
1
1
  const { codexPlusRuntimeAssets } = require("../../runtime/assets");
2
2
  const { replaceOnce } = require("./replace");
3
3
  const { makePatchSet } = require("./make-patch-set");
4
+ const { aboutMetadataRequire } = require("./hooks/about");
5
+ const { diagnosticDetailsHook } = require("./hooks/diagnostics");
6
+ const { mermaidDiagramHook } = require("./hooks/mermaid");
7
+ const { messageComposerHook } = require("./hooks/message-composer");
8
+ const { nativeMainHook } = require("./hooks/native-main");
9
+ const { reviewHook } = require("./hooks/review");
10
+ const { projectColorHook, sidebarMergeDataAttributes } = require("./hooks/sidebar");
11
+ const { appearanceSettingsHook, commandMenuItemsExpression } = require("./hooks/settings-commands");
12
+ const { threadHeaderHook } = require("./hooks/thread-header");
13
+ const { workerHook } = require("./hooks/worker");
4
14
  const {
5
15
  patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut,
6
16
  patchRunCommandProjectSelectorShortcut,
@@ -40,11 +50,6 @@ function buildCodexPlusPatchSet(config) {
40
50
  const sidebarThreadRowSignalsFile = files.sidebarThreadRowSignals;
41
51
  const branchPickerDropdownContentFile = files.branchPickerDropdownContent;
42
52
 
43
- function codexPlusWorkerHelpers() {
44
- return `
45
- const CPXWorkerBridge=require(\"./codex-plus-worker.js\");function CPX_traceRequest(e){return CPXWorkerBridge.traceRequest(e)}async function CPX_repositoryTargets(e,t,n,r){return CPXWorkerBridge.repositoryTargets(e,t,n,r,(i,a)=>pae(e.getWorktreeRepositoryForRoot(i,n),a))}function CPX_isReadOnlyBranchRequest(e,t){return CPXWorkerBridge.isReadOnlyBranchRequest(e,t)}`;
46
- }
47
-
48
53
  function patchTitle(text) {
49
54
  return replaceOnce(text, oldTitle, newTitle, `${oldTitle} in ${titleFile}`);
50
55
  }
@@ -59,7 +64,7 @@ function patchAboutDialog(text, context = {}) {
59
64
  let patched = replaceOnce(
60
65
  text,
61
66
  "let i=a.app.getName(),o=a.app.getVersion()",
62
- `let CPXAbout=require("./codex-plus-aboutMetadata.js").aboutPayload(${JSON.stringify(aboutContext)}),i=CPXAbout.appDisplayName,o=a.app.getVersion()`,
67
+ `let CPXAbout=${aboutMetadataRequire()}.aboutPayload(${JSON.stringify(aboutContext)}),i=CPXAbout.appDisplayName,o=a.app.getVersion()`,
63
68
  "about dialog app name anchor",
64
69
  );
65
70
  patched = replaceOnce(
@@ -77,7 +82,9 @@ function patchAboutDialog(text, context = {}) {
77
82
  patched = replaceOnce(
78
83
  patched,
79
84
  "function K0({appDisplayName:e,buildInfoLabel:t,buildInfoText:n,iconDataUrl:r,isDark:i,okLabel:a,title:o}){let s=r==null?``:",
80
- "function K0({appDisplayName:e,buildInfoLabel:t,buildInfoText:n,codexPlusDisclaimerHeading:D,codexPlusDisclaimerBody:O,iconDataUrl:r,isDark:i,okLabel:a,title:o}){let CPXAboutMetadata=require(\"./codex-plus-aboutMetadata.js\"),q=CPXAboutMetadata.disclaimerMarkup({escape:zz.default,heading:D,body:O}),s=r==null?``:",
85
+ "function K0({appDisplayName:e,buildInfoLabel:t,buildInfoText:n,codexPlusDisclaimerHeading:D,codexPlusDisclaimerBody:O,iconDataUrl:r,isDark:i,okLabel:a,title:o}){let CPXAboutMetadata=" +
86
+ aboutMetadataRequire() +
87
+ ",q=CPXAboutMetadata.disclaimerMarkup({escape:zz.default,heading:D,body:O}),s=r==null?``:",
81
88
  "about dialog renderer signature anchor",
82
89
  );
83
90
  patched = replaceOnce(
@@ -110,19 +117,19 @@ function patchWorker(text) {
110
117
  let patched = replaceOnce(
111
118
  text,
112
119
  "function pae(e,t){return e.queryClient.fetchQuery",
113
- `${codexPlusWorkerHelpers()}function pae(e,t){return e.queryClient.fetchQuery`,
120
+ `${workerHook()}function pae(e,t){return e.queryClient.fetchQuery`,
114
121
  "worker helper insertion anchor",
115
122
  );
116
123
  patched = replaceOnce(
117
124
  patched,
118
125
  "case`submodule-paths`:a=X({paths:await pae(this.gitManager.getWorktreeRepositoryForRoot(e.params.root,r),t.signal)});break;",
119
- "case`codex-plus-trace`:a=X(CPX_traceRequest(e.params));break;case`repository-targets`:a=X(await CPX_repositoryTargets(this.gitManager,e.params,r,t.signal));break;case`submodule-paths`:a=X({paths:await pae(this.gitManager.getWorktreeRepositoryForRoot(e.params.root,r),t.signal)});break;",
126
+ "case`codex-plus-trace`:a=X(CPXT(e.params));break;case`repository-targets`:a=X(await CPXR(this.gitManager,e.params,r,t.signal));break;case`submodule-paths`:a=X({paths:await pae(this.gitManager.getWorktreeRepositoryForRoot(e.params.root,r),t.signal)});break;",
120
127
  "repository-targets worker switch anchor",
121
128
  );
122
129
  patched = replaceOnce(
123
130
  patched,
124
131
  "function u2({requestKind:e,source:t}){return l2.has(e??``)||d2(t)}",
125
- "function u2({requestKind:e,source:t}){return l2.has(e??``)||d2(t)||CPX_isReadOnlyBranchRequest(e,t)}",
132
+ "function u2({requestKind:e,source:t}){return l2.has(e??``)||d2(t)||CPXB(e,t)}",
126
133
  "codex plus branch picker git allowlist anchor",
127
134
  );
128
135
  return replaceOnce(
@@ -133,24 +140,6 @@ function patchWorker(text) {
133
140
  );
134
141
  }
135
142
 
136
- const codexPlusReviewHelpers = `
137
- function CPXReviewMux(e){let t=e.mainReviewContent??(0,$.jsx)(of,e);return window.CodexPlus?.ui?.review?.renderBody?.({props:e,deps:{jsx:$.jsx,jsxs:$.jsxs,Fragment:$.Fragment,createElement:Q.createElement,React:Q,useStore:s,useAtom:l,routeAtom:ft,cwdAtom:Or,hostIdAtom:Dr,hostConfigAtom:kr,conversationIdAtom:jr,gitRequest:y,pathValue:B,DefaultReview:of,Button:Y,Tooltip:Ae,Icon:Je,Dropdown:yi,DropdownMenu:vi,BranchPickerDropdownContent:CPXBranchPickerDropdownContent,ReviewToolbar:dp,parseDiff:xr,DiffCard:Ma},defaultBody:t})??t}`;
138
-
139
- const codexPlusSubrepoDiffHelpers = `
140
- `;
141
-
142
- const codexPlusDiagnosticHelpers = `
143
- function CPXDiagnosticDetails(e){return window.CodexPlus?.ui?.errors?.renderDetails?.(e)??null}`;
144
-
145
- const codexPlusMermaidHelpers = `
146
- function CPXMermaidDiagramProps(e){return window.CodexPlus?.ui?.mermaid?.diagramProps?.(e)}`;
147
-
148
- const codexPlusThreadHeaderHelpers = `
149
- function CPXThreadHeaderAccessories(e){return window.CodexPlus?.ui?.threadHeader?.renderAccessories?.(e)??null}`;
150
-
151
- const codexPlusNativeMainHelpers = `
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}}})}`;
153
-
154
143
  function patchThreadSidePanelTabs(text) {
155
144
  let patched = replaceOnce(
156
145
  text,
@@ -161,13 +150,13 @@ function patchThreadSidePanelTabs(text) {
161
150
  patched = replaceOnce(
162
151
  patched,
163
152
  "function uf({cwd:e,fileEntries:t,generatedPathsReady:n,hasUnhandledAttributesFiles:r,isCappedMode:i,repositorySource:a,reviewSummarySource:o}){",
164
- `${codexPlusReviewHelpers}function uf({cwd:e,fileEntries:t,generatedPathsReady:n,hasUnhandledAttributesFiles:r,isCappedMode:i,repositorySource:a,reviewSummarySource:o}){`,
153
+ `${reviewHook()}function uf({cwd:e,fileEntries:t,generatedPathsReady:n,hasUnhandledAttributesFiles:r,isCappedMode:i,repositorySource:a,reviewSummarySource:o}){`,
165
154
  "review host hook insertion anchor",
166
155
  );
167
156
  return replaceOnce(
168
157
  patched,
169
158
  "let s;t[1]!==a||t[2]!==r||t[3]!==i?(s=(0,$.jsx)(Tf,{diffMode:a,setTabState:r,tabState:i}),t[1]=a,t[2]=r,t[3]=i,t[4]=s):s=t[4];let c;",
170
- "let s;t[1]!==a||t[2]!==r||t[3]!==i?(s=(0,$.jsx)(CPXReviewMux,{mainReviewContent:(0,$.jsx)(Tf,{diffMode:a,setTabState:r,tabState:i}),diffMode:a,setTabState:r,tabState:i}),t[1]=a,t[2]=r,t[3]=i,t[4]=s):s=t[4];let c;",
159
+ "let s;t[1]!==a||t[2]!==r||t[3]!==i?(s=(0,$.jsx)(CPXRM,{mainReviewContent:(0,$.jsx)(Tf,{diffMode:a,setTabState:r,tabState:i}),diffMode:a,setTabState:r,tabState:i}),t[1]=a,t[2]=r,t[3]=i,t[4]=s):s=t[4];let c;",
171
160
  "review body mux anchor",
172
161
  );
173
162
  }
@@ -175,7 +164,7 @@ function patchAppShell(text) {
175
164
  let patched = replaceOnce(
176
165
  text,
177
166
  "function En(e){return(0,Q.jsx)(wn,{onRetry:()=>{e.resetError()}})}",
178
- `${codexPlusDiagnosticHelpers}function En(e){return(0,Q.jsx)(wn,{error:e.error,onRetry:()=>{e.resetError()}})}`,
167
+ `${diagnosticDetailsHook()}function En(e){return(0,Q.jsx)(wn,{error:e.error,onRetry:()=>{e.resetError()}})}`,
179
168
  "app shell error fallback prop anchor",
180
169
  );
181
170
  patched = replaceOnce(
@@ -202,7 +191,7 @@ function patchErrorBoundary(text) {
202
191
  let patched = replaceOnce(
203
192
  text,
204
193
  "function Xf(e){let t=(0,Vf.c)(9),{resetError:n}=e,r=ee(),i,a;",
205
- `${codexPlusDiagnosticHelpers}function Xf(e){let t=(0,Vf.c)(9),{resetError:n,error:CPX_error,componentStack:CPX_componentStack}=e,r=ee(),i,a;`,
194
+ `${diagnosticDetailsHook()}function Xf(e){let t=(0,Vf.c)(9),{resetError:n,error:CPX_error,componentStack:CPX_componentStack}=e,r=ee(),i,a;`,
206
195
  "webview error boundary fallback prop anchor",
207
196
  );
208
197
  patched = replaceOnce(
@@ -223,7 +212,7 @@ function patchAppMainProjectColors(text) {
223
212
  let patched = replaceOnce(
224
213
  text,
225
214
  "function Pk(e){let t=(0,Q.c)(45),",
226
- `${codexPlusProjectColorHelpers}function Pk(e){let t=(0,Q.c)(46),`,
215
+ `${projectColorHook()}function Pk(e){let t=(0,Q.c)(46),`,
227
216
  "project color app main helper insertion anchor",
228
217
  );
229
218
  patched = replaceOnce(
@@ -235,7 +224,7 @@ function patchAppMainProjectColors(text) {
235
224
  patched = replaceOnce(
236
225
  patched,
237
226
  "q={onActivateGroup:V,onStartNewConversation:a,isGrouped:!0,hideRemoteHostEnvIcon:!0,hideTimestamp:l,locationId:b,floatStatusIconsRight:s,showPinActionOnHover:o}",
238
- "q={onActivateGroup:V,onStartNewConversation:a,isGrouped:!0,hideRemoteHostEnvIcon:!0,hideTimestamp:l,locationId:b,floatStatusIconsRight:s,showPinActionOnHover:o,dataAttributes:CPXHostThreadRowProps(i)}",
227
+ "q={onActivateGroup:V,onStartNewConversation:a,isGrouped:!0,hideRemoteHostEnvIcon:!0,hideTimestamp:l,locationId:b,floatStatusIconsRight:s,showPinActionOnHover:o,dataAttributes:CPXTR(i)}",
239
228
  "project thread row color key anchor",
240
229
  );
241
230
  patched = replaceOnce(
@@ -265,7 +254,7 @@ function patchAppMainProjectColors(text) {
265
254
  patched = replaceOnce(
266
255
  patched,
267
256
  "Ke=(0,Z.jsx)(Oe,{rowAttributes:ke,className:Ae,collapsed:L,contentClassName:je,",
268
- "Ke=(0,Z.jsx)(Oe,{rowAttributes:{...ke,...CPXHostProjectRowProps(n)},className:Ae,collapsed:L,contentClassName:je,",
257
+ "Ke=(0,Z.jsx)(Oe,{rowAttributes:{...ke,...CPXPR(n)},className:Ae,collapsed:L,contentClassName:je,",
269
258
  "project header row color attributes anchor",
270
259
  );
271
260
  return patched;
@@ -288,7 +277,7 @@ function patchAppMainSidebarBlur(text) {
288
277
  return replaceOnce(
289
278
  patched,
290
279
  "children:[l,u,(0,Z.jsx)(H_,{route:a,children:C})]",
291
- "children:[l,u,...(window.CodexPlus?.ui?.commands?.renderMenuItems?.({group:`suggested`,deps:{jsx:Z.jsx,MenuItem:Zy,register:Hp}})??[]),(0,Z.jsx)(H_,{route:a,children:C})]",
280
+ `children:[l,u,...(${commandMenuItemsExpression("suggested", "Z.jsx", "Zy", "Hp")}),(0,Z.jsx)(H_,{route:a,children:C})]`,
292
281
  "sidebar name blur command mount anchor",
293
282
  );
294
283
  }
@@ -328,19 +317,19 @@ function patchSidebarProjectHoverCardSourceRows(text) {
328
317
  patched = replaceOnce(
329
318
  patched,
330
319
  "dataAttributes:ae.sidebarThreadRow({active:s,hostId:t.hostId,id:n,kind:`pending-worktree`,pinned:r,title:t.label})",
331
- "dataAttributes:window.CodexPlus?.ui?.sidebar?.mergeDataAttributes?.(ae.sidebarThreadRow({active:s,hostId:t.hostId,id:n,kind:`pending-worktree`,pinned:r,title:t.label}),CPX_rowDataAttributes)",
320
+ `dataAttributes:${sidebarMergeDataAttributes("ae.sidebarThreadRow({active:s,hostId:t.hostId,id:n,kind:`pending-worktree`,pinned:r,title:t.label})", "CPX_rowDataAttributes")}`,
332
321
  "pending worktree sidebar row data attributes merge anchor",
333
322
  );
334
323
  patched = replaceOnce(
335
324
  patched,
336
325
  "dataAttributes:ae.sidebarThreadRow({active:s,hostId:null,id:t,kind:`remote`,pinned:r,title:e.task.title??``})",
337
- "dataAttributes:window.CodexPlus?.ui?.sidebar?.mergeDataAttributes?.(ae.sidebarThreadRow({active:s,hostId:null,id:t,kind:`remote`,pinned:r,title:e.task.title??``}),CPX_rowDataAttributes)",
326
+ `dataAttributes:${sidebarMergeDataAttributes("ae.sidebarThreadRow({active:s,hostId:null,id:t,kind:`remote`,pinned:r,title:e.task.title??``})", "CPX_rowDataAttributes")}`,
338
327
  "remote sidebar row data attributes merge anchor",
339
328
  );
340
329
  patched = replaceOnce(
341
330
  patched,
342
331
  "dataAttributes:ae.sidebarThreadRow({active:s,hostId:f,id:i,kind:`local`,pinned:r,title:x})",
343
- "dataAttributes:window.CodexPlus?.ui?.sidebar?.mergeDataAttributes?.(ae.sidebarThreadRow({active:s,hostId:f,id:i,kind:`local`,pinned:r,title:x}),CPX_rowDataAttributes)",
332
+ `dataAttributes:${sidebarMergeDataAttributes("ae.sidebarThreadRow({active:s,hostId:f,id:i,kind:`local`,pinned:r,title:x})", "CPX_rowDataAttributes")}`,
344
333
  "local sidebar row data attributes merge anchor",
345
334
  );
346
335
  patched = replaceOnce(
@@ -421,7 +410,7 @@ function patchHeader(text) {
421
410
  patched = replaceOnce(
422
411
  patched,
423
412
  "function lt(e){let t=(0,Z.c)(68),",
424
- `${codexPlusThreadHeaderHelpers}function lt(e){let t=(0,Z.c)(72),`,
413
+ `${threadHeaderHook()}function lt(e){let t=(0,Z.c)(72),`,
425
414
  "thread header accessory helper insertion anchor",
426
415
  );
427
416
  patched = replaceOnce(
@@ -444,7 +433,7 @@ function patchThreadPageHeader(text) {
444
433
  patched = replaceOnce(
445
434
  patched,
446
435
  "function c(e){let t=(0,o.c)(21),",
447
- `${codexPlusThreadHeaderHelpers}function c(e){let t=(0,o.c)(24),`,
436
+ `${threadHeaderHook()}function c(e){let t=(0,o.c)(24),`,
448
437
  "thread page header helper insertion anchor",
449
438
  );
450
439
  patched = replaceOnce(
@@ -466,7 +455,7 @@ function patchLocalConversationPageHeader(text) {
466
455
  let patched = replaceOnce(
467
456
  text,
468
457
  "function Tt(e){let t=(0,Y.c)(42),",
469
- `${codexPlusThreadHeaderHelpers}function Tt(e){let t=(0,Y.c)(45),`,
458
+ `${threadHeaderHook()}function Tt(e){let t=(0,Y.c)(45),`,
470
459
  "local conversation header helper insertion anchor",
471
460
  );
472
461
  patched = replaceOnce(
@@ -484,17 +473,11 @@ function patchLocalConversationPageHeader(text) {
484
473
  return patched;
485
474
  }
486
475
 
487
- const codexPlusProjectColorHelpers = `
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)}`;
489
-
490
- const codexPlusAppearanceSettingsHelpers = `
491
- function CPXAppearanceRows(e){return window.CodexPlus?.ui?.settings?.appearance?.renderRows?.({deps:{React:X,jsx:Z.jsx,SettingRow:J,ColorInput:sn,Switch:q},variant:e})??[]}`;
492
-
493
476
  function patchGeneralSettingsUserBubbleColors(text) {
494
477
  let patched = replaceOnce(
495
478
  text,
496
479
  "function tn({showCodeFont:e,showTranslucentSidebarToggle:t,variant:n}){",
497
- `${codexPlusAppearanceSettingsHelpers}function tn({showCodeFont:e,showTranslucentSidebarToggle:t,variant:n}){`,
480
+ `${appearanceSettingsHook()}function tn({showCodeFont:e,showTranslucentSidebarToggle:t,variant:n}){`,
498
481
  "user bubble settings helper insertion anchor",
499
482
  );
500
483
  return replaceOnce(
@@ -505,20 +488,17 @@ function patchGeneralSettingsUserBubbleColors(text) {
505
488
  );
506
489
  }
507
490
 
508
- const codexPlusUserBubbleHelpers = `
509
- ${codexPlusProjectColorHelpers}function CPX_installHostSurfaceProps(){}CPX_installHostSurfaceProps();`;
510
-
511
491
  function patchUserMessageAttachmentsBubbleColors(text) {
512
492
  let patched = replaceOnce(
513
493
  text,
514
494
  "var Z=i(),Q=e(n(),1),$=r();function Ue(e){",
515
- `var Z=i(),Q=e(n(),1),$=r();${codexPlusUserBubbleHelpers}function Ue(e){`,
495
+ `var Z=i(),Q=e(n(),1),$=r();${messageComposerHook()}function Ue(e){`,
516
496
  "user bubble helper insertion anchor",
517
497
  );
518
498
  patched = replaceOnce(
519
499
  patched,
520
500
  "Se=W?(0,$.jsx)(`div`,{className:`w-full p-px`,children:(0,$.jsx)(it,{cwd:T??null,hostId:k,initialMessage:U.trim(),onCancel:()=>{q(null)},onDraftChange:e=>{q(e)},onSubmit:ge})}):le?(0,$.jsx)(`div`,{\"data-user-message-bubble\":!0,role:H?`button`:void 0,tabIndex:0,className:D(e,`text-left focus-visible:ring-2 focus-visible:ring-token-focus-border focus-visible:outline-none`,H&&`cursor-interaction`),",
521
- "Se=W?(0,$.jsx)(`div`,{className:`w-full p-px`,children:(0,$.jsx)(it,{cwd:T??null,hostId:k,initialMessage:U.trim(),onCancel:()=>{q(null)},onDraftChange:e=>{q(e)},onSubmit:ge})}):le?(0,$.jsx)(`div`,{\"data-user-message-bubble\":!0,...CPXHostUserBubbleProps({}),role:H?`button`:void 0,tabIndex:0,className:D(e,`text-left focus-visible:ring-2 focus-visible:ring-token-focus-border focus-visible:outline-none`,H&&`cursor-interaction`),",
501
+ "Se=W?(0,$.jsx)(`div`,{className:`w-full p-px`,children:(0,$.jsx)(it,{cwd:T??null,hostId:k,initialMessage:U.trim(),onCancel:()=>{q(null)},onDraftChange:e=>{q(e)},onSubmit:ge})}):le?(0,$.jsx)(`div`,{\"data-user-message-bubble\":!0,...CPXBubbleProps({}),role:H?`button`:void 0,tabIndex:0,className:D(e,`text-left focus-visible:ring-2 focus-visible:ring-token-focus-border focus-visible:outline-none`,H&&`cursor-interaction`),",
522
502
  "user bubble marker attribute anchor",
523
503
  );
524
504
  return replaceOnce(
@@ -544,8 +524,8 @@ function patchUserMessageAttachmentsProjectColors(text) {
544
524
  );
545
525
  return replaceOnce(
546
526
  patched,
547
- "\"data-user-message-bubble\":!0,...CPXHostUserBubbleProps({}),role:H?`button`:void 0,",
548
- "\"data-user-message-bubble\":!0,...CPXHostUserBubbleProps({project:CPX_userMessageProjectId}),role:H?`button`:void 0,",
527
+ "\"data-user-message-bubble\":!0,...CPXBubbleProps({}),role:H?`button`:void 0,",
528
+ "\"data-user-message-bubble\":!0,...CPXBubbleProps({project:CPX_userMessageProjectId}),role:H?`button`:void 0,",
549
529
  "user bubble project marker attribute anchor",
550
530
  );
551
531
  }
@@ -554,13 +534,13 @@ function patchComposerBubbleColors(text) {
554
534
  let patched = replaceOnce(
555
535
  text,
556
536
  "function oh(e){let t=(0,$.c)(13),",
557
- `${codexPlusUserBubbleHelpers}function oh(e){let t=(0,$.c)(14),`,
537
+ `${messageComposerHook()}function oh(e){let t=(0,$.c)(14),`,
558
538
  "composer user bubble helper insertion anchor",
559
539
  );
560
540
  patched = replaceOnce(
561
541
  patched,
562
542
  "function oh(e){let t=(0,$.c)(14),{children:n,className:r,externalFooterVariant:i,inert:a,isDragActive:o,layout:s,onDragEnter:c,onDragLeave:l,onDragOver:u,onDrop:d}=e,",
563
- "function oh(e){let t=(0,$.c)(14),{children:n,className:r,externalFooterVariant:i,inert:a,isDragActive:o,layout:s,onDragEnter:c,onDragLeave:l,onDragOver:u,onDrop:d,codexPlusProps:CPX_hostSurfaceProps}=e,CPX_surfaceProps=CPX_hostSurfaceProps??CPXHostComposerSurfaceProps({}),",
543
+ "function oh(e){let t=(0,$.c)(14),{children:n,className:r,externalFooterVariant:i,inert:a,isDragActive:o,layout:s,onDragEnter:c,onDragLeave:l,onDragOver:u,onDrop:d,codexPlusProps:CPX_hostSurfaceProps}=e,CPX_surfaceProps=CPX_hostSurfaceProps??CPXSurfaceProps({}),",
564
544
  "composer host surface props anchor",
565
545
  );
566
546
  patched = replaceOnce(
@@ -582,7 +562,7 @@ function patchComposerProjectColors(text) {
582
562
  patched = replaceOnce(
583
563
  patched,
584
564
  anchors.composerProjectStyleCaller,
585
- anchors.composerProjectStyleCaller.replace(";return", ",CPX_composerThreadProjectId=a(CPX_threadProjectId,G==null?null:CPX_localThreadKey(G)),CPX_composerSurfaceProps=CPXHostComposerSurfaceProps({project:G==null?On?{hostId:On.hostId,path:On.remotePath,projectId:kn,label:On.label??On.name}:x??void 0:CPX_composerThreadProjectId});return"),
565
+ anchors.composerProjectStyleCaller.replace(";return", ",CPX_composerThreadProjectId=a(CPX_threadProjectId,G==null?null:CPX_localThreadKey(G)),CPX_composerSurfaceProps=CPXSurfaceProps({project:G==null?On?{hostId:On.hostId,path:On.remotePath,projectId:kn,label:On.label??On.name}:x??void 0:CPX_composerThreadProjectId});return"),
586
566
  "composer project style hook-safe caller anchor",
587
567
  );
588
568
  return replaceOnce(
@@ -615,13 +595,13 @@ function patchLocalTaskRow(text) {
615
595
  let patched = replaceOnce(
616
596
  text,
617
597
  "function fn(e){let t=(0,K.c)(124),",
618
- `${codexPlusProjectColorHelpers}function fn(e){let t=(0,K.c)(124),`,
598
+ `${projectColorHook()}function fn(e){let t=(0,K.c)(124),`,
619
599
  "local task row project color helper insertion anchor",
620
600
  );
621
601
  patched = replaceOnce(
622
602
  patched,
623
603
  "threadSummary:Ne,dataAttributes:Fe}=e,Ie=g===void 0?!1:g,",
624
- "threadSummary:Ne,dataAttributes:Fe}=e,CPX_rowDataAttributes=Fe??CPXHostProjectRowProps(Oe),Ie=g===void 0?!1:g,",
604
+ "threadSummary:Ne,dataAttributes:Fe}=e,CPX_rowDataAttributes=Fe??CPXPR(Oe),Ie=g===void 0?!1:g,",
625
605
  "local task row project assignment anchor",
626
606
  );
627
607
  patched = replaceOnce(
@@ -648,7 +628,7 @@ function patchMermaidDiagramShell(text) {
648
628
  let patched = replaceOnce(
649
629
  text,
650
630
  "function d(e){let t=(0,s.c)(18),{Renderer:n,className:r,code:i,fallback:d,isCodeFenceOpen:f,wideBlockKind:p}=e,",
651
- `${codexPlusMermaidHelpers}function d(e){let t=(0,s.c)(18),{Renderer:n,className:r,code:i,fallback:d,isCodeFenceOpen:f,wideBlockKind:p}=e,`,
631
+ `${mermaidDiagramHook()}function d(e){let t=(0,s.c)(18),{Renderer:n,className:r,code:i,fallback:d,isCodeFenceOpen:f,wideBlockKind:p}=e,`,
652
632
  "mermaid diagram shell helper insertion anchor",
653
633
  );
654
634
  return replaceOnce(
@@ -672,13 +652,13 @@ function patchMainNativeBridge(text) {
672
652
  let patched = replaceOnce(
673
653
  text,
674
654
  "function z1(e){return a.ipcMain.handle(Tl,async(t,n)=>{",
675
- `${codexPlusNativeMainHelpers}function z1(e){return a.ipcMain.handle(Tl,async(t,n)=>{`,
655
+ `${nativeMainHook()}function z1(e){return a.ipcMain.handle(Tl,async(t,n)=>{`,
676
656
  "codex plus native main helper insertion anchor",
677
657
  );
678
658
  return replaceOnce(
679
659
  patched,
680
660
  "v0({buildFlavor:i,getContextForWebContents:N.getContextForWebContents,isTrustedIpcEvent:te,usesOwlAppShell:y}),a.ipcMain.on(kl,",
681
- "v0({buildFlavor:i,getContextForWebContents:N.getContextForWebContents,isTrustedIpcEvent:te,usesOwlAppShell:y}),CPXRegisterNativeRequest({isTrustedIpcEvent:te}),a.ipcMain.on(kl,",
661
+ "v0({buildFlavor:i,getContextForWebContents:N.getContextForWebContents,isTrustedIpcEvent:te,usesOwlAppShell:y}),CPXNative.registerNativeRequest({isTrustedIpcEvent:te}),a.ipcMain.on(kl,",
682
662
  "codex plus native main registration anchor",
683
663
  );
684
664
  }
@@ -693,13 +673,13 @@ function patchMainMenuDiagnostics(text) {
693
673
  patched = replaceOnce(
694
674
  patched,
695
675
  "He,We,{type:`separator`}",
696
- "He,We,...CPXNativeMenuTemplateItems(`view-menu`),{type:`separator`}",
676
+ "He,We,...CPXNative.templateItems(`view-menu`),{type:`separator`}",
697
677
  "codex plus view menu template items anchor",
698
678
  );
699
679
  return replaceOnce(
700
680
  patched,
701
681
  "me.refreshApplicationMenu(),w(`application menu refreshed`,A),",
702
- "CPXRefreshApplicationMenu=()=>me.refreshApplicationMenu(),me.refreshApplicationMenu(),CPXLogMenuDiagnostics(),w(`application menu refreshed`,A),",
682
+ "CPXNative.setRefreshApplicationMenu(()=>me.refreshApplicationMenu()),me.refreshApplicationMenu(),CPXNative.logMenuDiagnostics(),w(`application menu refreshed`,A),",
703
683
  "codex plus menu diagnostics refresh anchor",
704
684
  );
705
685
  }
@@ -0,0 +1,7 @@
1
+ function aboutMetadataRequire() {
2
+ return 'require("./codex-plus-aboutMetadata.js")';
3
+ }
4
+
5
+ module.exports = {
6
+ aboutMetadataRequire,
7
+ };
@@ -0,0 +1,7 @@
1
+ function diagnosticDetailsHook() {
2
+ return "function CPXDiagnosticDetails(e){return window.CodexPlus?.ui?.errors?.renderDetails?.(e)??null}";
3
+ }
4
+
5
+ module.exports = {
6
+ diagnosticDetailsHook,
7
+ };
@@ -0,0 +1,7 @@
1
+ function mermaidDiagramHook() {
2
+ return "function CPXMermaidDiagramProps(e){return window.CodexPlus?.ui?.mermaid?.diagramProps?.(e)}";
3
+ }
4
+
5
+ module.exports = {
6
+ mermaidDiagramHook,
7
+ };
@@ -0,0 +1,7 @@
1
+ function messageComposerHook() {
2
+ return "let CPXMC=window.CodexPlusHost.adapters.messageComposer,CPXBubbleProps=e=>CPXMC.userBubbleProps(e),CPXSurfaceProps=e=>CPXMC.composerSurfaceProps(e);";
3
+ }
4
+
5
+ module.exports = {
6
+ messageComposerHook,
7
+ };
@@ -0,0 +1,7 @@
1
+ function nativeMainHook() {
2
+ return 'let CPXNative=require("./codex-plus-native-main.js").create({electron:a});';
3
+ }
4
+
5
+ module.exports = {
6
+ nativeMainHook,
7
+ };
@@ -0,0 +1,12 @@
1
+ function projectSelectorSearchHook() {
2
+ return "let CPXP=window.CodexPlusHost.adapters.projectSelector;";
3
+ }
4
+
5
+ function projectSelectorTriggerHook() {
6
+ return "function CPXPST(e,t){return CPXP.trigger(e,t,Me)}";
7
+ }
8
+
9
+ module.exports = {
10
+ projectSelectorSearchHook,
11
+ projectSelectorTriggerHook,
12
+ };
@@ -0,0 +1,7 @@
1
+ function reviewHook() {
2
+ return "let CPXR=window.CodexPlusHost.adapters.review,CPXRM=e=>CPXR.renderBodyFromHost(e,[$,Q,s,l,ft,Or,Dr,kr,jr,y,B,of,Y,Ae,Je,yi,vi,CPXBranchPickerDropdownContent,dp,xr,Ma]);";
3
+ }
4
+
5
+ module.exports = {
6
+ reviewHook,
7
+ };
@@ -0,0 +1,12 @@
1
+ function appearanceSettingsHook() {
2
+ return "function CPXAppearanceRows(e){return window.CodexPlus?.ui?.settings?.appearance?.renderRows?.({deps:{React:X,jsx:Z.jsx,SettingRow:J,ColorInput:sn,Switch:q},variant:e})??[]}";
3
+ }
4
+
5
+ function commandMenuItemsExpression(group, jsx, menuItem, register) {
6
+ return `window.CodexPlus?.ui?.commands?.renderMenuItems?.({group:\`${group}\`,deps:{jsx:${jsx},MenuItem:${menuItem},register:${register}}})??[]`;
7
+ }
8
+
9
+ module.exports = {
10
+ appearanceSettingsHook,
11
+ commandMenuItemsExpression,
12
+ };
@@ -0,0 +1,12 @@
1
+ function projectColorHook() {
2
+ return "let CPXS=window.CodexPlusHost.adapters.sidebar,CPXPR=e=>CPXS.projectRowProps(e),CPXTR=e=>CPXS.threadRowProps(e);";
3
+ }
4
+
5
+ function sidebarMergeDataAttributes(baseExpression, extraExpression) {
6
+ return `window.CodexPlusHost.adapters.sidebar.mergeThreadRowAttributes(${baseExpression},${extraExpression})`;
7
+ }
8
+
9
+ module.exports = {
10
+ projectColorHook,
11
+ sidebarMergeDataAttributes,
12
+ };
@@ -0,0 +1,7 @@
1
+ function threadHeaderHook() {
2
+ return "let CPXTH=window.CodexPlusHost.adapters.threadHeader;function CPXThreadHeaderAccessories(e){return CPXTH.accessories(e.context,e.deps)}";
3
+ }
4
+
5
+ module.exports = {
6
+ threadHeaderHook,
7
+ };
@@ -0,0 +1,7 @@
1
+ function workerHook() {
2
+ return 'const CPXW=require("./codex-plus-worker.js"),CPXT=e=>CPXW.traceRequest(e),CPXR=(e,t,n,r)=>CPXW.repositoryTargetsFromHost(e,t,n,r,pae),CPXB=(e,t)=>CPXW.isReadOnlyBranchRequest(e,t);';
3
+ }
4
+
5
+ module.exports = {
6
+ workerHook,
7
+ };
@@ -1,40 +1,41 @@
1
1
  const { replaceOnce } = require("./replace");
2
+ const { projectSelectorSearchHook, projectSelectorTriggerHook } = require("./hooks/project-selector");
2
3
 
3
4
  function patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut(text) {
4
5
  let patched = replaceOnce(
5
6
  text,
6
7
  "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
+ `Ne=r();${projectSelectorSearchHook()}function Pe(e){let t=(0,Ne.c)(42),`,
8
9
  "project selector fuzzy search adapter insertion anchor",
9
10
  );
10
11
  patched = replaceOnce(
11
12
  patched,
12
13
  "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
+ "v=CPXP.fuzzyFilter(n,h);",
14
15
  "project selector fuzzy search filter anchor",
15
16
  );
16
17
  patched = replaceOnce(
17
18
  patched,
18
19
  "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
+ "S=(0,H.jsx)(ve,{value:h,onChange:o,onKeyDown:e=>CPXP.acceptFirst(e,v,i,h),placeholder:s,className:`mb-1`})",
20
21
  "project selector accept first match keydown anchor",
21
22
  );
22
23
  patched = replaceOnce(
23
24
  patched,
24
25
  "(0,H.jsx)(`span`,{className:`truncate`,children:e.label})",
25
- "(0,H.jsx)(`span`,{className:`truncate`,children:CPXProjectSelectorFuzzyHighlight(e.label,h)})",
26
+ "(0,H.jsx)(`span`,{className:`truncate`,children:CPXP.fuzzyHighlight(e.label,h,H.jsx)})",
26
27
  "project selector fuzzy search highlight anchor",
27
28
  );
28
29
  patched = replaceOnce(
29
30
  patched,
30
31
  "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
+ `${projectSelectorTriggerHook()}function Ie(e){let t=(0,Ne.c)(81),`,
32
33
  "project selector shortcut helper insertion anchor",
33
34
  );
34
35
  return replaceOnce(
35
36
  patched,
36
37
  "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
+ "at=(0,H.jsx)(ye,{open:f,onOpenChange:g,onCloseAutoFocus:Y,align:tt,disabled:O,triggerButton:CPXPST(X,k),contentWidth:`workspace`,contentMaxHeight:`tall`,children:$})",
38
39
  "project selector shortcut final dropdown trigger anchor",
39
40
  );
40
41
  }
@@ -0,0 +1,16 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+ const { ui } = globalObject.CodexPlus;
4
+
5
+ const buildInfo = [];
6
+
7
+ function addBuildInfo(fn) {
8
+ buildInfo.push(fn);
9
+ return fn;
10
+ }
11
+
12
+ ui.about = {
13
+ addBuildInfo,
14
+ buildInfo,
15
+ };
16
+ })();
@@ -0,0 +1,85 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+ const { core, safeId } = globalObject.__CodexPlusRuntime;
4
+
5
+ function register(command) {
6
+ core.commands.set(safeId(command.id), command);
7
+ return command;
8
+ }
9
+
10
+ function run(id, ...args) {
11
+ const command = core.commands.get(id);
12
+ if (!command) throw new Error(`Unknown Codex Plus command: ${id}`);
13
+ return command.run?.(...args);
14
+ }
15
+
16
+ function commandGroups(command) {
17
+ return command.menu?.groups || [];
18
+ }
19
+
20
+ function commandKeybindings(command) {
21
+ return command.shortcut?.defaultKeybindings || [];
22
+ }
23
+
24
+ function commandMetadata() {
25
+ return Array.from(core.commands.values())
26
+ .filter((command) => command.palette?.enabled !== false)
27
+ .map((command) => {
28
+ const groups = commandGroups(command);
29
+ return {
30
+ id: command.id,
31
+ title: command.title,
32
+ description: command.description,
33
+ menuGroups: groups,
34
+ defaultKeybindings: commandKeybindings(command),
35
+ commandMenuGroupKey: groups.includes("panels") ? "panels" : groups[0],
36
+ commandMenu: true,
37
+ electron: {
38
+ menuTitle: command.title,
39
+ defaultKeybindings: commandKeybindings(command),
40
+ },
41
+ };
42
+ });
43
+ }
44
+
45
+ function CommandMenuItemHost({ command, deps, group, close }) {
46
+ const jsx = deps?.jsx;
47
+ const MenuItem = deps?.MenuItem;
48
+ if (typeof jsx !== "function" || MenuItem == null) return null;
49
+ const render = (closeMenu) =>
50
+ jsx(
51
+ MenuItem,
52
+ {
53
+ value: command.title,
54
+ title: command.title,
55
+ description: command.description,
56
+ onSelect() {
57
+ run(command.id);
58
+ closeMenu?.();
59
+ close?.();
60
+ },
61
+ },
62
+ command.id,
63
+ );
64
+ deps?.register?.(command.id, () => run(command.id), {
65
+ menuItem: { id: command.id, groupKey: group, render },
66
+ });
67
+ return null;
68
+ }
69
+
70
+ function renderMenuItems({ group, deps, close } = {}) {
71
+ const jsx = deps?.jsx;
72
+ if (typeof jsx !== "function") return [];
73
+ return Array.from(core.commands.values())
74
+ .filter((command) => commandGroups(command).includes(group))
75
+ .map((command) => jsx(CommandMenuItemHost, { command, deps, group, close }, command.id));
76
+ }
77
+
78
+ globalObject.CodexPlus.commands = {
79
+ register,
80
+ run,
81
+ all: () => Array.from(core.commands.values()),
82
+ menuItems: (group) => Array.from(core.commands.values()).filter((command) => commandGroups(command).includes(group)),
83
+ };
84
+ globalObject.CodexPlus.ui.commands = { renderMenuItems, commandMetadata };
85
+ })();