codex-copilot-dx 0.4.14 → 0.4.15

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 CHANGED
@@ -48,6 +48,13 @@ codex-copilot-dx doctor
48
48
 
49
49
  The doctor checks the GitHub token, Codex config, Claude Code settings, Claude App gateway profile, and whether the local adapter port is listening.
50
50
 
51
+ If Copilot token refresh fails with `401` or `403`, the saved GitHub token may be expired, revoked, or missing Copilot access. Delete the saved token and start the tool again to trigger GitHub device login:
52
+
53
+ ```bash
54
+ rm ~/.local/share/copilot-api/github_token
55
+ codex-copilot-dx
56
+ ```
57
+
51
58
  ### Claude App opt-in
52
59
 
53
60
  Claude App support is opt-in so the default Codex Desktop and Claude Code setup stays unchanged:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-copilot-dx",
3
- "version": "0.4.14",
3
+ "version": "0.4.15",
4
4
  "description": "Use Codex Desktop, Claude Code, and Claude App with GitHub Copilot",
5
5
  "type": "module",
6
6
  "bin": {
package/src/auth.mjs CHANGED
@@ -11,6 +11,14 @@ export function githubTokenPath(home = os.homedir()) {
11
11
  return path.join(home, ".local", "share", "copilot-api", "github_token");
12
12
  }
13
13
 
14
+ export function githubReauthMessage(reason, home = os.homedir()) {
15
+ const tokenPath = githubTokenPath(home);
16
+ return `${reason}
17
+ Delete the saved GitHub token, then run codex-copilot-dx again to log in:
18
+ rm '${tokenPath}'
19
+ codex-copilot-dx`;
20
+ }
21
+
14
22
  // Map GitHub polling responses to a small local state machine.
15
23
  export function interpretPoll(data) {
16
24
  if (typeof data.access_token === "string" && data.access_token) return { state: "done", token: data.access_token };
package/src/copilot.mjs CHANGED
@@ -1,10 +1,8 @@
1
1
  import fs from "node:fs";
2
- import path from "node:path";
3
- import os from "node:os";
4
2
  import { randomUUID } from "node:crypto";
5
3
  import { status } from "./status.mjs";
4
+ import { githubReauthMessage, githubTokenPath } from "./auth.mjs";
6
5
 
7
- const GITHUB_TOKEN_PATH = path.join(os.homedir(), ".local", "share", "copilot-api", "github_token");
8
6
  export const DEFAULT_API_BASE = "https://api.githubcopilot.com";
9
7
  let apiBase = DEFAULT_API_BASE;
10
8
  const IMG_MAX_DIM = parseInt(process.env.CCDX_IMG_MAX_DIM || "2048", 10);
@@ -249,10 +247,13 @@ let copilotToken = null;
249
247
  let copilotTokenExpiry = 0;
250
248
 
251
249
  function getGithubToken() {
250
+ const GITHUB_TOKEN_PATH = githubTokenPath();
252
251
  if (!fs.existsSync(GITHUB_TOKEN_PATH)) {
253
- throw new Error("GitHub token not found. Run the tool once to log in.");
252
+ throw new Error("GitHub token not found. Run codex-copilot-dx again to log in.");
254
253
  }
255
- return fs.readFileSync(GITHUB_TOKEN_PATH, "utf-8").trim();
254
+ const token = fs.readFileSync(GITHUB_TOKEN_PATH, "utf-8").trim();
255
+ if (!token) throw new Error(githubReauthMessage("GitHub token file is empty."));
256
+ return token;
256
257
  }
257
258
 
258
259
  export async function getCopilotToken({ signal } = {}) {
@@ -262,7 +263,12 @@ export async function getCopilotToken({ signal } = {}) {
262
263
  headers: { Authorization: `token ${ghToken}`, Accept: "application/json" },
263
264
  signal,
264
265
  });
265
- if (!resp.ok) throw new Error(`Failed to get Copilot token: ${resp.status}`);
266
+ if (!resp.ok) {
267
+ if (resp.status === 401 || resp.status === 403) {
268
+ throw new Error(githubReauthMessage(`Failed to get Copilot token: ${resp.status}. The saved GitHub token may be expired, revoked, or missing Copilot access.`));
269
+ }
270
+ throw new Error(`Failed to get Copilot token: ${resp.status}`);
271
+ }
266
272
  const data = await resp.json();
267
273
  if (!data.token) throw new Error("Copilot token response missing token field");
268
274
  copilotToken = data.token;