codex-plus-patcher 0.7.1 → 0.8.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/package.json +1 -1
- package/src/cli.js +6 -0
- package/src/core/asar.js +6 -4
- package/src/core/dev-mode.js +69 -4
- package/src/core/plugin-audit.js +461 -13
- package/src/patches/26.623.31921-4452.js +45 -0
- package/src/patches/26.623.42026-4514.js +44 -0
- package/src/patches/index.js +4 -0
- package/src/patches/lib/common-patches.js +531 -2
- package/src/patches/lib/project-selector-shortcut-patch.js +130 -2
- package/src/runtime/host/projectSelector.js +7 -2
- package/src/runtime/plugins/projectColors.js +2 -0
- package/src/runtime/plugins/projectSelectorShortcut.js +27 -12
- package/src/runtime/plugins/userBubbleColors.js +4 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
const { readAsar, walkFiles } = require("./core/asar");
|
|
14
14
|
const {
|
|
15
15
|
DEFAULT_DEV_HOME,
|
|
16
|
+
DEFAULT_DEV_INSTANCE_ID,
|
|
16
17
|
DEFAULT_ELECTRON_USER_DATA,
|
|
17
18
|
formatLaunchDevResult,
|
|
18
19
|
formatSyncDevHomeResult,
|
|
@@ -49,12 +50,14 @@ function parseArgs(argv) {
|
|
|
49
50
|
includeNativeOpenProbes: false,
|
|
50
51
|
noProgress: false,
|
|
51
52
|
quiet: false,
|
|
53
|
+
devInstanceId: DEFAULT_DEV_INSTANCE_ID,
|
|
52
54
|
};
|
|
53
55
|
const rest = [...argv];
|
|
54
56
|
if (rest[0] && !rest[0].startsWith("--")) args.command = rest.shift();
|
|
55
57
|
if (args.command === "audit-plugins") {
|
|
56
58
|
args.target = DEFAULT_AUDIT_TARGET;
|
|
57
59
|
args.remoteDebuggingPort = DEFAULT_AUDIT_PORT;
|
|
60
|
+
args.devInstanceId = "audit";
|
|
58
61
|
}
|
|
59
62
|
for (let index = 0; index < rest.length; index += 1) {
|
|
60
63
|
const arg = rest[index];
|
|
@@ -68,6 +71,7 @@ function parseArgs(argv) {
|
|
|
68
71
|
else if (arg === "--source-home") args.sourceHome = path.resolve(expandPath(next()));
|
|
69
72
|
else if (arg === "--dev-home") args.devHome = path.resolve(expandPath(next()));
|
|
70
73
|
else if (arg === "--electron-user-data") args.electronUserDataPath = path.resolve(expandPath(next()));
|
|
74
|
+
else if (arg === "--dev-instance-id") args.devInstanceId = next();
|
|
71
75
|
else if (arg === "--remote-debugging-port" || arg === "--port") {
|
|
72
76
|
const value = next();
|
|
73
77
|
args.remoteDebuggingPort = args.command === "audit-plugins" ? Number(value) : value;
|
|
@@ -120,6 +124,7 @@ Options:
|
|
|
120
124
|
Isolated Electron userData for launch-dev. Default: ./work/codex-plus-electron-user-data
|
|
121
125
|
--remote-debugging-port <port>
|
|
122
126
|
Remote debugging port passed to launch-dev or audit-plugins
|
|
127
|
+
--dev-instance-id <id> Dev-only bundle identity suffix. Default: dev, or audit for audit-plugins
|
|
123
128
|
--asar <path> app.asar path for ASAR readback commands
|
|
124
129
|
--file <asar-path> Packed file path for asar-cat
|
|
125
130
|
--contains <text> Filter asar-list paths by substring
|
|
@@ -396,6 +401,7 @@ async function main() {
|
|
|
396
401
|
devHome: args.devHome,
|
|
397
402
|
electronUserDataPath: args.electronUserDataPath,
|
|
398
403
|
remoteDebuggingPort: args.remoteDebuggingPort,
|
|
404
|
+
devInstanceId: args.devInstanceId,
|
|
399
405
|
});
|
|
400
406
|
process.stdout.write(args.json ? `${JSON.stringify(result, null, 2)}\n` : formatLaunchDevResult(result));
|
|
401
407
|
return;
|
package/src/core/asar.js
CHANGED
|
@@ -11,9 +11,10 @@ function sha256File(file) {
|
|
|
11
11
|
|
|
12
12
|
function readAsar(asarPath) {
|
|
13
13
|
const buffer = fs.readFileSync(asarPath);
|
|
14
|
+
const headerSize = buffer.readUInt32LE(4);
|
|
14
15
|
const jsonSize = buffer.readUInt32LE(12);
|
|
15
16
|
const header = JSON.parse(buffer.subarray(16, 16 + jsonSize).toString("utf8"));
|
|
16
|
-
return { buffer, dataStart:
|
|
17
|
+
return { buffer, dataStart: 8 + headerSize, header };
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function walkFiles(node, prefix = "", out = []) {
|
|
@@ -99,13 +100,14 @@ function patchAsar(asarPath, fileTransforms, transformContext = {}) {
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
const json = Buffer.from(JSON.stringify(archive.header), "utf8");
|
|
103
|
+
const padding = Buffer.alloc((4 - (json.length % 4)) % 4);
|
|
102
104
|
const header = Buffer.alloc(16);
|
|
103
105
|
header.writeUInt32LE(4, 0);
|
|
104
|
-
header.writeUInt32LE(json.length + 8, 4);
|
|
105
|
-
header.writeUInt32LE(json.length + 4, 8);
|
|
106
|
+
header.writeUInt32LE(json.length + padding.length + 8, 4);
|
|
107
|
+
header.writeUInt32LE(json.length + padding.length + 4, 8);
|
|
106
108
|
header.writeUInt32LE(json.length, 12);
|
|
107
109
|
|
|
108
|
-
fs.writeFileSync(asarPath, Buffer.concat([header, json, ...dataBuffers]));
|
|
110
|
+
fs.writeFileSync(asarPath, Buffer.concat([header, json, padding, ...dataBuffers]));
|
|
109
111
|
return sha256File(asarPath);
|
|
110
112
|
}
|
|
111
113
|
|
package/src/core/dev-mode.js
CHANGED
|
@@ -4,12 +4,13 @@ const os = require("node:os");
|
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
|
|
6
6
|
const { patchAsar } = require("./asar");
|
|
7
|
-
const { setPlistBuddyValue } = require("./plist");
|
|
7
|
+
const { replacePlistString, setPlistBuddyValue } = require("./plist");
|
|
8
8
|
|
|
9
9
|
const ASAR_PATH_IN_BUNDLE = "Contents/Resources/app.asar";
|
|
10
10
|
const RUNTIME_MANIFEST_FILE = "webview/assets/codex-plus/runtime-manifest.js";
|
|
11
11
|
const DEFAULT_DEV_HOME = path.resolve("work/codex-plus-dev-home");
|
|
12
12
|
const DEFAULT_ELECTRON_USER_DATA = path.resolve("work/codex-plus-electron-user-data");
|
|
13
|
+
const DEFAULT_DEV_INSTANCE_ID = "dev";
|
|
13
14
|
const DEV_MODE_WARNING =
|
|
14
15
|
"Dev mode shares the original Codex worktrees. Use it for UI/plugin validation; do not edit the same checkout from regular Codex and Codex Plus at the same time.";
|
|
15
16
|
|
|
@@ -179,11 +180,40 @@ function syncDevHome({
|
|
|
179
180
|
};
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
function
|
|
183
|
+
function sanitizeDevInstanceId(devInstanceId) {
|
|
184
|
+
if (devInstanceId == null || devInstanceId === "") return null;
|
|
185
|
+
const sanitized = String(devInstanceId)
|
|
186
|
+
.trim()
|
|
187
|
+
.toLowerCase()
|
|
188
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
189
|
+
.replace(/^-+|-+$/g, "");
|
|
190
|
+
if (!sanitized) throw new Error("--dev-instance-id must contain at least one letter or number");
|
|
191
|
+
return sanitized;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function devBundleIdentity(devInstanceId) {
|
|
195
|
+
const sanitized = sanitizeDevInstanceId(devInstanceId);
|
|
196
|
+
if (!sanitized) return null;
|
|
197
|
+
return {
|
|
198
|
+
id: sanitized,
|
|
199
|
+
bundleIdentifier: `com.openai.codex-plus.${sanitized}`,
|
|
200
|
+
displayName: `Codex Plus (${sanitized})`,
|
|
201
|
+
name: `Codex Plus ${sanitized}`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function buildLaunchDev({
|
|
206
|
+
targetApp,
|
|
207
|
+
devHome = DEFAULT_DEV_HOME,
|
|
208
|
+
electronUserDataPath = DEFAULT_ELECTRON_USER_DATA,
|
|
209
|
+
remoteDebuggingPort,
|
|
210
|
+
devInstanceId = DEFAULT_DEV_INSTANCE_ID,
|
|
211
|
+
} = {}) {
|
|
183
212
|
if (!targetApp) throw new Error("--target is required");
|
|
184
213
|
const appBinary = path.join(path.resolve(targetApp), "Contents/MacOS/Codex");
|
|
185
214
|
const resolvedDevHome = path.resolve(devHome);
|
|
186
215
|
const resolvedElectronUserDataPath = path.resolve(electronUserDataPath);
|
|
216
|
+
const instanceIdentity = devBundleIdentity(devInstanceId);
|
|
187
217
|
const args = [`--user-data-dir=${resolvedElectronUserDataPath}`];
|
|
188
218
|
if (remoteDebuggingPort != null) args.push(`--remote-debugging-port=${remoteDebuggingPort}`);
|
|
189
219
|
return {
|
|
@@ -193,6 +223,7 @@ function buildLaunchDev({ targetApp, devHome = DEFAULT_DEV_HOME, electronUserDat
|
|
|
193
223
|
CODEX_HOME: resolvedDevHome,
|
|
194
224
|
CODEX_ELECTRON_USER_DATA_PATH: resolvedElectronUserDataPath,
|
|
195
225
|
},
|
|
226
|
+
instanceIdentity,
|
|
196
227
|
warning: DEV_MODE_WARNING,
|
|
197
228
|
};
|
|
198
229
|
}
|
|
@@ -217,18 +248,46 @@ function markDevRuntimeConfig(targetApp, { patchAsarImpl = patchAsar, setPlistBu
|
|
|
217
248
|
return { asar: asarPath, patchedAsarSha };
|
|
218
249
|
}
|
|
219
250
|
|
|
220
|
-
function
|
|
251
|
+
function signDevApp(targetApp, execFileSync = childProcess.execFileSync) {
|
|
252
|
+
execFileSync("/usr/bin/codesign", ["--force", "--deep", "--sign", "-", path.resolve(targetApp)], { stdio: "pipe" });
|
|
253
|
+
return { signed: true };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function markDevBundleIdentity(
|
|
257
|
+
targetApp,
|
|
258
|
+
devInstanceId = DEFAULT_DEV_INSTANCE_ID,
|
|
259
|
+
{ replacePlistStringImpl = replacePlistString } = {},
|
|
260
|
+
) {
|
|
261
|
+
const identity = devBundleIdentity(devInstanceId);
|
|
262
|
+
if (!identity) return null;
|
|
263
|
+
const plistPath = path.join(path.resolve(targetApp), "Contents/Info.plist");
|
|
264
|
+
replacePlistStringImpl(plistPath, "CFBundleIdentifier", identity.bundleIdentifier);
|
|
265
|
+
replacePlistStringImpl(plistPath, "CFBundleDisplayName", identity.displayName);
|
|
266
|
+
replacePlistStringImpl(plistPath, "CFBundleName", identity.name);
|
|
267
|
+
return identity;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function launchDevApp({
|
|
271
|
+
spawn = childProcess.spawn,
|
|
272
|
+
env = process.env,
|
|
273
|
+
markDevRuntimeConfigImpl = markDevRuntimeConfig,
|
|
274
|
+
markDevBundleIdentityImpl = markDevBundleIdentity,
|
|
275
|
+
signDevAppImpl = signDevApp,
|
|
276
|
+
...options
|
|
277
|
+
} = {}) {
|
|
221
278
|
const launch = buildLaunchDev(options);
|
|
222
279
|
fs.mkdirSync(launch.env.CODEX_HOME, { recursive: true });
|
|
223
280
|
fs.mkdirSync(launch.env.CODEX_ELECTRON_USER_DATA_PATH, { recursive: true });
|
|
224
281
|
const devRuntimeConfig = markDevRuntimeConfigImpl(options.targetApp);
|
|
282
|
+
const devBundle = markDevBundleIdentityImpl(options.targetApp, options.devInstanceId);
|
|
283
|
+
const devSignature = signDevAppImpl(options.targetApp);
|
|
225
284
|
const child = spawn(launch.command, launch.args, {
|
|
226
285
|
detached: true,
|
|
227
286
|
env: { ...env, ...launch.env },
|
|
228
287
|
stdio: "ignore",
|
|
229
288
|
});
|
|
230
289
|
child.unref();
|
|
231
|
-
return { ...launch, devRuntimeConfig, pid: child.pid };
|
|
290
|
+
return { ...launch, devRuntimeConfig, devBundle, devSignature, pid: child.pid };
|
|
232
291
|
}
|
|
233
292
|
|
|
234
293
|
function formatSyncDevHomeResult(result) {
|
|
@@ -255,6 +314,7 @@ function formatLaunchDevResult(result) {
|
|
|
255
314
|
`CODEX_ELECTRON_USER_DATA_PATH: ${result.env.CODEX_ELECTRON_USER_DATA_PATH}`,
|
|
256
315
|
];
|
|
257
316
|
if (result.pid != null) lines.push(`PID: ${result.pid}`);
|
|
317
|
+
if (result.instanceIdentity) lines.push(`Bundle identity: ${result.instanceIdentity.bundleIdentifier}`);
|
|
258
318
|
lines.push(`Warning: ${result.warning}`);
|
|
259
319
|
return `${lines.join("\n")}\n`;
|
|
260
320
|
}
|
|
@@ -262,13 +322,18 @@ function formatLaunchDevResult(result) {
|
|
|
262
322
|
module.exports = {
|
|
263
323
|
COPY_ENTRIES,
|
|
264
324
|
DEFAULT_DEV_HOME,
|
|
325
|
+
DEFAULT_DEV_INSTANCE_ID,
|
|
265
326
|
DEFAULT_ELECTRON_USER_DATA,
|
|
266
327
|
DEV_MODE_WARNING,
|
|
267
328
|
SQLITE_SNAPSHOT_ENTRIES,
|
|
268
329
|
buildLaunchDev,
|
|
330
|
+
devBundleIdentity,
|
|
269
331
|
formatLaunchDevResult,
|
|
270
332
|
formatSyncDevHomeResult,
|
|
271
333
|
launchDevApp,
|
|
334
|
+
markDevBundleIdentity,
|
|
272
335
|
markDevRuntimeConfig,
|
|
336
|
+
sanitizeDevInstanceId,
|
|
337
|
+
signDevApp,
|
|
273
338
|
syncDevHome,
|
|
274
339
|
};
|