codex-plus-patcher 0.7.0 → 0.7.2
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 +2 -1
- package/package.json +2 -2
- package/src/cli.js +94 -0
- package/src/core/asar.js +6 -4
- package/src/core/dev-mode.js +339 -0
- package/src/core/plugin-audit.js +1605 -0
- package/src/patches/26.623.41415-4505.js +44 -0
- package/src/patches/26.623.42026-4514.js +44 -0
- package/src/patches/index.js +10 -1
- package/src/patches/lib/common-patches.js +621 -195
- package/src/patches/lib/hooks/message-composer.js +1 -1
- package/src/patches/lib/hooks/project-selector.js +2 -2
- package/src/patches/lib/hooks/review.js +4 -2
- package/src/patches/lib/hooks/settings-commands.js +3 -2
- package/src/patches/lib/hooks/sidebar.js +1 -6
- package/src/patches/lib/project-selector-shortcut-patch.js +141 -2
- package/src/runtime/api/index.js +3 -0
- package/src/runtime/assets.js +4 -4
- package/src/runtime/host/projectSelector.js +5 -1
- package/src/runtime/plugins/mermaidFullscreen.js +19 -6
- package/src/runtime/plugins/nestedRepositories.js +72 -11
- package/src/runtime/plugins/projectColors.js +96 -7
- package/src/runtime/plugins/projectSelectorShortcut.js +67 -12
- package/src/runtime/plugins/sidebarNameBlur.js +1 -1
- package/src/runtime/plugins/userBubbleColors.js +4 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function messageComposerHook() {
|
|
2
|
-
return "
|
|
2
|
+
return "var CPXMC=window.CodexPlusHost.adapters.messageComposer,CPXBubbleProps=e=>CPXMC.userBubbleProps(e),CPXSurfaceProps=e=>CPXMC.composerSurfaceProps(e);";
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
@@ -2,8 +2,8 @@ function projectSelectorSearchHook() {
|
|
|
2
2
|
return "let CPXP=window.CodexPlusHost.adapters.projectSelector;";
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
function projectSelectorTriggerHook() {
|
|
6
|
-
return
|
|
5
|
+
function projectSelectorTriggerHook(reactIdentifier = "Me") {
|
|
6
|
+
return `function CPXPST(e,t){return CPXP.trigger(e,t,${reactIdentifier})}`;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
function reviewHook() {
|
|
2
|
-
|
|
1
|
+
function reviewHook(depsExpression) {
|
|
2
|
+
const deps =
|
|
3
|
+
depsExpression || "[$,Q,s,l,ft,Or,Dr,kr,jr,y,B,of,Y,Ae,Je,yi,vi,CPXBranchPickerDropdownContent,dp,xr,Ma]";
|
|
4
|
+
return `let CPXR=window.CodexPlusHost.adapters.review,CPXRM=e=>CPXR.renderBodyFromHost(e,${deps});`;
|
|
3
5
|
}
|
|
4
6
|
|
|
5
7
|
module.exports = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
function appearanceSettingsHook() {
|
|
2
|
-
|
|
1
|
+
function appearanceSettingsHook(depsExpression) {
|
|
2
|
+
const deps = depsExpression || "{React:X,jsx:Z.jsx,SettingRow:J,ColorInput:sn,Switch:q}";
|
|
3
|
+
return `function CPXAppearanceRows(e){return window.CodexPlus?.ui?.settings?.appearance?.renderRows?.({deps:${deps},variant:e})??[]}`;
|
|
3
4
|
}
|
|
4
5
|
|
|
5
6
|
function commandMenuItemsExpression(group, jsx, menuItem, register) {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
function projectColorHook() {
|
|
2
|
-
return "
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
function sidebarMergeDataAttributes(baseExpression, extraExpression) {
|
|
6
|
-
return `window.CodexPlusHost.adapters.sidebar.mergeThreadRowAttributes(${baseExpression},${extraExpression})`;
|
|
2
|
+
return "var CPXS=window.CodexPlusHost.adapters.sidebar,CPXPR=e=>CPXS.projectRowProps(e);";
|
|
7
3
|
}
|
|
8
4
|
|
|
9
5
|
module.exports = {
|
|
10
6
|
projectColorHook,
|
|
11
|
-
sidebarMergeDataAttributes,
|
|
12
7
|
};
|
|
@@ -2,6 +2,14 @@ const { replaceOnce } = require("./replace");
|
|
|
2
2
|
const { projectSelectorSearchHook, projectSelectorTriggerHook } = require("./hooks/project-selector");
|
|
3
3
|
|
|
4
4
|
function patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut(text) {
|
|
5
|
+
if (text.includes("function Ti(e){let t=(0,Oi.c)(109),")) {
|
|
6
|
+
return replaceOnce(
|
|
7
|
+
text,
|
|
8
|
+
"de=(0,X.jsx)(`button`,{type:`button`,className:`flex min-w-0 items-center gap-1.5 rounded-lg bg-token-foreground/5 px-2 py-0.5 text-base leading-6 font-medium tracking-[-0.13px] text-token-foreground`,disabled:re,children:ue})",
|
|
9
|
+
"de=(0,X.jsx)(`button`,{type:`button`,\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":`default`,className:`flex min-w-0 items-center gap-1.5 rounded-lg bg-token-foreground/5 px-2 py-0.5 text-base leading-6 font-medium tracking-[-0.13px] text-token-foreground`,disabled:re,children:ue})",
|
|
10
|
+
"project selector shortcut final dropdown trigger anchor",
|
|
11
|
+
);
|
|
12
|
+
}
|
|
5
13
|
let patched = replaceOnce(
|
|
6
14
|
text,
|
|
7
15
|
"Ne=r();function Pe(e){let t=(0,Ne.c)(42),",
|
|
@@ -40,16 +48,147 @@ function patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut(text) {
|
|
|
40
48
|
);
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
function patchHomeProjectDropdownProjectSelectorShortcut(text) {
|
|
52
|
+
if (text.includes("function zn(e){let t=(0,Bn.c)(44),") && text.includes("function ar({activeProjectIdOverride:e,")) {
|
|
53
|
+
let patched = replaceOnce(
|
|
54
|
+
text,
|
|
55
|
+
"function zn(e){let t=(0,Bn.c)(44),",
|
|
56
|
+
`${projectSelectorSearchHook()}${projectSelectorTriggerHook("$")}function zn(e){let t=(0,Bn.c)(44),`,
|
|
57
|
+
"home project selector shortcut helper insertion anchor",
|
|
58
|
+
);
|
|
59
|
+
patched = replaceOnce(
|
|
60
|
+
patched,
|
|
61
|
+
"let e=_.trim().toLowerCase();b=r.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))});",
|
|
62
|
+
"b=CPXP.fuzzyFilter(r,_);",
|
|
63
|
+
"home project selector fuzzy search filter anchor",
|
|
64
|
+
);
|
|
65
|
+
patched = replaceOnce(
|
|
66
|
+
patched,
|
|
67
|
+
"w=(0,Z.jsx)(_t,{value:_,onChange:s,placeholder:c,className:`mb-1`})",
|
|
68
|
+
"w=(0,Z.jsx)(_t,{value:_,onChange:s,onKeyDown:e=>CPXP.acceptFirst(e,b,o,_),placeholder:c,className:`mb-1`})",
|
|
69
|
+
"home project selector accept first match keydown anchor",
|
|
70
|
+
);
|
|
71
|
+
patched = replaceOnce(
|
|
72
|
+
patched,
|
|
73
|
+
"(0,Z.jsx)(`span`,{className:`truncate`,children:e.label})",
|
|
74
|
+
"(0,Z.jsx)(`span`,{className:`truncate`,children:CPXP.fuzzyHighlight(e.label,_,Z.jsx)})",
|
|
75
|
+
"home project selector fuzzy search highlight anchor",
|
|
76
|
+
);
|
|
77
|
+
patched = replaceOnce(
|
|
78
|
+
patched,
|
|
79
|
+
"children:(0,$.jsxs)(me,{size:`composerSm`,color:`ghost`,className:`min-w-0`,children:",
|
|
80
|
+
"children:(0,$.jsxs)(me,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":u,size:`composerSm`,color:`ghost`,className:`min-w-0`,children:",
|
|
81
|
+
"home project selector default button marker anchor",
|
|
82
|
+
);
|
|
83
|
+
patched = replaceOnce(
|
|
84
|
+
patched,
|
|
85
|
+
"children:(0,$.jsx)($n,{categoryLabel:(0,$.jsx)(R,{id:`composer.localCwdDropdown.footerCategory`",
|
|
86
|
+
"children:(0,$.jsx)($n,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":u,categoryLabel:(0,$.jsx)(R,{id:`composer.localCwdDropdown.footerCategory`",
|
|
87
|
+
"home project selector footer button marker anchor",
|
|
88
|
+
);
|
|
89
|
+
patched = replaceOnce(
|
|
90
|
+
patched,
|
|
91
|
+
"ze=()=>(0,$.jsxs)(`button`,{className:V(`heading-xl text-token-text-tertiary",
|
|
92
|
+
"ze=()=>(0,$.jsxs)(`button`,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":u,className:V(`heading-xl text-token-text-tertiary",
|
|
93
|
+
"home project selector hero button marker anchor",
|
|
94
|
+
);
|
|
95
|
+
patched = replaceOnce(
|
|
96
|
+
patched,
|
|
97
|
+
"triggerButton:p??G(),contentWidth:`menu`",
|
|
98
|
+
"triggerButton:CPXPST(p??G(),u),contentWidth:`menu`",
|
|
99
|
+
"home project selector empty trigger anchor",
|
|
100
|
+
);
|
|
101
|
+
return replaceOnce(
|
|
102
|
+
patched,
|
|
103
|
+
"triggerButton:p??(u===`hero`?ze():u===`home`?G():Ie()),contentWidth:`workspace`",
|
|
104
|
+
"triggerButton:CPXPST(p??(u===`hero`?ze():u===`home`?G():Ie()),u),contentWidth:`workspace`",
|
|
105
|
+
"home project selector workspace trigger anchor",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
let patched = replaceOnce(
|
|
109
|
+
text,
|
|
110
|
+
"function St({activeProjectIdOverride:e,allowLocalProjects:t=!0,allowLocalProjectActions:n=t,allowRemoteProjects:r=!0,disabled:a=!1,hideLabel:o=!1,onWorkspaceRootSelected:s,variant:c=`default`,isOpen:l,onOpenChange:m,triggerButton:_}){",
|
|
111
|
+
`${projectSelectorSearchHook()}${projectSelectorTriggerHook("wt")}function St({activeProjectIdOverride:e,allowLocalProjects:t=!0,allowLocalProjectActions:n=t,allowRemoteProjects:r=!0,disabled:a=!1,hideLabel:o=!1,onWorkspaceRootSelected:s,variant:c=\`default\`,isOpen:l,onOpenChange:m,triggerButton:_}){`,
|
|
112
|
+
"home project selector shortcut helper insertion anchor",
|
|
113
|
+
);
|
|
114
|
+
patched = replaceOnce(
|
|
115
|
+
patched,
|
|
116
|
+
"let e=_.trim().toLowerCase();b=r.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))});",
|
|
117
|
+
"b=CPXP.fuzzyFilter(r,_);",
|
|
118
|
+
"home project selector fuzzy search filter anchor",
|
|
119
|
+
);
|
|
120
|
+
patched = replaceOnce(
|
|
121
|
+
patched,
|
|
122
|
+
"w=(0,X.jsx)(ie,{value:_,onChange:s,placeholder:c,className:`mb-1`})",
|
|
123
|
+
"w=(0,X.jsx)(ie,{value:_,onChange:s,onKeyDown:e=>CPXP.acceptFirst(e,b,o,_),placeholder:c,className:`mb-1`})",
|
|
124
|
+
"home project selector accept first match keydown anchor",
|
|
125
|
+
);
|
|
126
|
+
patched = replaceOnce(
|
|
127
|
+
patched,
|
|
128
|
+
"(0,X.jsx)(`span`,{className:`truncate`,children:e.label})",
|
|
129
|
+
"(0,X.jsx)(`span`,{className:`truncate`,children:CPXP.fuzzyHighlight(e.label,_,X.jsx)})",
|
|
130
|
+
"home project selector fuzzy search highlight anchor",
|
|
131
|
+
);
|
|
132
|
+
patched = replaceOnce(
|
|
133
|
+
patched,
|
|
134
|
+
"children:(0,$.jsxs)(Ne,{size:`composerSm`,color:`ghost`,className:`min-w-0`,children:",
|
|
135
|
+
"children:(0,$.jsxs)(Ne,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":c,size:`composerSm`,color:`ghost`,className:`min-w-0`,children:",
|
|
136
|
+
"home project selector default button marker anchor",
|
|
137
|
+
);
|
|
138
|
+
patched = replaceOnce(
|
|
139
|
+
patched,
|
|
140
|
+
"children:(0,$.jsx)(gt,{categoryLabel:(0,$.jsx)(R,{id:`composer.localCwdDropdown.footerCategory`",
|
|
141
|
+
"children:(0,$.jsx)(gt,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":c,categoryLabel:(0,$.jsx)(R,{id:`composer.localCwdDropdown.footerCategory`",
|
|
142
|
+
"home project selector footer button marker anchor",
|
|
143
|
+
);
|
|
144
|
+
patched = replaceOnce(
|
|
145
|
+
patched,
|
|
146
|
+
"Ze=()=>(0,$.jsxs)(`button`,{className:W(`heading-xl text-token-text-tertiary",
|
|
147
|
+
"Ze=()=>(0,$.jsxs)(`button`,{\"data-codex-plus-project-selector-trigger\":!0,\"data-codex-plus-project-selector-variant\":c,className:W(`heading-xl text-token-text-tertiary",
|
|
148
|
+
"home project selector hero button marker anchor",
|
|
149
|
+
);
|
|
150
|
+
patched = replaceOnce(
|
|
151
|
+
patched,
|
|
152
|
+
"triggerButton:_??J(),contentWidth:`menu`",
|
|
153
|
+
"triggerButton:CPXPST(_??J(),c),contentWidth:`menu`",
|
|
154
|
+
"home project selector empty trigger anchor",
|
|
155
|
+
);
|
|
156
|
+
return replaceOnce(
|
|
157
|
+
patched,
|
|
158
|
+
"triggerButton:_??(c===`hero`?Ze():c===`home`?J():Ke()),contentWidth:`workspace`",
|
|
159
|
+
"triggerButton:CPXPST(_??(c===`hero`?Ze():c===`home`?J():Ke()),c),contentWidth:`workspace`",
|
|
160
|
+
"home project selector workspace trigger anchor",
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
43
164
|
function patchRunCommandProjectSelectorShortcut(text) {
|
|
165
|
+
const runtimeCommandEntries = "...(window.CodexPlus?.commands?.all?.()??[]).map(e=>[e.id,()=>window.CodexPlus?.commands?.run?.(e.id)])";
|
|
166
|
+
if (text.includes("Jy(`toggleSidebar`,r);")) {
|
|
167
|
+
return replaceOnce(
|
|
168
|
+
text,
|
|
169
|
+
"Jy(`toggleSidebar`,r);",
|
|
170
|
+
"Jy(`toggleSidebar`,r);for(let e of window.CodexPlus?.commands?.all?.()??[])Jy(e.id,()=>window.CodexPlus?.commands?.run?.(e.id));",
|
|
171
|
+
"codex plus runtime command dispatch anchor",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
if (text.includes("],[`openFolder`,GTt],[`toggleSidebar`,")) {
|
|
175
|
+
return replaceOnce(
|
|
176
|
+
text,
|
|
177
|
+
"],[`openFolder`,GTt],[`toggleSidebar`,",
|
|
178
|
+
`],[\`openFolder\`,GTt],${runtimeCommandEntries},[\`toggleSidebar\`,`,
|
|
179
|
+
"codex plus runtime command dispatch anchor",
|
|
180
|
+
);
|
|
181
|
+
}
|
|
44
182
|
return replaceOnce(
|
|
45
183
|
text,
|
|
46
184
|
"],[`openFolder`,()=>{r()}],[`toggleSidebar`,",
|
|
47
|
-
|
|
48
|
-
"
|
|
185
|
+
`],[\`openFolder\`,()=>{r()}],${runtimeCommandEntries},[\`toggleSidebar\`,`,
|
|
186
|
+
"codex plus runtime command dispatch anchor",
|
|
49
187
|
);
|
|
50
188
|
}
|
|
51
189
|
|
|
52
190
|
module.exports = {
|
|
191
|
+
patchHomeProjectDropdownProjectSelectorShortcut,
|
|
53
192
|
patchLocalActiveWorkspaceRootDropdownProjectSelectorShortcut,
|
|
54
193
|
patchRunCommandProjectSelectorShortcut,
|
|
55
194
|
};
|
package/src/runtime/api/index.js
CHANGED
package/src/runtime/assets.js
CHANGED
|
@@ -55,13 +55,13 @@ const runtimeFiles = [
|
|
|
55
55
|
...browserRuntimeAssets,
|
|
56
56
|
];
|
|
57
57
|
|
|
58
|
-
function browserRuntimeManifest() {
|
|
59
|
-
return `window.__CodexPlusRuntimeFiles=${JSON.stringify(browserRuntimeFiles)};window.__CodexPlusLoadRuntimeFiles?.(window.__CodexPlusRuntimeFiles);\n`;
|
|
58
|
+
function browserRuntimeManifest(config = {}) {
|
|
59
|
+
return `window.__CodexPlusRuntimeConfig=${JSON.stringify(config)};window.__CodexPlusRuntimeFiles=${JSON.stringify(browserRuntimeFiles)};window.__CodexPlusLoadRuntimeFiles?.(window.__CodexPlusRuntimeFiles);\n`;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function codexPlusRuntimeAssets() {
|
|
62
|
+
function codexPlusRuntimeAssets(config = {}) {
|
|
63
63
|
return runtimeFiles.map(([asarPath, localPath]) => {
|
|
64
|
-
const content = localPath == null ? browserRuntimeManifest() : fs.readFileSync(path.join(runtimeRoot, localPath), "utf8");
|
|
64
|
+
const content = localPath == null ? browserRuntimeManifest(config) : fs.readFileSync(path.join(runtimeRoot, localPath), "utf8");
|
|
65
65
|
return [asarPath, content];
|
|
66
66
|
});
|
|
67
67
|
}
|
|
@@ -40,7 +40,11 @@
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function trigger(element, variant, React) {
|
|
43
|
-
return React
|
|
43
|
+
return typeof React?.cloneElement === "function" &&
|
|
44
|
+
element != null &&
|
|
45
|
+
typeof element === "object" &&
|
|
46
|
+
"props" in element &&
|
|
47
|
+
"type" in element
|
|
44
48
|
? React.cloneElement(element, {
|
|
45
49
|
...element.props,
|
|
46
50
|
"data-codex-plus-project-selector-trigger": true,
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
const BUTTON_CLASS = "codex-plus-mermaid-expand-button";
|
|
5
5
|
|
|
6
6
|
function sourceFor(container) {
|
|
7
|
-
return container.querySelector("pre.sr-only")?.textContent ||
|
|
7
|
+
return container.querySelector("pre.sr-only")?.textContent ||
|
|
8
|
+
container.parentElement?.querySelector(":scope > pre.sr-only")?.textContent ||
|
|
9
|
+
"";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hostFor(container) {
|
|
13
|
+
return container.closest('[data-markdown-copy="code-block"]') || container;
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
function assetUrl(assetPath) {
|
|
@@ -13,6 +19,10 @@
|
|
|
13
19
|
return new URL(`assets/${assetPath}`, document.baseURI).href;
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
function mermaidCoreAsset() {
|
|
23
|
+
return CodexPlus.config?.mermaidCoreAsset || "mermaid.core.js";
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
function escapeHtml(value) {
|
|
17
27
|
return String(value).replace(/[&<>"']/g, (char) => ({
|
|
18
28
|
"&": "&",
|
|
@@ -219,17 +229,19 @@ renderFromSource().catch((error) => {
|
|
|
219
229
|
const isDark = document.documentElement.classList.contains("dark") || document.documentElement.classList.contains("electron-dark");
|
|
220
230
|
const debug = localStorage.getItem("codexPlusMermaidDebug") === "1";
|
|
221
231
|
const html = source
|
|
222
|
-
? viewerHtml({ source, isDark, mermaidModuleUrl: assetUrl(
|
|
232
|
+
? viewerHtml({ source, isDark, mermaidModuleUrl: assetUrl(mermaidCoreAsset()), debug })
|
|
223
233
|
: `<!doctype html><meta charset="utf-8"><body>${escapeHtml("No Mermaid source was found.")}</body>`;
|
|
224
234
|
CodexPlus.native.request("mermaid/openViewer", { html }).catch(() => {});
|
|
225
235
|
}
|
|
226
236
|
|
|
227
237
|
function decorate(container) {
|
|
228
|
-
|
|
229
|
-
|
|
238
|
+
const host = hostFor(container);
|
|
239
|
+
if (host.querySelector(`:scope > .${BUTTON_CLASS}`)) return;
|
|
240
|
+
host.setAttribute("data-codex-plus-mermaid-host", "");
|
|
241
|
+
host.style.position ||= "relative";
|
|
230
242
|
const control = button("Open Mermaid diagram fullscreen");
|
|
231
|
-
control.addEventListener("click", () => openViewer(
|
|
232
|
-
|
|
243
|
+
control.addEventListener("click", () => openViewer(host));
|
|
244
|
+
host.prepend(control);
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
function decorateAll(root = document) {
|
|
@@ -243,6 +255,7 @@ renderFromSource().catch((error) => {
|
|
|
243
255
|
description: "Adds a separate fullscreen viewer with zoom controls to rendered Mermaid diagrams.",
|
|
244
256
|
required: true,
|
|
245
257
|
styles:
|
|
258
|
+
`[data-codex-plus-mermaid-host]{position:relative}` +
|
|
246
259
|
`[data-codex-plus-mermaid-diagram]{position:relative}` +
|
|
247
260
|
`.${BUTTON_CLASS}{position:absolute;left:.5rem;top:.5rem;z-index:30;display:inline-flex;width:1.75rem;height:1.75rem;align-items:center;justify-content:center;border:1px solid var(--color-token-input-border,rgba(127,127,127,.35));border-radius:.375rem;background:var(--color-background-elevated-primary,#fff);color:var(--color-token-foreground,#111);box-shadow:0 2px 8px rgba(0,0,0,.12);opacity:.82}` +
|
|
248
261
|
`.${BUTTON_CLASS}::before,.${BUTTON_CLASS}::after{content:"";position:absolute;width:.42rem;height:.42rem;border-color:currentColor;border-style:solid}` +
|
|
@@ -13,6 +13,43 @@
|
|
|
13
13
|
return JSON.stringify([hostId, conversationId, cwd]);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function workerRequest(workerId, method, params, signal) {
|
|
17
|
+
const bridge = window.electronBridge;
|
|
18
|
+
if (typeof bridge?.sendWorkerMessageFromView !== "function" || typeof bridge?.subscribeToWorkerMessages !== "function") {
|
|
19
|
+
return Promise.reject(new Error("Electron worker bridge is unavailable"));
|
|
20
|
+
}
|
|
21
|
+
if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
22
|
+
const id = `codex-plus-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
23
|
+
const request = { id, method, params };
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
let unsubscribe = null;
|
|
26
|
+
let done = false;
|
|
27
|
+
const cleanup = () => {
|
|
28
|
+
if (done) return;
|
|
29
|
+
done = true;
|
|
30
|
+
unsubscribe?.();
|
|
31
|
+
signal?.removeEventListener?.("abort", abort);
|
|
32
|
+
};
|
|
33
|
+
const abort = () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
bridge.sendWorkerMessageFromView(workerId, { type: "worker-request-cancel", workerId, id }).catch(() => {});
|
|
36
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
37
|
+
};
|
|
38
|
+
unsubscribe = bridge.subscribeToWorkerMessages(workerId, (message) => {
|
|
39
|
+
if (message?.type !== "worker-response" || message?.workerId !== workerId || message?.response?.id !== id) return;
|
|
40
|
+
cleanup();
|
|
41
|
+
const result = message.response.result;
|
|
42
|
+
if (result?.type === "ok") resolve(result.value);
|
|
43
|
+
else reject(new Error(result?.error?.message || "Worker request failed"));
|
|
44
|
+
});
|
|
45
|
+
signal?.addEventListener?.("abort", abort, { once: true });
|
|
46
|
+
bridge.sendWorkerMessageFromView(workerId, { type: "worker-request", workerId, request }).catch((error) => {
|
|
47
|
+
cleanup();
|
|
48
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
16
53
|
function debugText(value) {
|
|
17
54
|
try {
|
|
18
55
|
return JSON.stringify(value, (_key, item) => (typeof item === "bigint" ? String(item) : item), 2) ?? "";
|
|
@@ -86,6 +123,7 @@
|
|
|
86
123
|
function RepoDiffBody({ cwd, hostConfig, conversationId, diffMode, diffText, statusText, error, isLoading }, deps) {
|
|
87
124
|
const { jsx, createElement, parseDiff, DiffCard, pathValue } = deps;
|
|
88
125
|
if (error != null || isLoading || diffText == null) return PlainDiff({ text: statusText }, deps);
|
|
126
|
+
if (typeof parseDiff !== "function" || typeof DiffCard !== "function") return PlainDiff({ text: diffText }, deps);
|
|
89
127
|
let parsed;
|
|
90
128
|
try {
|
|
91
129
|
parsed = parseDiff(diffText);
|
|
@@ -193,6 +231,27 @@
|
|
|
193
231
|
}, [open, query, repo.root, hostConfig.id]);
|
|
194
232
|
|
|
195
233
|
const title = selected || "Unstaged";
|
|
234
|
+
if (!Button || !Tooltip || !Icon || !Dropdown || !DropdownMenu || !BranchPickerDropdownContent) {
|
|
235
|
+
const options = branches.length > 0 ? branches : searchedBranches;
|
|
236
|
+
return jsxs("label", {
|
|
237
|
+
className: "flex min-w-32 max-w-52 shrink-0 items-center gap-1 text-xs text-token-description-foreground",
|
|
238
|
+
children: [
|
|
239
|
+
jsx("span", { className: "sr-only", children: "Base branch" }),
|
|
240
|
+
jsx("select", {
|
|
241
|
+
className:
|
|
242
|
+
"min-w-0 flex-1 rounded-md border border-token-border bg-token-main-surface-primary px-1.5 py-1 text-xs text-token-foreground",
|
|
243
|
+
value: selected,
|
|
244
|
+
disabled: loading || error != null,
|
|
245
|
+
onFocus: loadBranches,
|
|
246
|
+
onChange: (event) => setBaseBranch(event.target.value),
|
|
247
|
+
children: [
|
|
248
|
+
jsx("option", { value: "", children: loading ? "Loading..." : "Unstaged" }, "unstaged"),
|
|
249
|
+
...options.map((branch) => jsx("option", { value: branch.name ?? branch, children: branch.name ?? branch }, branch.name ?? branch)),
|
|
250
|
+
],
|
|
251
|
+
}),
|
|
252
|
+
],
|
|
253
|
+
});
|
|
254
|
+
}
|
|
196
255
|
const button = jsxs(Button, {
|
|
197
256
|
type: "button",
|
|
198
257
|
color: selected ? "ghostActive" : "ghost",
|
|
@@ -317,14 +376,16 @@
|
|
|
317
376
|
],
|
|
318
377
|
}),
|
|
319
378
|
jsx(BranchPicker, { repo, hostConfig, baseBranch, setBaseBranch, deps }),
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
379
|
+
ReviewToolbar
|
|
380
|
+
? jsx(ReviewToolbar, {
|
|
381
|
+
conversationId,
|
|
382
|
+
cwd: repo.cwd,
|
|
383
|
+
hostId,
|
|
384
|
+
codexWorktree: false,
|
|
385
|
+
surface: "review-toolbar",
|
|
386
|
+
reviewToolbarCompact: true,
|
|
387
|
+
}, repo.id)
|
|
388
|
+
: null,
|
|
328
389
|
],
|
|
329
390
|
}),
|
|
330
391
|
collapsed ? null : RepoDiffBody({ cwd: repo.cwd, hostConfig, conversationId, diffMode, diffText, statusText, error, isLoading: loading }, deps),
|
|
@@ -338,7 +399,7 @@
|
|
|
338
399
|
const cwd = useAtom(cwdAtom);
|
|
339
400
|
const hostId = useAtom(hostIdAtom);
|
|
340
401
|
const hostConfig = useAtom(hostConfigAtom);
|
|
341
|
-
const conversationAtomValue = useAtom(conversationIdAtom);
|
|
402
|
+
const conversationAtomValue = conversationIdAtom ? useAtom(conversationIdAtom) : null;
|
|
342
403
|
const conversationId = routeStore.value.routeKind === "local-thread" ? routeStore.value.conversationId : null;
|
|
343
404
|
const [targets, setTargets] = React.useState(null);
|
|
344
405
|
const [collapsed, setCollapsedState] = React.useState(() => new Map());
|
|
@@ -438,8 +499,8 @@
|
|
|
438
499
|
start(api) {
|
|
439
500
|
api.ui.review.wrapBody((props, deps) => ReviewMux(props, deps));
|
|
440
501
|
api.modules.registerHostModule("codex-plus:native:repository-targets", {
|
|
441
|
-
request(params) {
|
|
442
|
-
return
|
|
502
|
+
request(params, signal) {
|
|
503
|
+
return workerRequest("git", "repository-targets", params, signal);
|
|
443
504
|
},
|
|
444
505
|
});
|
|
445
506
|
},
|
|
@@ -58,6 +58,90 @@
|
|
|
58
58
|
return palette[fnv1a32(colorKey(project)) % palette.length];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const projectByPath = new Map();
|
|
62
|
+
const projectByName = new Map();
|
|
63
|
+
|
|
64
|
+
function pathBasename(value) {
|
|
65
|
+
const trimmed = String(value || "").replace(/\/+$/, "");
|
|
66
|
+
if (trimmed === "") return "";
|
|
67
|
+
return trimmed.split("/").pop() || "";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function projectPathKeys(project) {
|
|
71
|
+
if (project == null || typeof project === "string") return [];
|
|
72
|
+
const host = project.hostId ?? project.host ?? project.remoteHostId ?? "local";
|
|
73
|
+
const paths = [project.path, project.cwd, project.projectPath, project.remotePath, project.root, project.workspaceRoot]
|
|
74
|
+
.filter((value) => value != null && String(value).trim() !== "")
|
|
75
|
+
.map((value) => String(value).trim());
|
|
76
|
+
return paths.map((path) => `${host}:${path}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function projectNameKeys(project) {
|
|
80
|
+
if (project == null || typeof project === "string") return [];
|
|
81
|
+
const repositoryRoot = project.repositoryData?.rootFolder;
|
|
82
|
+
const values = [
|
|
83
|
+
project.label,
|
|
84
|
+
project.name,
|
|
85
|
+
repositoryRoot,
|
|
86
|
+
pathBasename(project.projectId),
|
|
87
|
+
pathBasename(project.id),
|
|
88
|
+
...projectPathKeys(project).map((key) => pathBasename(key)),
|
|
89
|
+
];
|
|
90
|
+
return Array.from(new Set(values
|
|
91
|
+
.filter((value) => value != null && String(value).trim() !== "")
|
|
92
|
+
.map((value) => String(value).trim())));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function rememberProjectName(key, project) {
|
|
96
|
+
if (key === "") return;
|
|
97
|
+
const existing = projectByName.get(key);
|
|
98
|
+
if (existing === undefined) {
|
|
99
|
+
projectByName.set(key, project);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (existing != null && colorKey(existing) !== colorKey(project)) projectByName.set(key, null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function rememberProject(project) {
|
|
106
|
+
const key = colorKey(project);
|
|
107
|
+
if (key.trim() === "") return project;
|
|
108
|
+
for (const pathKey of projectPathKeys(project)) projectByPath.set(pathKey, project);
|
|
109
|
+
for (const nameKey of projectNameKeys(project)) rememberProjectName(nameKey, project);
|
|
110
|
+
return project;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resolveProject(project) {
|
|
114
|
+
for (const pathKey of projectPathKeys(project)) {
|
|
115
|
+
const knownProject = projectByPath.get(pathKey);
|
|
116
|
+
if (knownProject) return knownProject;
|
|
117
|
+
}
|
|
118
|
+
for (const nameKey of projectNameKeys(project)) {
|
|
119
|
+
const knownProject = projectByName.get(nameKey);
|
|
120
|
+
if (knownProject) return knownProject;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function activeSidebarStyle() {
|
|
126
|
+
const active = document.querySelector('[data-app-action-sidebar-thread-active="true"][data-codex-plus-project-color]');
|
|
127
|
+
if (!active) return undefined;
|
|
128
|
+
const computed = getComputedStyle(active);
|
|
129
|
+
const accent = computed.getPropertyValue("--codex-plus-project-accent").trim();
|
|
130
|
+
if (accent === "") return undefined;
|
|
131
|
+
return {
|
|
132
|
+
"--codex-plus-project-accent": accent,
|
|
133
|
+
"--codex-plus-project-bg-light": computed.getPropertyValue("--codex-plus-project-bg-light").trim(),
|
|
134
|
+
"--codex-plus-project-fg-light": computed.getPropertyValue("--codex-plus-project-fg-light").trim(),
|
|
135
|
+
"--codex-plus-project-soft-light": computed.getPropertyValue("--codex-plus-project-soft-light").trim(),
|
|
136
|
+
"--codex-plus-project-bg-dark": computed.getPropertyValue("--codex-plus-project-bg-dark").trim(),
|
|
137
|
+
"--codex-plus-project-fg-dark": computed.getPropertyValue("--codex-plus-project-fg-dark").trim(),
|
|
138
|
+
"--codex-plus-project-border-dark": computed.getPropertyValue("--codex-plus-project-border-dark").trim(),
|
|
139
|
+
"--codex-plus-project-separator-light": computed.getPropertyValue("--codex-plus-project-separator-light").trim(),
|
|
140
|
+
"--codex-plus-project-separator-dark": computed.getPropertyValue("--codex-plus-project-separator-dark").trim(),
|
|
141
|
+
borderLeft: `6px solid ${accent}`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
61
145
|
function style(project) {
|
|
62
146
|
const key = colorKey(project);
|
|
63
147
|
if (!readEnabled() || key.trim() === "") return undefined;
|
|
@@ -77,7 +161,9 @@
|
|
|
77
161
|
}
|
|
78
162
|
|
|
79
163
|
function dataAttributes(project, sidebar) {
|
|
80
|
-
const
|
|
164
|
+
const resolvedProject = sidebar ? rememberProject(project) : resolveProject(project);
|
|
165
|
+
const directStyle = style(project);
|
|
166
|
+
const inlineStyle = resolvedProject ? style(resolvedProject) : directStyle ?? activeSidebarStyle();
|
|
81
167
|
if (inlineStyle == null) return undefined;
|
|
82
168
|
return {
|
|
83
169
|
"data-codex-plus-project-color": "",
|
|
@@ -114,14 +200,17 @@
|
|
|
114
200
|
description: "Provides deterministic project accent colors across sidebar, messages, and composer surfaces.",
|
|
115
201
|
required: true,
|
|
116
202
|
styles:
|
|
117
|
-
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-sidebar-color]{border-radius:0;background-color:var(--codex-plus-project-soft-light);border-left-color:var(--codex-plus-project-accent)}" +
|
|
118
|
-
":root:not(.dark):not(.electron-dark) [data-app-action-sidebar-
|
|
119
|
-
":root.dark [data-codex-plus-project-sidebar-color]
|
|
120
|
-
":root.dark [data-app-action-sidebar-thread-
|
|
203
|
+
":root:not(.dark):not(.electron-dark) :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]){border-radius:0;background-color:var(--codex-plus-project-soft-light);border-left-color:var(--codex-plus-project-accent)}" +
|
|
204
|
+
":root:not(.dark):not(.electron-dark) [data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color]{background-color:var(--codex-plus-project-soft-light);border-left-color:var(--codex-plus-project-accent)}" +
|
|
205
|
+
":root:not(.dark):not(.electron-dark) :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"]{background-color:var(--codex-plus-project-bg-light);box-shadow:inset 5px 0 0 var(--codex-plus-project-accent)}" +
|
|
206
|
+
":root.dark :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]),:root.electron-dark :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]){border-radius:0;background-color:var(--codex-plus-project-bg-dark);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
207
|
+
":root.dark [data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color],:root.electron-dark [data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color]{background-color:var(--codex-plus-project-bg-dark);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
208
|
+
":root.dark :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"],:root.electron-dark :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"]{background-color:color-mix(in srgb,var(--codex-plus-project-accent) 38%,transparent);border-left-color:color-mix(in srgb,var(--codex-plus-project-accent) 88%,transparent);box-shadow:inset 5px 0 0 var(--codex-plus-project-accent)}" +
|
|
121
209
|
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]{border-left-color:var(--codex-plus-project-accent)}" +
|
|
122
210
|
":root.dark [data-codex-plus-project-color],:root.electron-dark [data-codex-plus-project-color]{border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
123
|
-
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){
|
|
124
|
-
":root.dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]),:root.electron-dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){
|
|
211
|
+
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){box-shadow:inset 6px 0 0 var(--codex-plus-project-accent);border-left-color:var(--codex-plus-project-accent)}" +
|
|
212
|
+
":root.dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]),:root.electron-dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){box-shadow:inset 6px 0 0 var(--codex-plus-project-accent);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
213
|
+
"[data-codex-plus-user-entry][data-codex-plus-project-color]{box-shadow:inset 6px 0 0 var(--codex-plus-project-accent),0 0 0 .5px rgba(255,255,255,.2)!important}",
|
|
125
214
|
exports: {
|
|
126
215
|
colorFor,
|
|
127
216
|
colorKey,
|