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.
- package/README.md +2 -1
- package/package.json +4 -2
- package/src/patches/lib/common-patches.js +46 -66
- package/src/patches/lib/hooks/about.js +7 -0
- package/src/patches/lib/hooks/diagnostics.js +7 -0
- package/src/patches/lib/hooks/mermaid.js +7 -0
- package/src/patches/lib/hooks/message-composer.js +7 -0
- package/src/patches/lib/hooks/native-main.js +7 -0
- package/src/patches/lib/hooks/project-selector.js +12 -0
- package/src/patches/lib/hooks/review.js +7 -0
- package/src/patches/lib/hooks/settings-commands.js +12 -0
- package/src/patches/lib/hooks/sidebar.js +12 -0
- package/src/patches/lib/hooks/thread-header.js +7 -0
- package/src/patches/lib/hooks/worker.js +7 -0
- package/src/patches/lib/project-selector-shortcut-patch.js +7 -6
- package/src/runtime/api/about.js +16 -0
- package/src/runtime/api/commands.js +85 -0
- package/src/runtime/api/composer.js +14 -0
- package/src/runtime/api/diagnostics.js +38 -0
- package/src/runtime/api/errors.js +20 -0
- package/src/runtime/api/index.js +79 -0
- package/src/runtime/api/mermaid.js +14 -0
- package/src/runtime/api/message.js +14 -0
- package/src/runtime/api/modules.js +57 -0
- package/src/runtime/api/native.js +14 -0
- package/src/runtime/api/patches.js +31 -0
- package/src/runtime/api/review.js +20 -0
- package/src/runtime/api/settings.js +76 -0
- package/src/runtime/api/sidebar.js +24 -0
- package/src/runtime/api/styles.js +28 -0
- package/src/runtime/api/threadHeader.js +41 -0
- package/src/runtime/assets.js +58 -17
- package/src/runtime/host/messageComposer.js +16 -0
- package/src/runtime/host/nativeMain.js +159 -0
- package/src/runtime/host/projectSelector.js +58 -0
- package/src/runtime/host/review.js +62 -0
- package/src/runtime/host/sidebar.js +21 -0
- package/src/runtime/host/threadHeader.js +9 -0
- package/src/runtime/{worker.js → host/worker.js} +7 -0
- package/src/runtime/runtime.js +23 -441
|
@@ -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
|
};
|