@duanluan/codex-plus-plus-launcher 1.2.0 → 1.2.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.
- package/codex_plus_plus_launcher/__init__.py +1 -1
- package/npm/build-local-binary.cjs +28 -3
- package/npm/launcher.js +121 -4
- package/npm/plugin-auth-unlocked.js +1 -0
- package/package.json +3 -1
- package/patches/codex-plus-plus-plugin-unlock.patch +164 -0
- package/upstream-bin/darwin-arm64/codex-plus-plus +0 -0
- package/upstream-bin/darwin-arm64/codex-plus-plus-manager +0 -0
- package/upstream-bin/darwin-x64/codex-plus-plus +0 -0
- package/upstream-bin/darwin-x64/codex-plus-plus-manager +0 -0
- package/upstream-bin/linux-x64/codex-plus-plus +0 -0
- package/upstream-bin/upstream-release.json +13 -13
- package/upstream-bin/win32-x64/codex-plus-plus-manager.exe +0 -0
- package/upstream-bin/win32-x64/codex-plus-plus.exe +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.2.
|
|
1
|
+
__version__ = "1.2.1"
|
|
@@ -9,6 +9,14 @@ function packageRoot() {
|
|
|
9
9
|
return path.resolve(__dirname, '..');
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function packageVersion(root = packageRoot()) {
|
|
13
|
+
return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function defaultUpstreamRef(root = packageRoot()) {
|
|
17
|
+
return `v${packageVersion(root)}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
function run(command, args, options = {}) {
|
|
13
21
|
const result = spawnSync(command, args, { stdio: 'inherit', shell: false, ...options });
|
|
14
22
|
if (result.status !== 0) {
|
|
@@ -16,6 +24,11 @@ function run(command, args, options = {}) {
|
|
|
16
24
|
}
|
|
17
25
|
}
|
|
18
26
|
|
|
27
|
+
function runSucceeds(command, args, options = {}) {
|
|
28
|
+
const result = spawnSync(command, args, { stdio: 'ignore', shell: false, ...options });
|
|
29
|
+
return result.status === 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
function platformKey(platform = process.platform, arch = process.arch) {
|
|
20
33
|
return `${platform}-${arch}`;
|
|
21
34
|
}
|
|
@@ -42,10 +55,20 @@ function packageBuildArgs(key) {
|
|
|
42
55
|
return key === 'linux-x64' ? ['-p', 'codex-plus-launcher'] : [];
|
|
43
56
|
}
|
|
44
57
|
|
|
58
|
+
function applyPluginUnlockPatch(upstreamDir, root = packageRoot()) {
|
|
59
|
+
const patchPath = path.join(root, 'patches', 'codex-plus-plus-plugin-unlock.patch');
|
|
60
|
+
if (runSucceeds('git', ['apply', '--reverse', '--check', patchPath], { cwd: upstreamDir })) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
run('git', ['apply', '--check', patchPath], { cwd: upstreamDir });
|
|
64
|
+
run('git', ['apply', patchPath], { cwd: upstreamDir });
|
|
65
|
+
}
|
|
66
|
+
|
|
45
67
|
function main() {
|
|
46
68
|
const root = packageRoot();
|
|
47
|
-
const
|
|
48
|
-
const
|
|
69
|
+
const ref = process.env.CODEXPP_UPSTREAM_REF || defaultUpstreamRef(root);
|
|
70
|
+
const refKey = ref.replace(/[^A-Za-z0-9._-]/g, '_');
|
|
71
|
+
const upstreamDir = process.env.CODEXPP_UPSTREAM_DIR || path.join(os.tmpdir(), `CodexPlusPlus-upstream-build-${refKey}`);
|
|
49
72
|
const key = process.env.CODEXPP_SIDECAR_PLATFORM || platformKey();
|
|
50
73
|
const outDir = path.join(root, 'upstream-bin', key);
|
|
51
74
|
|
|
@@ -56,6 +79,8 @@ function main() {
|
|
|
56
79
|
run('git', ['checkout', 'FETCH_HEAD'], { cwd: upstreamDir });
|
|
57
80
|
}
|
|
58
81
|
|
|
82
|
+
applyPluginUnlockPatch(upstreamDir, root);
|
|
83
|
+
|
|
59
84
|
if (key !== 'linux-x64') {
|
|
60
85
|
run('npm', ['install', '--package-lock=false'], { cwd: path.join(upstreamDir, 'apps', 'codex-plus-manager'), shell: process.platform === 'win32' });
|
|
61
86
|
run('npm', ['run', 'vite:build'], { cwd: path.join(upstreamDir, 'apps', 'codex-plus-manager'), shell: process.platform === 'win32' });
|
|
@@ -100,4 +125,4 @@ if (require.main === module) {
|
|
|
100
125
|
}
|
|
101
126
|
}
|
|
102
127
|
|
|
103
|
-
module.exports = { buildTargetArgs, cargoTargetForKey, main, packageBuildArgs, platformKey };
|
|
128
|
+
module.exports = { applyPluginUnlockPatch, buildTargetArgs, cargoTargetForKey, defaultUpstreamRef, main, packageBuildArgs, platformKey };
|
package/npm/launcher.js
CHANGED
|
@@ -13,6 +13,8 @@ const MANAGER_NAME = 'Codex++ 管理工具';
|
|
|
13
13
|
const LINUX_SHIM_DIR_NAME = 'codex-desktop-linux-shim';
|
|
14
14
|
const LINUX_SHIM_BINARY = 'codex.exe';
|
|
15
15
|
const LINUX_DESKTOP_ENTRY = 'codex-plus-plus.desktop';
|
|
16
|
+
const PLUGIN_AUTH_UNLOCK_FILE = 'plugin-auth-unlocked.js';
|
|
17
|
+
const PLUGIN_AUTH_UNLOCK_CONTENT = 'function e(e){return false}export{e as t};\n';
|
|
16
18
|
|
|
17
19
|
function optionValue(options, key, fallback) {
|
|
18
20
|
const value = options[key];
|
|
@@ -63,6 +65,11 @@ function upstreamMetadataPath(options = {}) {
|
|
|
63
65
|
return path.join(root, 'upstream-bin', 'upstream-release.json');
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
function pluginAuthUnlockPath(options = {}) {
|
|
69
|
+
const root = optionValue(options, 'packageRoot', packageRoot);
|
|
70
|
+
return optionValue(options, 'pluginAuthUnlockPath', () => path.join(root, 'npm', PLUGIN_AUTH_UNLOCK_FILE));
|
|
71
|
+
}
|
|
72
|
+
|
|
66
73
|
function readJsonFile(candidate, fsImpl = fs) {
|
|
67
74
|
try {
|
|
68
75
|
return JSON.parse(fsImpl.readFileSync(candidate, 'utf8'));
|
|
@@ -585,11 +592,113 @@ function shellSingleQuote(value) {
|
|
|
585
592
|
return `'${String(value).replace(/'/g, "'\\''")}'`;
|
|
586
593
|
}
|
|
587
594
|
|
|
588
|
-
function linuxCodexShimScript(startScript) {
|
|
595
|
+
function linuxCodexShimScript(startScript, pluginAuthUnlockFile) {
|
|
589
596
|
return [
|
|
590
597
|
'#!/usr/bin/env bash',
|
|
591
598
|
'set -euo pipefail',
|
|
592
|
-
|
|
599
|
+
'',
|
|
600
|
+
`START_SCRIPT=${shellSingleQuote(startScript)}`,
|
|
601
|
+
`PLUGIN_AUTH_UNLOCK_FILE=${shellSingleQuote(pluginAuthUnlockFile)}`,
|
|
602
|
+
'TMP_APP_ROOT=""',
|
|
603
|
+
'CHILD_PID=""',
|
|
604
|
+
'',
|
|
605
|
+
'resolve_file_dir() {',
|
|
606
|
+
' local source="$1"',
|
|
607
|
+
' local dir',
|
|
608
|
+
' while [ -L "$source" ]; do',
|
|
609
|
+
' dir="$(cd -P "$(dirname "$source")" && pwd)"',
|
|
610
|
+
' source="$(readlink "$source")"',
|
|
611
|
+
' case "$source" in',
|
|
612
|
+
' /*) ;;',
|
|
613
|
+
' *) source="$dir/$source" ;;',
|
|
614
|
+
' esac',
|
|
615
|
+
' done',
|
|
616
|
+
' cd -P "$(dirname "$source")" && pwd',
|
|
617
|
+
'}',
|
|
618
|
+
'',
|
|
619
|
+
'cleanup() {',
|
|
620
|
+
' if [ -n "$TMP_APP_ROOT" ]; then',
|
|
621
|
+
' rm -rf "$TMP_APP_ROOT"',
|
|
622
|
+
' fi',
|
|
623
|
+
'}',
|
|
624
|
+
'',
|
|
625
|
+
'forward_signal() {',
|
|
626
|
+
' local sig="$1"',
|
|
627
|
+
' if [ -n "$CHILD_PID" ] && kill -0 "$CHILD_PID" 2>/dev/null; then',
|
|
628
|
+
' kill -"$sig" "$CHILD_PID" 2>/dev/null || true',
|
|
629
|
+
' fi',
|
|
630
|
+
'}',
|
|
631
|
+
'',
|
|
632
|
+
'trap cleanup EXIT',
|
|
633
|
+
"trap 'forward_signal HUP' HUP",
|
|
634
|
+
"trap 'forward_signal INT' INT",
|
|
635
|
+
"trap 'forward_signal TERM' TERM",
|
|
636
|
+
'',
|
|
637
|
+
'APP_ROOT="$(resolve_file_dir "$START_SCRIPT")"',
|
|
638
|
+
'WEBVIEW_DIR="$APP_ROOT/content/webview"',
|
|
639
|
+
'',
|
|
640
|
+
'if [ ! -f "$PLUGIN_AUTH_UNLOCK_FILE" ]; then',
|
|
641
|
+
' echo "Codex++ plugin auth unlock file not found: $PLUGIN_AUTH_UNLOCK_FILE" >&2',
|
|
642
|
+
' exit 1',
|
|
643
|
+
'fi',
|
|
644
|
+
'',
|
|
645
|
+
'if [ ! -d "$WEBVIEW_DIR" ]; then',
|
|
646
|
+
' exec "$START_SCRIPT" -- "$@"',
|
|
647
|
+
'fi',
|
|
648
|
+
'',
|
|
649
|
+
'TMP_APP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/codex-plus-plus-linux-app.XXXXXX")"',
|
|
650
|
+
'cp "$START_SCRIPT" "$TMP_APP_ROOT/start.sh"',
|
|
651
|
+
'chmod 755 "$TMP_APP_ROOT/start.sh"',
|
|
652
|
+
'',
|
|
653
|
+
'shopt -s dotglob nullglob',
|
|
654
|
+
'for entry in "$APP_ROOT"/*; do',
|
|
655
|
+
' name="$(basename "$entry")"',
|
|
656
|
+
' if [ "$name" = "start.sh" ] || [ "$name" = "content" ]; then',
|
|
657
|
+
' continue',
|
|
658
|
+
' fi',
|
|
659
|
+
' ln -s "$entry" "$TMP_APP_ROOT/$name"',
|
|
660
|
+
'done',
|
|
661
|
+
'shopt -u dotglob nullglob',
|
|
662
|
+
'',
|
|
663
|
+
'mkdir -p "$TMP_APP_ROOT/content/webview/assets"',
|
|
664
|
+
'if [ -d "$APP_ROOT/content" ]; then',
|
|
665
|
+
' shopt -s dotglob nullglob',
|
|
666
|
+
' for entry in "$APP_ROOT/content"/*; do',
|
|
667
|
+
' name="$(basename "$entry")"',
|
|
668
|
+
' if [ "$name" = "webview" ]; then',
|
|
669
|
+
' continue',
|
|
670
|
+
' fi',
|
|
671
|
+
' ln -s "$entry" "$TMP_APP_ROOT/content/$name"',
|
|
672
|
+
' done',
|
|
673
|
+
' shopt -u dotglob nullglob',
|
|
674
|
+
'fi',
|
|
675
|
+
'',
|
|
676
|
+
'shopt -s dotglob nullglob',
|
|
677
|
+
'for entry in "$WEBVIEW_DIR"/*; do',
|
|
678
|
+
' name="$(basename "$entry")"',
|
|
679
|
+
' if [ "$name" = "assets" ]; then',
|
|
680
|
+
' continue',
|
|
681
|
+
' fi',
|
|
682
|
+
' ln -s "$entry" "$TMP_APP_ROOT/content/webview/$name"',
|
|
683
|
+
'done',
|
|
684
|
+
'for entry in "$WEBVIEW_DIR/assets"/*; do',
|
|
685
|
+
' name="$(basename "$entry")"',
|
|
686
|
+
' if [[ "$name" == plugin-auth-*.js ]]; then',
|
|
687
|
+
' ln -s "$PLUGIN_AUTH_UNLOCK_FILE" "$TMP_APP_ROOT/content/webview/assets/$name"',
|
|
688
|
+
' else',
|
|
689
|
+
' ln -s "$entry" "$TMP_APP_ROOT/content/webview/assets/$name"',
|
|
690
|
+
' fi',
|
|
691
|
+
'done',
|
|
692
|
+
'shopt -u dotglob nullglob',
|
|
693
|
+
'',
|
|
694
|
+
'"$TMP_APP_ROOT/start.sh" -- "$@" &',
|
|
695
|
+
'CHILD_PID=$!',
|
|
696
|
+
'set +e',
|
|
697
|
+
'wait "$CHILD_PID"',
|
|
698
|
+
'STATUS=$?',
|
|
699
|
+
'set -e',
|
|
700
|
+
'CHILD_PID=""',
|
|
701
|
+
'exit "$STATUS"',
|
|
593
702
|
'',
|
|
594
703
|
].join('\n');
|
|
595
704
|
}
|
|
@@ -599,9 +708,16 @@ function writeLinuxCodexShim(installation, options = {}) {
|
|
|
599
708
|
const shimRoot = linuxShimRoot(options);
|
|
600
709
|
fsImpl.mkdirSync(shimRoot, { recursive: true });
|
|
601
710
|
const shimPath = path.join(shimRoot, LINUX_SHIM_BINARY);
|
|
602
|
-
|
|
711
|
+
const pluginAuthTarget = path.join(shimRoot, PLUGIN_AUTH_UNLOCK_FILE);
|
|
712
|
+
const pluginAuthSource = pluginAuthUnlockPath(options);
|
|
713
|
+
if (fsImpl.existsSync(pluginAuthSource)) {
|
|
714
|
+
fsImpl.copyFileSync(pluginAuthSource, pluginAuthTarget);
|
|
715
|
+
} else {
|
|
716
|
+
fsImpl.writeFileSync(pluginAuthTarget, PLUGIN_AUTH_UNLOCK_CONTENT, 'utf8');
|
|
717
|
+
}
|
|
718
|
+
fsImpl.writeFileSync(shimPath, linuxCodexShimScript(installation.startScript, pluginAuthTarget), 'utf8');
|
|
603
719
|
fsImpl.chmodSync(shimPath, 0o755);
|
|
604
|
-
return { shimRoot, shimPath };
|
|
720
|
+
return { shimRoot, shimPath, pluginAuthUnlock: pluginAuthTarget };
|
|
605
721
|
}
|
|
606
722
|
|
|
607
723
|
function linuxDesktopEntry({ name, execPath, iconPath, comment }) {
|
|
@@ -756,6 +872,7 @@ async function installLinuxApp(options = {}) {
|
|
|
756
872
|
const shim = writeLinuxCodexShim(installation, options);
|
|
757
873
|
installed.linuxShim = shim.shimPath;
|
|
758
874
|
installed.linuxShimRoot = shim.shimRoot;
|
|
875
|
+
installed.linuxPluginAuthUnlock = shim.pluginAuthUnlock;
|
|
759
876
|
installed.linuxCodexStart = installation.startScript;
|
|
760
877
|
const entrypoints = await installEntrypoints(installed, { ...options, installRoot: installed.installRoot });
|
|
761
878
|
const statePath = writeLinuxInstallState(installed, installation, options);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){return false}export{e as t};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duanluan/codex-plus-plus-launcher",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Install and launch Codex++ from npm",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cxpp": "npm/cxpp.js",
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"codex_plus_plus_launcher/*.py",
|
|
17
17
|
"codex_plus_plus_launcher/assets/*",
|
|
18
|
+
"patches/**",
|
|
18
19
|
"upstream-bin/**",
|
|
19
20
|
"install-npm.cjs",
|
|
20
21
|
"npm/cxpp.js",
|
|
21
22
|
"npm/i18n.js",
|
|
22
23
|
"npm/launcher.js",
|
|
23
24
|
"npm/install.js",
|
|
25
|
+
"npm/plugin-auth-unlocked.js",
|
|
24
26
|
"npm/build-local-binary.cjs",
|
|
25
27
|
"npm/verify-package.cjs",
|
|
26
28
|
"npm/smoke-install.cjs",
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
--- a/assets/inject/renderer-inject.js
|
|
2
|
+
+++ b/assets/inject/renderer-inject.js
|
|
3
|
+
@@ -67,0 +68 @@
|
|
4
|
+
+ const codexPluginNavUnlockVersion = "2";
|
|
5
|
+
@@ -2701,0 +2703,154 @@
|
|
6
|
+
+ function pluginNavButtonCandidates() {
|
|
7
|
+
+ return Array.from(document.querySelectorAll(selectors.pluginNavButton))
|
|
8
|
+
+ .filter((button) => button instanceof HTMLElement && isPluginNavButton(button));
|
|
9
|
+
+ }
|
|
10
|
+
+
|
|
11
|
+
+ function isPluginNavButton(button) {
|
|
12
|
+
+ const text = (button.textContent || "").trim();
|
|
13
|
+
+ if (/^(Plugins|插件)$/.test(text)) return true;
|
|
14
|
+
+ return !!button.querySelector?.(selectors.pluginSvgPath);
|
|
15
|
+
+ }
|
|
16
|
+
+
|
|
17
|
+
+ function reactPropKeys(element) {
|
|
18
|
+
+ return Object.keys(element || {}).filter((key) => key.startsWith("__reactProps"));
|
|
19
|
+
+ }
|
|
20
|
+
+
|
|
21
|
+
+ function reactPropsFor(element) {
|
|
22
|
+
+ return reactPropKeys(element)
|
|
23
|
+
+ .map((key) => element[key])
|
|
24
|
+
+ .filter((props) => props && typeof props === "object");
|
|
25
|
+
+ }
|
|
26
|
+
+
|
|
27
|
+
+ function reactFiberFor(element) {
|
|
28
|
+
+ const key = Object.keys(element || {}).find((key) => key.startsWith("__reactFiber"));
|
|
29
|
+
+ return key ? element[key] : null;
|
|
30
|
+
+ }
|
|
31
|
+
+
|
|
32
|
+
+ function reactPropHandlersFor(element) {
|
|
33
|
+
+ const handlers = reactPropsFor(element)
|
|
34
|
+
+ .map((props) => props.onClick)
|
|
35
|
+
+ .filter((handler) => typeof handler === "function");
|
|
36
|
+
+ const fiber = reactFiberFor(element);
|
|
37
|
+
+ [
|
|
38
|
+
+ fiber?.memoizedProps?.onClick,
|
|
39
|
+
+ fiber?.pendingProps?.onClick,
|
|
40
|
+
+ fiber?.alternate?.memoizedProps?.onClick,
|
|
41
|
+
+ fiber?.alternate?.pendingProps?.onClick,
|
|
42
|
+
+ ].forEach((handler) => {
|
|
43
|
+
+ if (typeof handler === "function") handlers.push(handler);
|
|
44
|
+
+ });
|
|
45
|
+
+ return Array.from(new Set(handlers));
|
|
46
|
+
+ }
|
|
47
|
+
+
|
|
48
|
+
+ function reactClickHandlerFor(element) {
|
|
49
|
+
+ for (const handler of reactPropHandlersFor(element)) {
|
|
50
|
+
+ if (typeof handler === "function") return handler;
|
|
51
|
+
+ }
|
|
52
|
+
+ return null;
|
|
53
|
+
+ }
|
|
54
|
+
+
|
|
55
|
+
+ function isUsefulPluginNavClickHandler(handler) {
|
|
56
|
+
+ if (typeof handler !== "function") return false;
|
|
57
|
+
+ const source = Function.prototype.toString.call(handler);
|
|
58
|
+
+ if (/^\s*(?:\(\)\s*=>\s*\{\s*\}|function\s*[^(]*\([^)]*\)\s*\{\s*\})\s*$/.test(source)) return false;
|
|
59
|
+
+ if (source.includes("navigateToCodexPlugins")) return false;
|
|
60
|
+
+ return true;
|
|
61
|
+
+ }
|
|
62
|
+
+
|
|
63
|
+
+ function isSkillsRouteClickHandler(handler) {
|
|
64
|
+
+ if (!isUsefulPluginNavClickHandler(handler)) return false;
|
|
65
|
+
+ const source = Function.prototype.toString.call(handler);
|
|
66
|
+
+ return source.includes("Uy(") || source.includes("/skills");
|
|
67
|
+
+ }
|
|
68
|
+
+
|
|
69
|
+
+ function isSkillsNavButton(button) {
|
|
70
|
+
+ const text = (button.textContent || "").trim();
|
|
71
|
+
+ return /^(Skills|技能)$/.test(text);
|
|
72
|
+
+ }
|
|
73
|
+
+
|
|
74
|
+
+ function pluginNavFallbackClickHandler(button) {
|
|
75
|
+
+ const ownSkillsHandler = reactPropHandlersFor(button).find(isSkillsRouteClickHandler);
|
|
76
|
+
+ if (ownSkillsHandler) return ownSkillsHandler;
|
|
77
|
+
+ const currentHandler = reactClickHandlerFor(button);
|
|
78
|
+
+ if (isUsefulPluginNavClickHandler(currentHandler)) return currentHandler;
|
|
79
|
+
+ const nav = button.closest?.('nav[role="navigation"]');
|
|
80
|
+
+ const candidates = Array.from(nav?.querySelectorAll?.(selectors.pluginNavButton) || []);
|
|
81
|
+
+ for (const candidate of candidates) {
|
|
82
|
+
+ if (candidate === button) continue;
|
|
83
|
+
+ const handlers = reactPropHandlersFor(candidate);
|
|
84
|
+
+ const skillsHandler = handlers.find(isSkillsRouteClickHandler);
|
|
85
|
+
+ if (skillsHandler) return skillsHandler;
|
|
86
|
+
+ }
|
|
87
|
+
+ const skillsButton = candidates.find((candidate) => candidate !== button && isSkillsNavButton(candidate));
|
|
88
|
+
+ const skillsHandler = reactClickHandlerFor(skillsButton);
|
|
89
|
+
+ if (isUsefulPluginNavClickHandler(skillsHandler)) return skillsHandler;
|
|
90
|
+
+ return null;
|
|
91
|
+
+ }
|
|
92
|
+
+
|
|
93
|
+
+ function patchReactPluginNavProps(element) {
|
|
94
|
+
+ const pluginHandler = pluginNavFallbackClickHandler(element);
|
|
95
|
+
+ reactPropsFor(element)
|
|
96
|
+
+ .forEach((props) => {
|
|
97
|
+
+ props.disabled = false;
|
|
98
|
+
+ props["aria-disabled"] = false;
|
|
99
|
+
+ props["data-disabled"] = undefined;
|
|
100
|
+
+ if (pluginHandler && !isUsefulPluginNavClickHandler(props.onClick)) {
|
|
101
|
+
+ props.onClick = pluginHandler;
|
|
102
|
+
+ }
|
|
103
|
+
+ });
|
|
104
|
+
+ }
|
|
105
|
+
+
|
|
106
|
+
+ function clearPluginNavDisabledState(element) {
|
|
107
|
+
+ if (!(element instanceof HTMLElement)) return;
|
|
108
|
+
+ if ("disabled" in element) element.disabled = false;
|
|
109
|
+
+ element.removeAttribute("disabled");
|
|
110
|
+
+ element.removeAttribute("aria-disabled");
|
|
111
|
+
+ element.removeAttribute("data-disabled");
|
|
112
|
+
+ element.removeAttribute("inert");
|
|
113
|
+
+ element.classList.remove("disabled", "opacity-50", "cursor-not-allowed", "pointer-events-none");
|
|
114
|
+
+ element.style.pointerEvents = "auto";
|
|
115
|
+
+ element.style.opacity = "";
|
|
116
|
+
+ element.style.cursor = "pointer";
|
|
117
|
+
+ element.tabIndex = 0;
|
|
118
|
+
+ patchReactPluginNavProps(element);
|
|
119
|
+
+ }
|
|
120
|
+
+
|
|
121
|
+
+ function pluginNavUnlockNodes(button) {
|
|
122
|
+
+ const nodes = [button];
|
|
123
|
+
+ button.querySelectorAll?.("[disabled], [aria-disabled], [data-disabled], .cursor-not-allowed, .pointer-events-none")
|
|
124
|
+
+ .forEach((node) => nodes.push(node));
|
|
125
|
+
+ let parent = button.parentElement;
|
|
126
|
+
+ for (let depth = 0; parent && depth < 3; depth += 1, parent = parent.parentElement) {
|
|
127
|
+
+ if (parent.matches?.("button, [role='button'], [disabled], [aria-disabled], [data-disabled], .cursor-not-allowed, .pointer-events-none")) {
|
|
128
|
+
+ nodes.push(parent);
|
|
129
|
+
+ }
|
|
130
|
+
+ }
|
|
131
|
+
+ return Array.from(new Set(nodes));
|
|
132
|
+
+ }
|
|
133
|
+
+
|
|
134
|
+
+ function unlockPluginNavButtons() {
|
|
135
|
+
+ if (!codexPlusSettings().pluginMarketplaceUnlock) return;
|
|
136
|
+
+ pluginNavButtonCandidates().forEach((button) => {
|
|
137
|
+
+ button.dataset.codexPluginNavUnlocked = codexPluginNavUnlockVersion;
|
|
138
|
+
+ pluginNavUnlockNodes(button).forEach(clearPluginNavDisabledState);
|
|
139
|
+
+ });
|
|
140
|
+
+ }
|
|
141
|
+
+
|
|
142
|
+
+ function refreshPluginNavUnlockLoop() {
|
|
143
|
+
+ const shouldRun = codexPlusSettings().pluginMarketplaceUnlock;
|
|
144
|
+
+ if (!shouldRun) {
|
|
145
|
+
+ clearInterval(window.__codexPluginNavUnlockRefreshTimer);
|
|
146
|
+
+ window.__codexPluginNavUnlockRefreshTimer = null;
|
|
147
|
+
+ return;
|
|
148
|
+
+ }
|
|
149
|
+
+ if (window.__codexPluginNavUnlockRefreshTimer) return;
|
|
150
|
+
+ window.__codexPluginNavUnlockRefreshTimer = setInterval(() => {
|
|
151
|
+
+ if (!codexPlusSettings().pluginMarketplaceUnlock) {
|
|
152
|
+
+ clearInterval(window.__codexPluginNavUnlockRefreshTimer);
|
|
153
|
+
+ window.__codexPluginNavUnlockRefreshTimer = null;
|
|
154
|
+
+ return;
|
|
155
|
+
+ }
|
|
156
|
+
+ unlockPluginNavButtons();
|
|
157
|
+
+ }, codexForcePluginInstallRefreshIntervalMs);
|
|
158
|
+
+ }
|
|
159
|
+
+
|
|
160
|
+
@@ -7592,0 +7748,2 @@
|
|
161
|
+
+ unlockPluginNavButtons();
|
|
162
|
+
+ refreshPluginNavUnlockLoop();
|
|
163
|
+
@@ -7647,0 +7805 @@
|
|
164
|
+
+ selectors.pluginNavButton,
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "v1.2.
|
|
3
|
-
"html_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/tag/v1.2.
|
|
4
|
-
"asset_name": "CodexPlusPlus-1.2.
|
|
5
|
-
"asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.
|
|
6
|
-
"windows_asset_name": "CodexPlusPlus-1.2.
|
|
7
|
-
"windows_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.
|
|
8
|
-
"macos_x64_asset_name": "CodexPlusPlus-1.2.
|
|
9
|
-
"macos_x64_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.
|
|
10
|
-
"macos_arm64_asset_name": "CodexPlusPlus-1.2.
|
|
11
|
-
"macos_arm64_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.
|
|
12
|
-
"source_zip_url": "https://github.com/BigPizzaV3/CodexPlusPlus/archive/refs/tags/v1.2.
|
|
13
|
-
"install_spec": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.
|
|
14
|
-
"commit": "
|
|
2
|
+
"version": "v1.2.1",
|
|
3
|
+
"html_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/tag/v1.2.1",
|
|
4
|
+
"asset_name": "CodexPlusPlus-1.2.1-macos-arm64.dmg",
|
|
5
|
+
"asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.1/CodexPlusPlus-1.2.1-macos-arm64.dmg",
|
|
6
|
+
"windows_asset_name": "CodexPlusPlus-1.2.1-windows-x64-setup.exe",
|
|
7
|
+
"windows_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.1/CodexPlusPlus-1.2.1-windows-x64-setup.exe",
|
|
8
|
+
"macos_x64_asset_name": "CodexPlusPlus-1.2.1-macos-x64.dmg",
|
|
9
|
+
"macos_x64_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.1/CodexPlusPlus-1.2.1-macos-x64.dmg",
|
|
10
|
+
"macos_arm64_asset_name": "CodexPlusPlus-1.2.1-macos-arm64.dmg",
|
|
11
|
+
"macos_arm64_asset_url": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.1/CodexPlusPlus-1.2.1-macos-arm64.dmg",
|
|
12
|
+
"source_zip_url": "https://github.com/BigPizzaV3/CodexPlusPlus/archive/refs/tags/v1.2.1.zip",
|
|
13
|
+
"install_spec": "https://github.com/BigPizzaV3/CodexPlusPlus/releases/download/v1.2.1/CodexPlusPlus-1.2.1-macos-arm64.dmg",
|
|
14
|
+
"commit": "b20ca373d2e5a29bb75b532bd93f74bac18626f5",
|
|
15
15
|
"repository": "BigPizzaV3/CodexPlusPlus"
|
|
16
16
|
}
|
|
Binary file
|
|
Binary file
|