Skip to content

Commit ae8f9d0

Browse files
rejectliuclaude
andcommitted
feat: add manual token refresh command
Add `refresh-token` CLI command and `/token/refresh` API endpoint to manually refresh Copilot token without restarting the container. Usage: `docker compose exec copilot-api refresh-token` Co-Authored-By: Claude (claude-opus-4.5) <noreply@anthropic.com>
1 parent daba172 commit ae8f9d0

File tree

6 files changed

+80
-9
lines changed

6 files changed

+80
-9
lines changed

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
2121
CMD wget --spider -q http://localhost:4141/ || exit 1
2222

2323
COPY entrypoint.sh /entrypoint.sh
24-
RUN chmod +x /entrypoint.sh
24+
COPY refresh-token /usr/local/bin/refresh-token
25+
RUN chmod +x /entrypoint.sh /usr/local/bin/refresh-token
26+
2527
ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#!/bin/sh
2-
if [ "$1" = "--auth" ]; then
3-
# Run auth command
4-
exec bun run dist/main.js auth
5-
else
6-
# Default command
7-
exec bun run dist/main.js start -g "$GH_TOKEN" "$@"
8-
fi
2+
case "$1" in
3+
--auth)
4+
exec bun run dist/main.js auth
5+
;;
6+
refresh-token)
7+
exec bun run dist/main.js refresh-token
8+
;;
9+
*)
10+
exec bun run dist/main.js start -g "$GH_TOKEN" "$@"
11+
;;
12+
esac
913

refresh-token

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
set -e
3+
4+
echo "Refreshing Copilot token..."
5+
bun run /app/dist/main.js refresh-token "$@"

src/main.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { defineCommand, runMain } from "citty"
55
import { auth } from "./auth"
66
import { checkUsage } from "./check-usage"
77
import { debug } from "./debug"
8+
import { refreshToken } from "./refresh-token"
89
import { start } from "./start"
910

1011
const main = defineCommand({
@@ -13,7 +14,13 @@ const main = defineCommand({
1314
description:
1415
"A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.",
1516
},
16-
subCommands: { auth, start, "check-usage": checkUsage, debug },
17+
subCommands: {
18+
auth,
19+
start,
20+
"check-usage": checkUsage,
21+
debug,
22+
"refresh-token": refreshToken,
23+
},
1724
})
1825

1926
await runMain(main)

src/refresh-token.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { defineCommand } from "citty"
2+
import consola from "consola"
3+
4+
export const refreshToken = defineCommand({
5+
meta: {
6+
name: "refresh-token",
7+
description: "Manually refresh the Copilot token via API",
8+
},
9+
args: {
10+
port: {
11+
type: "string",
12+
alias: "p",
13+
default: "4141",
14+
description: "The port the server is running on",
15+
},
16+
},
17+
async run({ args }) {
18+
const port = args.port
19+
const url = `http://localhost:${port}/token/refresh`
20+
21+
try {
22+
const response = await fetch(url, { method: "POST" })
23+
const data = await response.json()
24+
25+
if (response.ok && data.success) {
26+
consola.success("Token refreshed successfully")
27+
} else {
28+
consola.error("Failed to refresh token:", data.error || "Unknown error")
29+
process.exit(1)
30+
}
31+
} catch (error) {
32+
consola.error("Failed to connect to server:", error)
33+
consola.info("Make sure the server is running on port", port)
34+
process.exit(1)
35+
}
36+
},
37+
})

src/routes/token/route.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Hono } from "hono"
22

33
import { state } from "~/lib/state"
4+
import { getCopilotToken } from "~/services/github/get-copilot-token"
45

56
export const tokenRoute = new Hono()
67

@@ -14,3 +15,18 @@ tokenRoute.get("/", (c) => {
1415
return c.json({ error: "Failed to fetch token", token: null }, 500)
1516
}
1617
})
18+
19+
tokenRoute.post("/refresh", async (c) => {
20+
try {
21+
const { token } = await getCopilotToken()
22+
state.copilotToken = token
23+
console.log("Copilot token manually refreshed")
24+
return c.json({
25+
success: true,
26+
message: "Token refreshed successfully",
27+
})
28+
} catch (error) {
29+
console.error("Error refreshing token:", error)
30+
return c.json({ error: "Failed to refresh token", success: false }, 500)
31+
}
32+
})

0 commit comments

Comments
 (0)