@bjesuiter/codex-switcher 1.8.2 → 1.8.4
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 -6
- package/cdx.mjs +232 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,15 +6,11 @@ Switch the coding-agents [pi](https://pi.dev/), [codex](https://developers.opena
|
|
|
6
6
|
|
|
7
7
|
## Latest Changes
|
|
8
8
|
|
|
9
|
-
### 1.8.
|
|
10
|
-
|
|
11
|
-
#### Features
|
|
12
|
-
|
|
13
|
-
- Added `update-self` command aliases: `self-update`, `update`, and `updte`.
|
|
9
|
+
### 1.8.4
|
|
14
10
|
|
|
15
11
|
#### Fixes
|
|
16
12
|
|
|
17
|
-
-
|
|
13
|
+
- Linux `cdx doctor` guided checks now detect `gnome-keyring-daemon` with a full-command `pgrep -f` match, fixing false negatives/errors on systems where `pgrep -x` cannot match process names longer than 15 characters.
|
|
18
14
|
|
|
19
15
|
see full changelog here: https://github.com/bjesuiter/codex-switcher/blob/main/CHANGELOG.md
|
|
20
16
|
|
package/cdx.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { generatePKCE } from "@openauthjs/openauth/pkce";
|
|
|
15
15
|
import http from "node:http";
|
|
16
16
|
|
|
17
17
|
//#region package.json
|
|
18
|
-
var version = "1.8.
|
|
18
|
+
var version = "1.8.4";
|
|
19
19
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region lib/platform/path-resolver.ts
|
|
@@ -2825,7 +2825,7 @@ const isCommandAvailable = async (commandName) => {
|
|
|
2825
2825
|
};
|
|
2826
2826
|
const checkGnomeKeyringRunning = async () => {
|
|
2827
2827
|
if (await isCommandAvailable("pgrep")) {
|
|
2828
|
-
const pgrepResult = await runCommandCapture("pgrep", ["-
|
|
2828
|
+
const pgrepResult = await runCommandCapture("pgrep", ["-f", "(^|/)gnome-keyring-daemon( |$)"]);
|
|
2829
2829
|
if (pgrepResult.ok) return { ok: true };
|
|
2830
2830
|
return {
|
|
2831
2831
|
ok: false,
|
|
@@ -2839,22 +2839,201 @@ const checkGnomeKeyringRunning = async () => {
|
|
|
2839
2839
|
details: extractCommandFailureDetails(psFallback) ?? "No gnome-keyring-daemon process found."
|
|
2840
2840
|
};
|
|
2841
2841
|
};
|
|
2842
|
+
const parseSystemctlEnabledState = (output) => {
|
|
2843
|
+
const normalized = output.trim().toLowerCase();
|
|
2844
|
+
if ([
|
|
2845
|
+
"enabled",
|
|
2846
|
+
"enabled-runtime",
|
|
2847
|
+
"static",
|
|
2848
|
+
"indirect",
|
|
2849
|
+
"generated"
|
|
2850
|
+
].includes(normalized)) return "enabled";
|
|
2851
|
+
if ([
|
|
2852
|
+
"disabled",
|
|
2853
|
+
"masked",
|
|
2854
|
+
"not-found",
|
|
2855
|
+
"linked",
|
|
2856
|
+
"linked-runtime"
|
|
2857
|
+
].includes(normalized)) return "disabled";
|
|
2858
|
+
return "unknown";
|
|
2859
|
+
};
|
|
2860
|
+
const getLinuxGnomeKeyringAutoStartStatus = async () => {
|
|
2861
|
+
if (!await isCommandAvailable("systemctl")) return {
|
|
2862
|
+
state: "unknown",
|
|
2863
|
+
details: "systemctl is not available; autostart detection depends on your desktop/session config."
|
|
2864
|
+
};
|
|
2865
|
+
const units = ["gnome-keyring-daemon.socket", "gnome-keyring-daemon.service"];
|
|
2866
|
+
let sawDisabled = false;
|
|
2867
|
+
const details = [];
|
|
2868
|
+
for (const unit of units) {
|
|
2869
|
+
const result = await runCommandCapture("systemctl", [
|
|
2870
|
+
"--user",
|
|
2871
|
+
"is-enabled",
|
|
2872
|
+
unit
|
|
2873
|
+
]);
|
|
2874
|
+
const state = parseSystemctlEnabledState(result.stdout || result.stderr);
|
|
2875
|
+
if (state === "enabled") return {
|
|
2876
|
+
state: "enabled",
|
|
2877
|
+
details: `${unit} is enabled (${result.stdout || "enabled"}).`
|
|
2878
|
+
};
|
|
2879
|
+
if (state === "disabled") {
|
|
2880
|
+
sawDisabled = true;
|
|
2881
|
+
details.push(`${unit}: ${result.stdout || result.stderr || "disabled"}`);
|
|
2882
|
+
continue;
|
|
2883
|
+
}
|
|
2884
|
+
const maybeDetail = extractCommandFailureDetails(result);
|
|
2885
|
+
if (maybeDetail) details.push(`${unit}: ${maybeDetail}`);
|
|
2886
|
+
}
|
|
2887
|
+
if (sawDisabled) return {
|
|
2888
|
+
state: "disabled",
|
|
2889
|
+
details: details.join("; ")
|
|
2890
|
+
};
|
|
2891
|
+
return {
|
|
2892
|
+
state: "unknown",
|
|
2893
|
+
details: details.join("; ") || "Unable to determine gnome-keyring autostart state."
|
|
2894
|
+
};
|
|
2895
|
+
};
|
|
2896
|
+
const applyKeyringEnvAssignments = (raw) => {
|
|
2897
|
+
const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2898
|
+
for (const line of lines) {
|
|
2899
|
+
const match = line.match(/^([A-Z0-9_]+)=(.*);?$/);
|
|
2900
|
+
if (!match) continue;
|
|
2901
|
+
const key = match[1];
|
|
2902
|
+
const value = match[2].replace(/;$/, "");
|
|
2903
|
+
if (key) process.env[key] = value;
|
|
2904
|
+
}
|
|
2905
|
+
};
|
|
2906
|
+
const startGnomeKeyringNow = async () => {
|
|
2907
|
+
const directStart = await runCommandCapture("gnome-keyring-daemon", ["--start", "--components=secrets"]);
|
|
2908
|
+
if (directStart.ok) {
|
|
2909
|
+
applyKeyringEnvAssignments(directStart.stdout);
|
|
2910
|
+
const runningCheck = await checkGnomeKeyringRunning();
|
|
2911
|
+
if (runningCheck.ok) return { ok: true };
|
|
2912
|
+
return {
|
|
2913
|
+
ok: false,
|
|
2914
|
+
details: runningCheck.details ?? "gnome-keyring-daemon start command succeeded, but process was not detected afterwards."
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
if (await isCommandAvailable("systemctl")) {
|
|
2918
|
+
const serviceStart = await runCommandCapture("systemctl", [
|
|
2919
|
+
"--user",
|
|
2920
|
+
"start",
|
|
2921
|
+
"gnome-keyring-daemon.service"
|
|
2922
|
+
]);
|
|
2923
|
+
if (serviceStart.ok) {
|
|
2924
|
+
const runningCheck = await checkGnomeKeyringRunning();
|
|
2925
|
+
if (runningCheck.ok) return { ok: true };
|
|
2926
|
+
return {
|
|
2927
|
+
ok: false,
|
|
2928
|
+
details: runningCheck.details ?? "systemctl start succeeded, but gnome-keyring-daemon was not detected afterwards."
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
return {
|
|
2932
|
+
ok: false,
|
|
2933
|
+
details: extractCommandFailureDetails(directStart) ?? extractCommandFailureDetails(serviceStart) ?? "Failed to start gnome-keyring-daemon."
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
return {
|
|
2937
|
+
ok: false,
|
|
2938
|
+
details: extractCommandFailureDetails(directStart) ?? "Failed to start gnome-keyring-daemon."
|
|
2939
|
+
};
|
|
2940
|
+
};
|
|
2941
|
+
const enableGnomeKeyringAutoStart = async () => {
|
|
2942
|
+
if (!await isCommandAvailable("systemctl")) return {
|
|
2943
|
+
ok: false,
|
|
2944
|
+
details: "systemctl is not available, so cdx cannot automatically enable startup in this session manager."
|
|
2945
|
+
};
|
|
2946
|
+
const units = ["gnome-keyring-daemon.socket", "gnome-keyring-daemon.service"];
|
|
2947
|
+
const failures = [];
|
|
2948
|
+
for (const unit of units) {
|
|
2949
|
+
const result = await runCommandCapture("systemctl", [
|
|
2950
|
+
"--user",
|
|
2951
|
+
"enable",
|
|
2952
|
+
unit
|
|
2953
|
+
]);
|
|
2954
|
+
if (result.ok) return {
|
|
2955
|
+
ok: true,
|
|
2956
|
+
details: `${unit} enabled.`
|
|
2957
|
+
};
|
|
2958
|
+
const detail = extractCommandFailureDetails(result);
|
|
2959
|
+
failures.push(`${unit}: ${detail ?? "enable failed"}`);
|
|
2960
|
+
}
|
|
2961
|
+
return {
|
|
2962
|
+
ok: false,
|
|
2963
|
+
details: failures.join("; ")
|
|
2964
|
+
};
|
|
2965
|
+
};
|
|
2966
|
+
const maybeOfferToStartGnomeKeyring = async () => {
|
|
2967
|
+
const autoStartStatus = await getLinuxGnomeKeyringAutoStartStatus();
|
|
2968
|
+
if (autoStartStatus.state === "enabled") {
|
|
2969
|
+
const shouldStartNow = await p.confirm({
|
|
2970
|
+
message: "gnome-keyring autostart appears enabled, but it is not running right now. Start it now?",
|
|
2971
|
+
initialValue: true
|
|
2972
|
+
});
|
|
2973
|
+
if (p.isCancel(shouldStartNow) || !shouldStartNow) return false;
|
|
2974
|
+
const startResult = await startGnomeKeyringNow();
|
|
2975
|
+
if (!startResult.ok) {
|
|
2976
|
+
process.stdout.write(` failed to start gnome-keyring-daemon: ${startResult.details ?? "unknown error"}\n`);
|
|
2977
|
+
return false;
|
|
2978
|
+
}
|
|
2979
|
+
process.stdout.write(" started gnome-keyring-daemon for this session.\n");
|
|
2980
|
+
return true;
|
|
2981
|
+
}
|
|
2982
|
+
if (autoStartStatus.details) process.stdout.write(` autostart check: ${autoStartStatus.details}\n`);
|
|
2983
|
+
const action = await p.select({
|
|
2984
|
+
message: autoStartStatus.state === "disabled" ? "gnome-keyring autostart seems disabled. What should cdx do?" : "Could not confirm gnome-keyring autostart. What should cdx do?",
|
|
2985
|
+
options: [
|
|
2986
|
+
{
|
|
2987
|
+
value: "start-now",
|
|
2988
|
+
label: "Start now only"
|
|
2989
|
+
},
|
|
2990
|
+
{
|
|
2991
|
+
value: "enable-and-start",
|
|
2992
|
+
label: "Enable on system start and start now"
|
|
2993
|
+
},
|
|
2994
|
+
{
|
|
2995
|
+
value: "skip",
|
|
2996
|
+
label: "Skip"
|
|
2997
|
+
}
|
|
2998
|
+
],
|
|
2999
|
+
initialValue: "start-now"
|
|
3000
|
+
});
|
|
3001
|
+
if (p.isCancel(action) || action === "skip") return false;
|
|
3002
|
+
if (action === "enable-and-start") {
|
|
3003
|
+
const enableResult = await enableGnomeKeyringAutoStart();
|
|
3004
|
+
if (!enableResult.ok) {
|
|
3005
|
+
process.stdout.write(` failed to enable autostart: ${enableResult.details ?? "unknown error"}\n`);
|
|
3006
|
+
return false;
|
|
3007
|
+
}
|
|
3008
|
+
process.stdout.write(` autostart enabled${enableResult.details ? ` (${enableResult.details})` : ""}.\n`);
|
|
3009
|
+
}
|
|
3010
|
+
const startResult = await startGnomeKeyringNow();
|
|
3011
|
+
if (!startResult.ok) {
|
|
3012
|
+
process.stdout.write(` failed to start gnome-keyring-daemon: ${startResult.details ?? "unknown error"}\n`);
|
|
3013
|
+
return false;
|
|
3014
|
+
}
|
|
3015
|
+
process.stdout.write(" started gnome-keyring-daemon for this session.\n");
|
|
3016
|
+
return true;
|
|
3017
|
+
};
|
|
2842
3018
|
const runLinuxSecretStoreChecklist = async () => {
|
|
2843
3019
|
const gnomeKeyringInstalled = await isCommandAvailable("gnome-keyring-daemon");
|
|
2844
3020
|
const secretToolInstalled = await isCommandAvailable("secret-tool");
|
|
2845
3021
|
const gnomeKeyringRunning = await checkGnomeKeyringRunning();
|
|
2846
3022
|
return [
|
|
2847
3023
|
{
|
|
3024
|
+
id: "gnome-keyring-installed",
|
|
2848
3025
|
question: "Is gnome-keyring installed?",
|
|
2849
3026
|
ok: gnomeKeyringInstalled,
|
|
2850
3027
|
hint: "Install the `gnome-keyring` package, then log out/in (or restart your session)."
|
|
2851
3028
|
},
|
|
2852
3029
|
{
|
|
3030
|
+
id: "secret-tool-installed",
|
|
2853
3031
|
question: "Is secret-tool installed?",
|
|
2854
3032
|
ok: secretToolInstalled,
|
|
2855
3033
|
hint: "Install the package that provides `secret-tool` (often `libsecret-tools`)."
|
|
2856
3034
|
},
|
|
2857
3035
|
{
|
|
3036
|
+
id: "gnome-keyring-running",
|
|
2858
3037
|
question: "Is gnome-keyring running?",
|
|
2859
3038
|
ok: gnomeKeyringRunning.ok,
|
|
2860
3039
|
details: gnomeKeyringRunning.details,
|
|
@@ -2888,6 +3067,15 @@ const maybeRunLinuxSecretStoreChecklist = async () => {
|
|
|
2888
3067
|
process.stdout.write(` ${i + 1}/3 ${item.question} no\n`);
|
|
2889
3068
|
if (item.details) process.stdout.write(` details: ${item.details}\n`);
|
|
2890
3069
|
if (item.hint) process.stdout.write(` hint: ${item.hint}\n`);
|
|
3070
|
+
if (item.id === "gnome-keyring-running") {
|
|
3071
|
+
if (await maybeOfferToStartGnomeKeyring()) {
|
|
3072
|
+
const runningNow = await checkGnomeKeyringRunning();
|
|
3073
|
+
if (runningNow.ok) {
|
|
3074
|
+
passed += 1;
|
|
3075
|
+
process.stdout.write(" re-check: gnome-keyring-daemon is now running.\n");
|
|
3076
|
+
} else process.stdout.write(` re-check still failing: ${runningNow.details ?? "process not detected"}\n`);
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
2891
3079
|
}
|
|
2892
3080
|
process.stdout.write(` Guided checklist summary: ${passed}/${checklist.length} checks passed.\n`);
|
|
2893
3081
|
};
|
|
@@ -3629,6 +3817,46 @@ const executeUpdate = async (command, args) => {
|
|
|
3629
3817
|
});
|
|
3630
3818
|
});
|
|
3631
3819
|
};
|
|
3820
|
+
const executeCapture = async (command, args) => await new Promise((resolve) => {
|
|
3821
|
+
const child = spawn(command, args, { stdio: [
|
|
3822
|
+
"ignore",
|
|
3823
|
+
"pipe",
|
|
3824
|
+
"pipe"
|
|
3825
|
+
] });
|
|
3826
|
+
let stdout = "";
|
|
3827
|
+
child.stdout?.on("data", (chunk) => {
|
|
3828
|
+
stdout += chunk.toString();
|
|
3829
|
+
});
|
|
3830
|
+
child.once("error", () => {
|
|
3831
|
+
resolve({
|
|
3832
|
+
ok: false,
|
|
3833
|
+
output: ""
|
|
3834
|
+
});
|
|
3835
|
+
});
|
|
3836
|
+
child.once("close", (code) => {
|
|
3837
|
+
resolve({
|
|
3838
|
+
ok: code === 0,
|
|
3839
|
+
output: stdout.trim()
|
|
3840
|
+
});
|
|
3841
|
+
});
|
|
3842
|
+
});
|
|
3843
|
+
const getInstalledCdxVersion = async () => {
|
|
3844
|
+
const attempts = [{
|
|
3845
|
+
command: "cdx",
|
|
3846
|
+
args: ["--version"]
|
|
3847
|
+
}];
|
|
3848
|
+
if (process.argv[0] && process.argv[1]) attempts.push({
|
|
3849
|
+
command: process.argv[0],
|
|
3850
|
+
args: [process.argv[1], "--version"]
|
|
3851
|
+
});
|
|
3852
|
+
for (const attempt of attempts) {
|
|
3853
|
+
const result = await executeCapture(attempt.command, attempt.args);
|
|
3854
|
+
if (!result.ok || !result.output) continue;
|
|
3855
|
+
const version = result.output.split(/\r?\n/).at(-1)?.trim();
|
|
3856
|
+
if (version) return version;
|
|
3857
|
+
}
|
|
3858
|
+
return null;
|
|
3859
|
+
};
|
|
3632
3860
|
const registerUpdateSelfCommand = (program) => {
|
|
3633
3861
|
program.command("update-self").aliases([
|
|
3634
3862
|
"self-update",
|
|
@@ -3703,8 +3931,9 @@ const registerUpdateSelfCommand = (program) => {
|
|
|
3703
3931
|
}
|
|
3704
3932
|
}
|
|
3705
3933
|
await executeUpdate(command.command, command.args);
|
|
3934
|
+
const installedVersion = await getInstalledCdxVersion();
|
|
3706
3935
|
process.stdout.write("Update completed.\n");
|
|
3707
|
-
process.stdout.write(
|
|
3936
|
+
process.stdout.write(`Installed version: ${installedVersion ?? "unknown"}\n`);
|
|
3708
3937
|
} catch (error) {
|
|
3709
3938
|
exitWithCommandError(error);
|
|
3710
3939
|
}
|