Spaces:
Running
Running
File size: 5,501 Bytes
9e27976 120cd8d 9e27976 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
#!/usr/bin/env node
import { defineCommand } from "citty"
import clipboard from "clipboardy"
import consola from "consola"
import { serve, type ServerHandler } from "srvx"
import invariant from "tiny-invariant"
import { ensurePaths } from "./lib/paths"
import { initProxyFromEnv } from "./lib/proxy"
import { generateEnvScript } from "./lib/shell"
import { state } from "./lib/state"
import { setupCopilotToken, setupGitHubToken } from "./lib/token"
import { cacheModels, cacheVSCodeVersion } from "./lib/utils"
import { server } from "./server"
interface RunServerOptions {
port: number
verbose: boolean
accountType: string
manual: boolean
rateLimit?: number
rateLimitWait: boolean
githubToken?: string
claudeCode: boolean
showToken: boolean
proxyEnv: boolean
}
export async function runServer(options: RunServerOptions): Promise<void> {
if (options.proxyEnv) {
initProxyFromEnv()
}
if (options.verbose) {
consola.level = 5
consola.info("Verbose logging enabled")
}
state.accountType = options.accountType
if (options.accountType !== "individual") {
consola.info(`Using ${options.accountType} plan GitHub account`)
}
state.manualApprove = options.manual
state.rateLimitSeconds = options.rateLimit
state.rateLimitWait = options.rateLimitWait
state.showToken = options.showToken
await ensurePaths()
await cacheVSCodeVersion()
if (options.githubToken) {
state.githubToken = options.githubToken
consola.info("Using provided GitHub token")
} else {
await setupGitHubToken()
}
await setupCopilotToken()
await cacheModels()
consola.info(
`Available models: \n${state.models?.data.map((model) => `- ${model.id}`).join("\n")}`,
)
const serverUrl = `http://localhost:${options.port}`
if (options.claudeCode) {
invariant(state.models, "Models should be loaded by now")
const selectedModel = await consola.prompt(
"Select a model to use with Claude Code",
{
type: "select",
options: state.models.data.map((model) => model.id),
},
)
const selectedSmallModel = await consola.prompt(
"Select a small model to use with Claude Code",
{
type: "select",
options: state.models.data.map((model) => model.id),
},
)
const command = generateEnvScript(
{
ANTHROPIC_BASE_URL: serverUrl,
ANTHROPIC_AUTH_TOKEN: "dummy",
ANTHROPIC_MODEL: selectedModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,
ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,
DISABLE_NON_ESSENTIAL_MODEL_CALLS: "1",
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
},
"claude",
)
try {
clipboard.writeSync(command)
consola.success("Copied Claude Code command to clipboard!")
} catch {
consola.warn(
"Failed to copy to clipboard. Here is the Claude Code command:",
)
consola.log(command)
}
}
consola.box(
`🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`,
)
serve({
fetch: server.fetch as ServerHandler,
port: options.port,
})
}
export const start = defineCommand({
meta: {
name: "start",
description: "Start the Copilot API server",
},
args: {
port: {
alias: "p",
type: "string",
default: "7860",
description: "Port to listen on",
},
verbose: {
alias: "v",
type: "boolean",
default: false,
description: "Enable verbose logging",
},
"account-type": {
alias: "a",
type: "string",
default: "individual",
description: "Account type to use (individual, business, enterprise)",
},
manual: {
type: "boolean",
default: false,
description: "Enable manual request approval",
},
"rate-limit": {
alias: "r",
type: "string",
description: "Rate limit in seconds between requests",
},
wait: {
alias: "w",
type: "boolean",
default: false,
description:
"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set",
},
"github-token": {
alias: "g",
type: "string",
description:
"Provide GitHub token directly (must be generated using the `auth` subcommand)",
},
"claude-code": {
alias: "c",
type: "boolean",
default: false,
description:
"Generate a command to launch Claude Code with Copilot API config",
},
"show-token": {
type: "boolean",
default: false,
description: "Show GitHub and Copilot tokens on fetch and refresh",
},
"proxy-env": {
type: "boolean",
default: false,
description: "Initialize proxy from environment variables",
},
},
run({ args }) {
const rateLimitRaw = args["rate-limit"]
const rateLimit =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)
return runServer({
port: Number.parseInt(args.port, 10),
verbose: args.verbose,
accountType: args["account-type"],
manual: args.manual,
rateLimit,
rateLimitWait: args.wait,
githubToken: args["github-token"],
claudeCode: args["claude-code"],
showToken: args["show-token"],
proxyEnv: args["proxy-env"],
})
},
})
|