minecodex 0.1.16 → 0.1.18
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
CHANGED
|
@@ -613,6 +613,18 @@ export class MacPlatformAdapter {
|
|
|
613
613
|
return true;
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
async codexProcessStartedMsAgo(processInfo) {
|
|
617
|
+
if (!processInfo || !Number.isInteger(processInfo.pid) || processInfo.pid <= 1) return null;
|
|
618
|
+
const { stdout } = await this.execFile("/bin/ps", ["-axo", "pid=,lstart="]);
|
|
619
|
+
const line = String(stdout).split("\n").find((row) => {
|
|
620
|
+
const match = row.match(/\s*(\d+)\s+(.*)/);
|
|
621
|
+
return match?.[1] === String(processInfo.pid);
|
|
622
|
+
});
|
|
623
|
+
const startedAt = line ? Date.parse(line.replace(/^\s*\d+\s+/, "")) : Number.NaN;
|
|
624
|
+
if (!line || !Number.isFinite(startedAt)) return null;
|
|
625
|
+
return Math.max(0, Date.now() - startedAt);
|
|
626
|
+
}
|
|
627
|
+
|
|
616
628
|
async terminateNativeCodex(pid, expectedCommand = null) {
|
|
617
629
|
if (!Number.isInteger(pid) || pid <= 1) {
|
|
618
630
|
throw new Error("MineCodex requires an exact ChatGPT PID to terminate.");
|
|
@@ -120,7 +120,8 @@ export class RuntimeManager {
|
|
|
120
120
|
waitForReady: readyWaiter = waitForReady,
|
|
121
121
|
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
122
122
|
stopTimeoutMs = 5_000,
|
|
123
|
-
manualLaunchPollMs =
|
|
123
|
+
manualLaunchPollMs = 150,
|
|
124
|
+
manualTakeoverGraceMs = 60_000,
|
|
124
125
|
cdpPort = Number(process.env.CODEX_RUNTIME_CDP_PORT ?? 9231),
|
|
125
126
|
launchCoordinator = null,
|
|
126
127
|
}) {
|
|
@@ -132,6 +133,7 @@ export class RuntimeManager {
|
|
|
132
133
|
this.sleep = sleep;
|
|
133
134
|
this.stopTimeoutMs = stopTimeoutMs;
|
|
134
135
|
this.manualLaunchPollMs = manualLaunchPollMs;
|
|
136
|
+
this.manualTakeoverGraceMs = manualTakeoverGraceMs;
|
|
135
137
|
this.cdpPort = cdpPort;
|
|
136
138
|
this.child = null;
|
|
137
139
|
this.appliedFeatures = [];
|
|
@@ -327,6 +329,19 @@ export class RuntimeManager {
|
|
|
327
329
|
this.manualLaunchArmed = false;
|
|
328
330
|
}
|
|
329
331
|
|
|
332
|
+
async isManualTakeoverAllowed(processInfo) {
|
|
333
|
+
if (typeof this.platform?.codexProcessStartedMsAgo !== "function") return true;
|
|
334
|
+
let startedMsAgo;
|
|
335
|
+
try {
|
|
336
|
+
startedMsAgo = await this.platform.codexProcessStartedMsAgo(processInfo);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
this.logger.warn?.("MineCodex could not read the ChatGPT start time", error.message);
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
if (!Number.isInteger(startedMsAgo) || startedMsAgo < 0) return true;
|
|
342
|
+
return startedMsAgo < this.manualTakeoverGraceMs;
|
|
343
|
+
}
|
|
344
|
+
|
|
330
345
|
async reconcileManualCodexLaunch() {
|
|
331
346
|
if (this.manualLaunchMonitorStopped || this.manualLaunchSuppressionDepth > 0) return false;
|
|
332
347
|
const snapshot = await this.nativeCodexSnapshot();
|
|
@@ -372,6 +387,14 @@ export class RuntimeManager {
|
|
|
372
387
|
return false;
|
|
373
388
|
}
|
|
374
389
|
try {
|
|
390
|
+
if (!(await this.isManualTakeoverAllowed(currentProcess))) {
|
|
391
|
+
this.enhancementFailure = {
|
|
392
|
+
code: "OFFICIAL_CHATGPT_IN_USE",
|
|
393
|
+
message: "MineCodex left the official ChatGPT instance running because it was already in use.",
|
|
394
|
+
phase: "launch",
|
|
395
|
+
};
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
375
398
|
const result = await this.launchCoordinator.ensureObservedLaunch(currentProcess, {
|
|
376
399
|
stopRuntime: () => this.stopInternal(),
|
|
377
400
|
startRuntime: () => this.startInternal(),
|
|
@@ -2992,42 +2992,6 @@ export function createInjectionSource(features, {
|
|
|
2992
2992
|
return null;
|
|
2993
2993
|
}
|
|
2994
2994
|
|
|
2995
|
-
function nativeJsxRuntime(appModule) {
|
|
2996
|
-
const candidates = Object.values(appModule).filter((value) => {
|
|
2997
|
-
if (typeof value !== "function" || value.length !== 0) return false;
|
|
2998
|
-
let source;
|
|
2999
|
-
try {
|
|
3000
|
-
source = Function.prototype.toString.call(value);
|
|
3001
|
-
} catch {
|
|
3002
|
-
return false;
|
|
3003
|
-
}
|
|
3004
|
-
if (source.length > 1200) return false;
|
|
3005
|
-
if (
|
|
3006
|
-
source.includes("useState")
|
|
3007
|
-
|| source.includes("memo_cache_sentinel")
|
|
3008
|
-
|| source.includes("(0,")
|
|
3009
|
-
|| source.startsWith("class ")
|
|
3010
|
-
) return false;
|
|
3011
|
-
return source.includes("jsxs") && source.includes("Fragment");
|
|
3012
|
-
});
|
|
3013
|
-
for (const candidate of candidates) {
|
|
3014
|
-
let runtime;
|
|
3015
|
-
try {
|
|
3016
|
-
runtime = candidate();
|
|
3017
|
-
} catch {
|
|
3018
|
-
continue;
|
|
3019
|
-
}
|
|
3020
|
-
if (
|
|
3021
|
-
runtime
|
|
3022
|
-
&& typeof runtime === "object"
|
|
3023
|
-
&& typeof runtime.jsx === "function"
|
|
3024
|
-
&& typeof runtime.jsxs === "function"
|
|
3025
|
-
&& "Fragment" in runtime
|
|
3026
|
-
) return runtime;
|
|
3027
|
-
}
|
|
3028
|
-
return null;
|
|
3029
|
-
}
|
|
3030
|
-
|
|
3031
2995
|
async function loadNativeTabCapability() {
|
|
3032
2996
|
if (nativeTabCapability) return nativeTabCapability;
|
|
3033
2997
|
if (nativeTabCapabilityPromise) return nativeTabCapabilityPromise;
|
|
@@ -3045,15 +3009,9 @@ export function createInjectionSource(features, {
|
|
|
3045
3009
|
&& value.panelId === "right"
|
|
3046
3010
|
));
|
|
3047
3011
|
if (!controller) throw new Error("Codex right-panel controller is unavailable");
|
|
3048
|
-
|
|
3049
|
-
if (
|
|
3050
|
-
!controller?.tabById$
|
|
3051
|
-
|| typeof jsx?.jsx !== "function"
|
|
3052
|
-
|| typeof jsx?.jsxs !== "function"
|
|
3053
|
-
) throw new Error("Codex native tab capability is incomplete");
|
|
3012
|
+
if (!controller?.tabById$) throw new Error("Codex native tab capability is incomplete");
|
|
3054
3013
|
nativeTabCapability = {
|
|
3055
3014
|
controller,
|
|
3056
|
-
jsx,
|
|
3057
3015
|
moduleAsset: moduleUrl.split("/").pop(),
|
|
3058
3016
|
};
|
|
3059
3017
|
nativeTabCapabilityError = null;
|
|
@@ -3068,10 +3026,20 @@ export function createInjectionSource(features, {
|
|
|
3068
3026
|
return capability;
|
|
3069
3027
|
}
|
|
3070
3028
|
|
|
3071
|
-
function
|
|
3029
|
+
function nativeReactElement(type, props) {
|
|
3030
|
+
return {
|
|
3031
|
+
$$typeof: Symbol.for("react.transitional.element"),
|
|
3032
|
+
type,
|
|
3033
|
+
key: null,
|
|
3034
|
+
ref: null,
|
|
3035
|
+
props: props ?? {},
|
|
3036
|
+
};
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
function nativeDetailIcon(feature, detail) {
|
|
3072
3040
|
const icon = detail.icon ?? feature.icon;
|
|
3073
3041
|
if (!icon?.markup) return undefined;
|
|
3074
|
-
return
|
|
3042
|
+
return nativeReactElement("svg", {
|
|
3075
3043
|
width: 16,
|
|
3076
3044
|
height: 16,
|
|
3077
3045
|
viewBox: icon.viewBox ?? "0 0 24 24",
|
|
@@ -3086,14 +3054,13 @@ export function createInjectionSource(features, {
|
|
|
3086
3054
|
});
|
|
3087
3055
|
}
|
|
3088
3056
|
|
|
3089
|
-
function nativeDetailComponent(feature, detail
|
|
3057
|
+
function nativeDetailComponent(feature, detail) {
|
|
3090
3058
|
const detailKey = `${feature.id}:${detail.id}`;
|
|
3091
3059
|
let Component = nativeDetailComponents.get(detailKey);
|
|
3092
3060
|
if (Component) return Component;
|
|
3093
|
-
const { jsx } = capability;
|
|
3094
3061
|
const frameName = surfaceFrameName(feature.id);
|
|
3095
3062
|
Component = function CodexPersonalDetailTab() {
|
|
3096
|
-
return
|
|
3063
|
+
return nativeReactElement("div", {
|
|
3097
3064
|
"data-codex-personal-native-detail": detailKey,
|
|
3098
3065
|
style: {
|
|
3099
3066
|
height: "100%",
|
|
@@ -3101,7 +3068,7 @@ export function createInjectionSource(features, {
|
|
|
3101
3068
|
overflow: "hidden",
|
|
3102
3069
|
background: "var(--color-token-main-surface-primary)",
|
|
3103
3070
|
},
|
|
3104
|
-
children:
|
|
3071
|
+
children: nativeReactElement("iframe", {
|
|
3105
3072
|
name: frameName,
|
|
3106
3073
|
src: "about:blank",
|
|
3107
3074
|
title: detail.label,
|
|
@@ -3152,7 +3119,7 @@ export function createInjectionSource(features, {
|
|
|
3152
3119
|
return null;
|
|
3153
3120
|
}
|
|
3154
3121
|
|
|
3155
|
-
const { controller
|
|
3122
|
+
const { controller } = capability;
|
|
3156
3123
|
const tabId = `${feature.id}-${detail.id}`;
|
|
3157
3124
|
const detailKey = `${feature.id}:${detail.id}`;
|
|
3158
3125
|
let session = Array.from(nativeOpenTabSessions).find((candidate) => (
|
|
@@ -3171,12 +3138,12 @@ export function createInjectionSource(features, {
|
|
|
3171
3138
|
}
|
|
3172
3139
|
|
|
3173
3140
|
try {
|
|
3174
|
-
controller.openTab(scope, nativeDetailComponent(feature, detail
|
|
3141
|
+
controller.openTab(scope, nativeDetailComponent(feature, detail), {
|
|
3175
3142
|
id: tabId,
|
|
3176
3143
|
kind: tabId,
|
|
3177
3144
|
title: detail.label,
|
|
3178
3145
|
tooltip: detail.label,
|
|
3179
|
-
icon: nativeDetailIcon(feature, detail
|
|
3146
|
+
icon: nativeDetailIcon(feature, detail),
|
|
3180
3147
|
isClosable: true,
|
|
3181
3148
|
props: {},
|
|
3182
3149
|
onClose: () => {
|