codex-plus-patcher 0.6.0 → 0.7.1

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 (50) hide show
  1. package/README.md +3 -1
  2. package/package.json +5 -3
  3. package/src/cli.js +88 -0
  4. package/src/core/dev-mode.js +274 -0
  5. package/src/core/plugin-audit.js +1267 -0
  6. package/src/patches/26.623.41415-4505.js +44 -0
  7. package/src/patches/index.js +8 -1
  8. package/src/patches/lib/common-patches.js +411 -248
  9. package/src/patches/lib/hooks/about.js +7 -0
  10. package/src/patches/lib/hooks/diagnostics.js +7 -0
  11. package/src/patches/lib/hooks/mermaid.js +7 -0
  12. package/src/patches/lib/hooks/message-composer.js +7 -0
  13. package/src/patches/lib/hooks/native-main.js +7 -0
  14. package/src/patches/lib/hooks/project-selector.js +12 -0
  15. package/src/patches/lib/hooks/review.js +9 -0
  16. package/src/patches/lib/hooks/settings-commands.js +13 -0
  17. package/src/patches/lib/hooks/sidebar.js +7 -0
  18. package/src/patches/lib/hooks/thread-header.js +7 -0
  19. package/src/patches/lib/hooks/worker.js +7 -0
  20. package/src/patches/lib/project-selector-shortcut-patch.js +84 -8
  21. package/src/runtime/api/about.js +16 -0
  22. package/src/runtime/api/commands.js +85 -0
  23. package/src/runtime/api/composer.js +14 -0
  24. package/src/runtime/api/diagnostics.js +38 -0
  25. package/src/runtime/api/errors.js +20 -0
  26. package/src/runtime/api/index.js +82 -0
  27. package/src/runtime/api/mermaid.js +14 -0
  28. package/src/runtime/api/message.js +14 -0
  29. package/src/runtime/api/modules.js +57 -0
  30. package/src/runtime/api/native.js +14 -0
  31. package/src/runtime/api/patches.js +31 -0
  32. package/src/runtime/api/review.js +20 -0
  33. package/src/runtime/api/settings.js +76 -0
  34. package/src/runtime/api/sidebar.js +24 -0
  35. package/src/runtime/api/styles.js +28 -0
  36. package/src/runtime/api/threadHeader.js +41 -0
  37. package/src/runtime/assets.js +59 -18
  38. package/src/runtime/host/messageComposer.js +16 -0
  39. package/src/runtime/host/nativeMain.js +159 -0
  40. package/src/runtime/host/projectSelector.js +58 -0
  41. package/src/runtime/host/review.js +62 -0
  42. package/src/runtime/host/sidebar.js +21 -0
  43. package/src/runtime/host/threadHeader.js +9 -0
  44. package/src/runtime/{worker.js → host/worker.js} +7 -0
  45. package/src/runtime/plugins/mermaidFullscreen.js +19 -6
  46. package/src/runtime/plugins/nestedRepositories.js +72 -11
  47. package/src/runtime/plugins/projectColors.js +94 -7
  48. package/src/runtime/plugins/projectSelectorShortcut.js +67 -12
  49. package/src/runtime/plugins/sidebarNameBlur.js +1 -1
  50. package/src/runtime/runtime.js +23 -441
@@ -0,0 +1,76 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+ const { core, safeId } = globalObject.__CodexPlusRuntime;
4
+
5
+ function getPluginStore(pluginId) {
6
+ const key = `${core.storagePrefix}${pluginId}`;
7
+ try {
8
+ return JSON.parse(globalObject.localStorage?.getItem(key) || "{}") || {};
9
+ } catch {
10
+ return {};
11
+ }
12
+ }
13
+
14
+ function writePluginStore(pluginId, store) {
15
+ const key = `${core.storagePrefix}${pluginId}`;
16
+ globalObject.localStorage?.setItem(key, JSON.stringify(store));
17
+ }
18
+
19
+ function emitSetting(pluginId, key, value) {
20
+ const listenerKey = `${pluginId}:${key}`;
21
+ for (const listener of core.settingsListeners.get(listenerKey) || []) listener(value);
22
+ }
23
+
24
+ function define(pluginId, definitions) {
25
+ const id = safeId(pluginId);
26
+ const store = getPluginStore(id);
27
+ for (const [key, definition] of Object.entries(definitions || {})) {
28
+ if (!(key in store) && "default" in definition) store[key] = definition.default;
29
+ }
30
+ writePluginStore(id, store);
31
+ return {
32
+ definitions,
33
+ get(key) {
34
+ return getPluginStore(id)[key];
35
+ },
36
+ set(key, value) {
37
+ const next = getPluginStore(id);
38
+ next[key] = value;
39
+ writePluginStore(id, next);
40
+ emitSetting(id, key, value);
41
+ },
42
+ use(key, listener) {
43
+ const listenerKey = `${id}:${key}`;
44
+ const listeners = core.settingsListeners.get(listenerKey) || new Set();
45
+ listeners.add(listener);
46
+ core.settingsListeners.set(listenerKey, listeners);
47
+ listener(getPluginStore(id)[key]);
48
+ return () => listeners.delete(listener);
49
+ },
50
+ };
51
+ }
52
+
53
+ function AppearanceRowHost({ row, deps, variant }) {
54
+ return row.render?.({ ...deps, variant, row }) ?? null;
55
+ }
56
+
57
+ const appearance = {
58
+ rows: [],
59
+ addRow(row) {
60
+ this.rows.push(row);
61
+ return row;
62
+ },
63
+ renderRows({ deps, variant, section = "appearance" } = {}) {
64
+ const jsx = deps?.jsx;
65
+ if (typeof jsx !== "function") return [];
66
+ return this.rows
67
+ .filter((row) => (row.section || "appearance") === section)
68
+ .slice()
69
+ .sort((left, right) => (left.order || 0) - (right.order || 0))
70
+ .map((row) => jsx(AppearanceRowHost, { row, deps, variant }, row.id));
71
+ },
72
+ };
73
+
74
+ globalObject.CodexPlus.ui.settings = { appearance };
75
+ globalObject.CodexPlus.settings = { define };
76
+ })();
@@ -0,0 +1,24 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+ const { applyDecorators, mergeDataAttributes } = globalObject.__CodexPlusRuntime;
4
+ const sidebar = {
5
+ projectDecorators: [],
6
+ threadDecorators: [],
7
+ decorateProjectRow(fn) {
8
+ this.projectDecorators.push(fn);
9
+ return fn;
10
+ },
11
+ decorateThreadRow(fn) {
12
+ this.threadDecorators.push(fn);
13
+ return fn;
14
+ },
15
+ mergeDataAttributes,
16
+ projectRowProps(props) {
17
+ return applyDecorators(props, this.projectDecorators);
18
+ },
19
+ threadRowProps(props) {
20
+ return applyDecorators(props, this.threadDecorators);
21
+ },
22
+ };
23
+ globalObject.CodexPlus.ui.sidebar = sidebar;
24
+ })();
@@ -0,0 +1,28 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+ const { core, safeId } = globalObject.__CodexPlusRuntime;
4
+
5
+ function register(pluginId, cssText) {
6
+ if (typeof document === "undefined") return null;
7
+ const id = `codex-plus-style-${safeId(pluginId)}`;
8
+ let element = core.styleElements.get(id) || document.getElementById(id);
9
+ if (!element) {
10
+ element = document.createElement("style");
11
+ element.id = id;
12
+ document.head?.appendChild(element);
13
+ }
14
+ element.textContent = cssText;
15
+ core.styleElements.set(id, element);
16
+ return element;
17
+ }
18
+
19
+ function setRootVars(vars) {
20
+ if (typeof document === "undefined") return;
21
+ for (const [key, value] of Object.entries(vars || {})) {
22
+ if (value == null) document.documentElement.style.removeProperty(key);
23
+ else document.documentElement.style.setProperty(key, value);
24
+ }
25
+ }
26
+
27
+ globalObject.CodexPlus.styles = { register, setRootVars };
28
+ })();
@@ -0,0 +1,41 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function ThreadHeaderAccessoryHost({ accessory, context, deps }) {
5
+ const rendered = accessory?.({ context, ...deps }) ?? null;
6
+ globalObject.CodexPlus.diagnostics.log("threadHeader.accessoryHost.render", {
7
+ accessoryName: accessory?.name || null,
8
+ cwd: typeof context?.cwd === "string" ? context.cwd : null,
9
+ rendered: rendered != null,
10
+ });
11
+ return rendered;
12
+ }
13
+
14
+ function renderAccessories({ context, deps } = {}) {
15
+ const jsx = deps?.jsx;
16
+ if (typeof jsx !== "function") {
17
+ globalObject.CodexPlus.diagnostics.log("threadHeader.render.skip", { reason: "missing-jsx" });
18
+ return null;
19
+ }
20
+ globalObject.CodexPlus.diagnostics.log("threadHeader.render", {
21
+ accessoryCount: globalObject.CodexPlus.ui.threadHeader.accessories.length,
22
+ cwd: typeof context?.cwd === "string" ? context.cwd : null,
23
+ hostId: context?.hostId ?? null,
24
+ header: context?.header ?? null,
25
+ });
26
+ const rendered = globalObject.CodexPlus.ui.threadHeader.accessories.map((accessory, index) =>
27
+ jsx(ThreadHeaderAccessoryHost, { accessory, context, deps }, `thread-header-accessory:${index}`),
28
+ );
29
+ return rendered.length === 0 ? null : rendered;
30
+ }
31
+
32
+ globalObject.CodexPlus.ui.threadHeader = {
33
+ accessories: [],
34
+ addAccessory(fn) {
35
+ this.accessories.push(fn);
36
+ globalObject.CodexPlus.diagnostics.log("threadHeader.addAccessory", { accessoryName: fn?.name || null, accessoryCount: this.accessories.length });
37
+ return fn;
38
+ },
39
+ renderAccessories,
40
+ };
41
+ })();
@@ -2,31 +2,72 @@ const fs = require("node:fs");
2
2
  const path = require("node:path");
3
3
 
4
4
  const runtimeRoot = __dirname;
5
- const runtimeFiles = [
5
+ const browserRuntimeFiles = [
6
+ "api/index.js",
7
+ "api/diagnostics.js",
8
+ "api/modules.js",
9
+ "api/settings.js",
10
+ "api/patches.js",
11
+ "api/commands.js",
12
+ "api/styles.js",
13
+ "api/sidebar.js",
14
+ "api/message.js",
15
+ "api/composer.js",
16
+ "api/about.js",
17
+ "api/review.js",
18
+ "api/native.js",
19
+ "api/errors.js",
20
+ "api/threadHeader.js",
21
+ "api/mermaid.js",
22
+ "host/review.js",
23
+ "host/sidebar.js",
24
+ "host/messageComposer.js",
25
+ "host/projectSelector.js",
26
+ "host/threadHeader.js",
27
+ "vendor/fzf.umd.js",
28
+ "plugins/aboutMetadata.js",
29
+ "plugins/nestedRepositories.js",
30
+ "plugins/diagnosticErrors.js",
31
+ "plugins/userBubbleColors.js",
32
+ "plugins/projectColors.js",
33
+ "plugins/projectPathHeader.js",
34
+ "plugins/sidebarNameBlur.js",
35
+ "plugins/devTools.js",
36
+ "plugins/projectSelectorShortcut.js",
37
+ "plugins/mermaidFullscreen.js",
38
+ ];
39
+
40
+ const nodeRuntimeFiles = [
6
41
  [".vite/build/codex-plus-aboutMetadata.js", "plugins/aboutMetadata.js"],
7
- [".vite/build/codex-plus-worker.js", "worker.js"],
42
+ [".vite/build/codex-plus-native-main.js", "host/nativeMain.js"],
43
+ [".vite/build/codex-plus-worker.js", "host/worker.js"],
8
44
  ["webview/assets/codex-plus/runtime.js", "runtime.js"],
9
- ["webview/assets/codex-plus/plugins/aboutMetadata.js", "plugins/aboutMetadata.js"],
10
- ["webview/assets/codex-plus/plugins/nestedRepositories.js", "plugins/nestedRepositories.js"],
11
- ["webview/assets/codex-plus/plugins/diagnosticErrors.js", "plugins/diagnosticErrors.js"],
12
- ["webview/assets/codex-plus/plugins/userBubbleColors.js", "plugins/userBubbleColors.js"],
13
- ["webview/assets/codex-plus/plugins/projectColors.js", "plugins/projectColors.js"],
14
- ["webview/assets/codex-plus/plugins/projectPathHeader.js", "plugins/projectPathHeader.js"],
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"],
19
- ["webview/assets/codex-plus/plugins/mermaidFullscreen.js", "plugins/mermaidFullscreen.js"],
20
45
  ];
21
46
 
22
- function codexPlusRuntimeAssets() {
23
- return runtimeFiles.map(([asarPath, localPath]) => [
24
- asarPath,
25
- fs.readFileSync(path.join(runtimeRoot, localPath), "utf8"),
26
- ]);
47
+ const browserRuntimeAssets = browserRuntimeFiles.map((filePath) => [
48
+ `webview/assets/codex-plus/${filePath}`,
49
+ filePath.startsWith("vendor/") ? "../../node_modules/fzf/dist/fzf.umd.js" : filePath,
50
+ ]);
51
+
52
+ const runtimeFiles = [
53
+ ...nodeRuntimeFiles,
54
+ ["webview/assets/codex-plus/runtime-manifest.js", null],
55
+ ...browserRuntimeAssets,
56
+ ];
57
+
58
+ function browserRuntimeManifest(config = {}) {
59
+ return `window.__CodexPlusRuntimeConfig=${JSON.stringify(config)};window.__CodexPlusRuntimeFiles=${JSON.stringify(browserRuntimeFiles)};window.__CodexPlusLoadRuntimeFiles?.(window.__CodexPlusRuntimeFiles);\n`;
60
+ }
61
+
62
+ function codexPlusRuntimeAssets(config = {}) {
63
+ return runtimeFiles.map(([asarPath, localPath]) => {
64
+ const content = localPath == null ? browserRuntimeManifest(config) : fs.readFileSync(path.join(runtimeRoot, localPath), "utf8");
65
+ return [asarPath, content];
66
+ });
27
67
  }
28
68
 
29
69
  module.exports = {
70
+ browserRuntimeFiles,
30
71
  codexPlusRuntimeAssets,
31
72
  runtimeFiles,
32
73
  };
@@ -0,0 +1,16 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function userBubbleProps(props) {
5
+ return globalObject.CodexPlus?.ui?.message?.userBubbleProps?.(props);
6
+ }
7
+
8
+ function composerSurfaceProps(props) {
9
+ return globalObject.CodexPlus?.ui?.composer?.surfaceProps?.(props);
10
+ }
11
+
12
+ globalObject.CodexPlusHost.adapters.messageComposer = {
13
+ composerSurfaceProps,
14
+ userBubbleProps,
15
+ };
16
+ })();
@@ -0,0 +1,159 @@
1
+ const fs = require("node:fs");
2
+ const os = require("node:os");
3
+ const path = require("node:path");
4
+ const { randomUUID } = require("node:crypto");
5
+ const { pathToFileURL } = require("node:url");
6
+
7
+ function create({ electron }) {
8
+ let nativeMenuItems = [];
9
+ let refreshApplicationMenu = null;
10
+
11
+ function menuSnapshot(menu) {
12
+ return menu?.items?.map((item) => ({
13
+ id: item.id,
14
+ label: item.label,
15
+ enabled: item.enabled,
16
+ visible: item.visible,
17
+ accelerator: item.accelerator,
18
+ submenu: menuSnapshot(item.submenu),
19
+ }));
20
+ }
21
+
22
+ function logMenuDiagnostics() {
23
+ try {
24
+ const menu = menuSnapshot(electron.Menu.getApplicationMenu()) ?? [];
25
+ const text = JSON.stringify(menu);
26
+ const hasOpenDeveloperTools = text.includes("codexPlusOpenDevTools") || text.includes("Open Developer Tools");
27
+ if (process.env.CODEX_PLUS_MENU_DIAGNOSTICS === "1" || !hasOpenDeveloperTools) {
28
+ console.log(`[Codex Plus menu diagnostics] ${JSON.stringify({ hasOpenDeveloperTools, menu })}`);
29
+ }
30
+ } catch (error) {
31
+ console.log(`[Codex Plus menu diagnostics] ${JSON.stringify({ error: String(error?.message ?? error) })}`);
32
+ }
33
+ }
34
+
35
+ function openDevTools(event) {
36
+ try {
37
+ const webContents = event?.sender;
38
+ if (typeof webContents?.openDevTools !== "function") return { ok: false };
39
+ webContents.openDevTools();
40
+ return { ok: true };
41
+ } catch {
42
+ return { ok: false };
43
+ }
44
+ }
45
+
46
+ function focusedEvent() {
47
+ const window = electron.BrowserWindow.getFocusedWindow();
48
+ return window && !window.isDestroyed() ? { sender: window.webContents } : null;
49
+ }
50
+
51
+ function runNativeMenuRequest(request) {
52
+ switch (request?.method) {
53
+ case "devtools/open":
54
+ return openDevTools(focusedEvent());
55
+ default:
56
+ return { ok: false };
57
+ }
58
+ }
59
+
60
+ function templateItems(menuId) {
61
+ return nativeMenuItems
62
+ .filter((item) => item.menuId === menuId)
63
+ .map((item) => ({
64
+ id: item.id,
65
+ label: item.label,
66
+ click: () => {
67
+ runNativeMenuRequest(item.nativeRequest);
68
+ },
69
+ }));
70
+ }
71
+
72
+ function registerNativeMenuItem(item) {
73
+ if (item?.id == null || item?.menuId == null || item?.label == null || item?.nativeRequest?.method == null) {
74
+ return { ok: false };
75
+ }
76
+ const nextItem = {
77
+ id: String(item.id),
78
+ menuId: String(item.menuId),
79
+ label: String(item.label),
80
+ nativeRequest: {
81
+ method: String(item.nativeRequest.method),
82
+ params: item.nativeRequest.params,
83
+ },
84
+ afterId: item.afterId == null ? null : String(item.afterId),
85
+ afterLabel: item.afterLabel == null ? null : String(item.afterLabel),
86
+ };
87
+ nativeMenuItems = nativeMenuItems.filter((existing) => existing.id !== nextItem.id);
88
+ nativeMenuItems.push(nextItem);
89
+ try {
90
+ refreshApplicationMenu?.();
91
+ } catch {}
92
+ logMenuDiagnostics();
93
+ return { ok: true };
94
+ }
95
+
96
+ function openMermaidViewer(params) {
97
+ const html = params?.html;
98
+ if (typeof html !== "string" || html.length === 0) return { ok: false };
99
+ const filePath = path.join(os.tmpdir(), `codex-plus-mermaid-${randomUUID()}.html`);
100
+ fs.writeFileSync(filePath, html, "utf8");
101
+ const window = new electron.BrowserWindow({
102
+ height: 900,
103
+ resizable: true,
104
+ show: true,
105
+ title: "Mermaid diagram viewer",
106
+ webPreferences: {
107
+ contextIsolation: true,
108
+ nodeIntegration: false,
109
+ sandbox: true,
110
+ },
111
+ width: 1400,
112
+ });
113
+ window.webContents.setWindowOpenHandler((event) => {
114
+ try {
115
+ const url = new URL(event.url);
116
+ if (url.protocol === "https:" && url.hostname === "mermaid.live") electron.shell.openExternal(event.url);
117
+ } catch {}
118
+ return { action: "deny" };
119
+ });
120
+ window.on("closed", () => {
121
+ try {
122
+ fs.unlinkSync(filePath);
123
+ } catch {}
124
+ });
125
+ window.loadURL(pathToFileURL(filePath).toString()).catch(() => {});
126
+ return { ok: true };
127
+ }
128
+
129
+ function registerNativeRequest({ isTrustedIpcEvent }) {
130
+ return electron.ipcMain.handle("codex_plus:native-request", async (event, request) => {
131
+ if (!isTrustedIpcEvent(event)) return { ok: false };
132
+ switch (request?.method) {
133
+ case "native-menu/register-item":
134
+ return registerNativeMenuItem(request.params);
135
+ case "devtools/open":
136
+ return openDevTools(event);
137
+ case "mermaid/openViewer":
138
+ return openMermaidViewer(request.params);
139
+ default:
140
+ return { ok: false };
141
+ }
142
+ });
143
+ }
144
+
145
+ function setRefreshApplicationMenu(refresh) {
146
+ refreshApplicationMenu = refresh;
147
+ }
148
+
149
+ return {
150
+ logMenuDiagnostics,
151
+ registerNativeRequest,
152
+ setRefreshApplicationMenu,
153
+ templateItems,
154
+ };
155
+ }
156
+
157
+ module.exports = {
158
+ create,
159
+ };
@@ -0,0 +1,58 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function fuzzyFilter(projects, query) {
5
+ const needle = String(query ?? "").trim().toLowerCase();
6
+ return globalObject.CodexPlus?.ui?.projectSelector?.fuzzyFilter?.(projects, query) ??
7
+ (needle
8
+ ? projects.filter((project) =>
9
+ [project.label, project.repositoryData?.rootFolder ?? "", project.path ?? "", project.hostDisplayName ?? ""].some((value) =>
10
+ String(value ?? "").toLowerCase().includes(needle),
11
+ ),
12
+ )
13
+ : projects);
14
+ }
15
+
16
+ function fuzzyHighlight(text, query, jsx) {
17
+ return globalObject.CodexPlus?.ui?.projectSelector?.fuzzyHighlight?.({ text, query, jsx }) ?? text;
18
+ }
19
+
20
+ function closeDropdown(event) {
21
+ const KeyboardEventConstructor = globalObject.KeyboardEvent;
22
+ if (typeof KeyboardEventConstructor !== "function") return;
23
+
24
+ const target = event?.target;
25
+ const dispatchTarget = typeof target?.dispatchEvent === "function" ? target : globalObject.document;
26
+ dispatchTarget?.dispatchEvent?.(new KeyboardEventConstructor("keydown", {
27
+ bubbles: true,
28
+ cancelable: true,
29
+ key: "Escape",
30
+ }));
31
+ }
32
+
33
+ function acceptFirst(event, projects, selectProjectId, query) {
34
+ const project = projects?.[0];
35
+ if (event?.key !== "Enter" || String(query ?? "").trim().length === 0 || project == null) return;
36
+ event.preventDefault?.();
37
+ event.stopPropagation?.();
38
+ selectProjectId(project.projectId);
39
+ closeDropdown(event);
40
+ }
41
+
42
+ function trigger(element, variant, React) {
43
+ return React.isValidElement(element)
44
+ ? React.cloneElement(element, {
45
+ ...element.props,
46
+ "data-codex-plus-project-selector-trigger": true,
47
+ "data-codex-plus-project-selector-variant": variant,
48
+ })
49
+ : element;
50
+ }
51
+
52
+ globalObject.CodexPlusHost.adapters.projectSelector = {
53
+ acceptFirst,
54
+ fuzzyFilter,
55
+ fuzzyHighlight,
56
+ trigger,
57
+ };
58
+ })();
@@ -0,0 +1,62 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function renderBodyFromHost(props, hostDeps) {
5
+ const [
6
+ jsxRuntime,
7
+ React,
8
+ useStore,
9
+ useAtom,
10
+ routeAtom,
11
+ cwdAtom,
12
+ hostIdAtom,
13
+ hostConfigAtom,
14
+ conversationIdAtom,
15
+ gitRequest,
16
+ pathValue,
17
+ DefaultReview,
18
+ Button,
19
+ Tooltip,
20
+ Icon,
21
+ Dropdown,
22
+ DropdownMenu,
23
+ BranchPickerDropdownContent,
24
+ ReviewToolbar,
25
+ parseDiff,
26
+ DiffCard,
27
+ ] = hostDeps;
28
+ const deps = {
29
+ jsx: jsxRuntime.jsx,
30
+ jsxs: jsxRuntime.jsxs,
31
+ Fragment: jsxRuntime.Fragment,
32
+ createElement: React.createElement,
33
+ React,
34
+ useStore,
35
+ useAtom,
36
+ routeAtom,
37
+ cwdAtom,
38
+ hostIdAtom,
39
+ hostConfigAtom,
40
+ conversationIdAtom,
41
+ gitRequest,
42
+ pathValue,
43
+ DefaultReview,
44
+ Button,
45
+ Tooltip,
46
+ Icon,
47
+ Dropdown,
48
+ DropdownMenu,
49
+ BranchPickerDropdownContent,
50
+ ReviewToolbar,
51
+ parseDiff,
52
+ DiffCard,
53
+ };
54
+ return globalObject.CodexPlus.ui.review.renderBody({
55
+ props,
56
+ deps,
57
+ defaultBody: props.mainReviewContent ?? deps.jsx(DefaultReview, props),
58
+ });
59
+ }
60
+
61
+ globalObject.CodexPlusHost.adapters.review = { renderBodyFromHost };
62
+ })();
@@ -0,0 +1,21 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function projectRowProps(project) {
5
+ return globalObject.CodexPlus?.ui?.sidebar?.projectRowProps?.({ project });
6
+ }
7
+
8
+ function threadRowProps(project) {
9
+ return globalObject.CodexPlus?.ui?.sidebar?.threadRowProps?.({ project });
10
+ }
11
+
12
+ function mergeThreadRowAttributes(base, extra) {
13
+ return globalObject.CodexPlus?.ui?.sidebar?.mergeDataAttributes?.(base, extra);
14
+ }
15
+
16
+ globalObject.CodexPlusHost.adapters.sidebar = {
17
+ mergeThreadRowAttributes,
18
+ projectRowProps,
19
+ threadRowProps,
20
+ };
21
+ })();
@@ -0,0 +1,9 @@
1
+ (function () {
2
+ const globalObject = typeof window !== "undefined" ? window : globalThis;
3
+
4
+ function accessories(context, deps) {
5
+ return globalObject.CodexPlus?.ui?.threadHeader?.renderAccessories?.({ context, deps }) ?? null;
6
+ }
7
+
8
+ globalObject.CodexPlusHost.adapters.threadHeader = { accessories };
9
+ })();
@@ -221,8 +221,15 @@ function isReadOnlyBranchRequest(requestKind, source) {
221
221
  return source === "codex_plus_review" && (requestKind === "recent-branches" || requestKind === "search-branches");
222
222
  }
223
223
 
224
+ function repositoryTargetsFromHost(gitManager, params, platform, signal, getSubmodulePaths) {
225
+ return repositoryTargets(gitManager, params, platform, signal, (root, submoduleSignal) =>
226
+ getSubmodulePaths(gitManager.getWorktreeRepositoryForRoot(root, platform), submoduleSignal),
227
+ );
228
+ }
229
+
224
230
  module.exports = {
225
231
  isReadOnlyBranchRequest,
232
+ repositoryTargetsFromHost,
226
233
  repositoryTargets,
227
234
  traceRequest,
228
235
  };
@@ -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
  "&": "&amp;",
@@ -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("mermaid.core-eIokQLcr.js"), debug })
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
- if (container.querySelector(`:scope > .${BUTTON_CLASS}`)) return;
229
- container.style.position ||= "relative";
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(container));
232
- container.prepend(control);
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}` +