@bjesuiter/codex-switcher 1.8.0 → 1.8.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.
Files changed (3) hide show
  1. package/README.md +3 -10
  2. package/cdx.mjs +89 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,19 +6,12 @@ Switch the coding-agents [pi](https://pi.dev/), [codex](https://developers.opena
6
6
 
7
7
  ## Latest Changes
8
8
 
9
- ### 1.8.0
10
-
11
- #### Features
12
-
13
- - Added manual OAuth URL clipboard assist for login/relogin fallback flow, including an opt-in copy prompt and non-blocking behavior.
14
- - Added cross-platform clipboard copy strategies for auth URLs (local clipboard commands + OSC52 terminal fallback).
15
- - Added tmux/screen OSC52 framing support and fallback copy-command hints when auto-copy is unavailable.
9
+ ### 1.8.1
16
10
 
17
11
  #### Fixes
18
12
 
19
- - Clarified fallback guidance: manual URL copy/paste flow is now the recommended browser-launch fallback, while `--device-flow` may fail on some VPS/server IPs due to Cloudflare challenges.
20
- - Linux secure-store login reliability: treat native Secret Service "no matching entry" responses as missing-entry cases and improve unavailable-store error guidance.
21
- - Added Mosh-specific clipboard heuristics/warnings so OSC52 copy reports are less misleading when clipboard updates are unreliable.
13
+ - Added platform-native secure-store write/read/delete probes to `cdx doctor` on Linux, macOS, and Windows, so runtime secure-store failures are detected directly instead of only reporting adapter capability.
14
+ - Linux secure-store error handling now treats Secret Service `no result found` responses as missing-entry cases and classifies generic `Couldn't access platform secure storage` failures as unavailable-store errors with actionable guidance.
22
15
 
23
16
  see full changelog here: https://github.com/bjesuiter/codex-switcher/blob/main/CHANGELOG.md
24
17
 
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.0";
18
+ var version = "1.8.1";
19
19
 
20
20
  //#endregion
21
21
  //#region lib/platform/path-resolver.ts
@@ -663,13 +663,15 @@ const MISSING_ENTRY_MARKERS = [
663
663
  "no matching entry found in secure storage",
664
664
  "password not found",
665
665
  "no stored credentials found",
666
- "credential not found"
666
+ "credential not found",
667
+ "no result found"
667
668
  ];
668
669
  const STORE_UNAVAILABLE_MARKERS = [
669
670
  "unable to initialize linux secure-store backend",
670
671
  "no keyring backend could be initialized",
671
672
  "native keyring module not available",
672
673
  "secret service operation failed",
674
+ "couldn't access platform secure storage",
673
675
  "dbus",
674
676
  "d-bus",
675
677
  "org.freedesktop.secrets",
@@ -1061,14 +1063,16 @@ const windowsCrossKeychainPayloadExists = async (accountId) => withWindowsBacken
1061
1063
  //#endregion
1062
1064
  //#region lib/secrets/store.ts
1063
1065
  const MISSING_SECRET_STORE_ERROR_MARKERS = [
1064
- "No stored credentials found",
1065
- "No Keychain payload found",
1066
- "Password not found",
1067
- "no matching entry found in secure storage"
1066
+ "no stored credentials found",
1067
+ "no keychain payload found",
1068
+ "password not found",
1069
+ "no matching entry found in secure storage",
1070
+ "no result found"
1068
1071
  ];
1069
1072
  const isMissingSecretStoreEntryError = (error) => {
1070
1073
  if (!(error instanceof Error)) return false;
1071
- return MISSING_SECRET_STORE_ERROR_MARKERS.some((marker) => error.message.includes(marker));
1074
+ const message = error.message.toLowerCase();
1075
+ return MISSING_SECRET_STORE_ERROR_MARKERS.some((marker) => message.includes(marker));
1072
1076
  };
1073
1077
  const createMissingSecretStoreEntryError = (accountId) => /* @__PURE__ */ new Error(`No stored credentials found for account ${accountId}.`);
1074
1078
  const CACHED_ADAPTER_SYMBOL = Symbol.for("cdx.secretStore.cachedAdapter");
@@ -2711,6 +2715,56 @@ const getKeychainDecryptAccessByServiceAsync = async (services) => {
2711
2715
  return parseKeychainDecryptAccessFromDump(dumpResult.output, dedupedServices);
2712
2716
  };
2713
2717
 
2718
+ //#endregion
2719
+ //#region lib/secrets/probe.ts
2720
+ const toError = (error) => error instanceof Error ? error : new Error(String(error));
2721
+ const createProbePayload = (accountId, now) => ({
2722
+ refresh: `probe-refresh-${accountId}`,
2723
+ access: `probe-access-${accountId}`,
2724
+ expires: now + 6e4,
2725
+ accountId
2726
+ });
2727
+ const payloadMatches = (expected, actual) => expected.accountId === actual.accountId && expected.refresh === actual.refresh && expected.access === actual.access && expected.expires === actual.expires;
2728
+ const runSecretStoreWriteReadProbe = async (secretStore, options = {}) => {
2729
+ const probeAccountId = options.probeAccountId ?? `cdx-doctor-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
2730
+ const payload = createProbePayload(probeAccountId, options.now ?? Date.now());
2731
+ let saveSucceeded = false;
2732
+ let result = { ok: true };
2733
+ try {
2734
+ await secretStore.save(probeAccountId, payload);
2735
+ saveSucceeded = true;
2736
+ } catch (error) {
2737
+ result = {
2738
+ ok: false,
2739
+ stage: "save",
2740
+ error: toError(error)
2741
+ };
2742
+ }
2743
+ if (result.ok) try {
2744
+ if (!payloadMatches(payload, await secretStore.load(probeAccountId))) result = {
2745
+ ok: false,
2746
+ stage: "verify",
2747
+ error: /* @__PURE__ */ new Error("Secure-store probe loaded payload does not match the saved payload.")
2748
+ };
2749
+ } catch (error) {
2750
+ result = {
2751
+ ok: false,
2752
+ stage: "load",
2753
+ error: toError(error)
2754
+ };
2755
+ }
2756
+ if (saveSucceeded) try {
2757
+ await secretStore.delete(probeAccountId);
2758
+ } catch (error) {
2759
+ if (result.ok) result = {
2760
+ ok: false,
2761
+ stage: "delete",
2762
+ error: toError(error)
2763
+ };
2764
+ }
2765
+ return result;
2766
+ };
2767
+
2714
2768
  //#endregion
2715
2769
  //#region lib/commands/doctor.ts
2716
2770
  const hasRuntimeTrustedApp = (trustedApplications, runtimeExecutablePath) => {
@@ -2720,6 +2774,23 @@ const hasRuntimeTrustedApp = (trustedApplications, runtimeExecutablePath) => {
2720
2774
  return path.basename(trustedApp).toLowerCase() === runtimeBaseName;
2721
2775
  });
2722
2776
  };
2777
+ const getSecretStoreProbeHeading = (platform) => {
2778
+ if (platform === "linux") return "Linux secure-store probe";
2779
+ if (platform === "darwin") return "macOS secure-store probe";
2780
+ if (platform === "win32") return "Windows secure-store probe";
2781
+ return null;
2782
+ };
2783
+ const createProbeAdapterForCurrentPlatform = () => {
2784
+ const currentAdapter = getSecretStoreAdapter();
2785
+ if (process.platform === "darwin" && currentAdapter.id === "macos-legacy-keychain") return createSecretStoreAdapterFromSelection("legacy-keychain", "darwin");
2786
+ return createRuntimeSecretStoreAdapter(process.platform);
2787
+ };
2788
+ const getSecretStoreProbeGuidance = (platform) => {
2789
+ if (platform === "linux") return "Suggested fix: ensure Secret Service is running/unlocked (for example gnome-keyring + secret-tool), then retry login.";
2790
+ if (platform === "darwin") return "Suggested fix: ensure Keychain Access is unlocked and allows this runtime/toolchain to store/read passwords, then retry login.";
2791
+ if (platform === "win32") return "Suggested fix: ensure Windows Credential Manager is available for this user session, then retry login.";
2792
+ return null;
2793
+ };
2723
2794
  const registerDoctorCommand = (program) => {
2724
2795
  program.command("doctor").description("Show auth file paths and runtime capabilities").option("--check-keychain-acl", "Run keychain trusted-app/ACL checks on macOS (can be slow)").action(async (options) => {
2725
2796
  try {
@@ -2770,6 +2841,17 @@ const registerDoctorCommand = (program) => {
2770
2841
  process.stdout.write(` Summary: ${okCount}/${status.accounts.length} configured account(s) passed secure-store load checks.\n`);
2771
2842
  }
2772
2843
  }
2844
+ const probeHeading = getSecretStoreProbeHeading(process.platform);
2845
+ if (probeHeading) {
2846
+ process.stdout.write(`\n${probeHeading}:\n`);
2847
+ const probeResult = await runSecretStoreWriteReadProbe(createProbeAdapterForCurrentPlatform());
2848
+ if (probeResult.ok) process.stdout.write(" write/read/delete probe: OK\n");
2849
+ else {
2850
+ process.stdout.write(` ⚠ ${probeResult.stage} failed: ${probeResult.error.message}\n`);
2851
+ const guidance = getSecretStoreProbeGuidance(process.platform);
2852
+ if (guidance) process.stdout.write(` ${guidance}\n`);
2853
+ }
2854
+ }
2773
2855
  if (process.platform === "darwin" && !options.checkKeychainAcl) {
2774
2856
  process.stdout.write(" ┌─ Optional keychain ACL check\n");
2775
2857
  process.stdout.write(" │ Run: cdx doctor --check-keychain-acl\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bjesuiter/codex-switcher",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "type": "module",
5
5
  "description": "CLI tool to switch between multiple OpenAI accounts for OpenCode",
6
6
  "bin": {