copillm 0.2.9 → 0.3.0-beta.2
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 +69 -1
- package/dist/agentconfig/load.js +9 -1
- package/dist/agentconfig/schema.js +6 -0
- package/dist/auth/accountManager.js +118 -0
- package/dist/auth/accounts.js +161 -0
- package/dist/auth/credentials.js +196 -67
- package/dist/cli/agentEnv.js +2 -1
- package/dist/cli/auth/runAuth.js +243 -7
- package/dist/cli/commands/agents/claude.js +22 -2
- package/dist/cli/commands/agents/codex.js +22 -2
- package/dist/cli/commands/agents/copilot.js +25 -4
- package/dist/cli/commands/agents/pi.js +22 -2
- package/dist/cli/commands/agents/shared.js +57 -0
- package/dist/cli/commands/auth.js +27 -1
- package/dist/cli/copillmFlags.js +8 -0
- package/dist/cli/daemon/runDaemon.js +21 -2
- package/dist/cli/integrations/claudeExport.js +6 -4
- package/dist/cli/integrations/refreshCodex.js +4 -2
- package/dist/cli/integrations/refreshPi.js +4 -2
- package/dist/cli/packageInfo.js +1 -1
- package/dist/config/accountId.js +44 -0
- package/dist/config/home.js +35 -0
- package/dist/integrations/codex/init.js +12 -3
- package/dist/integrations/pi/init.js +4 -3
- package/dist/models/anthropicDefaults.js +13 -4
- package/dist/models/discovery.js +32 -10
- package/dist/server/accountResolver.js +85 -0
- package/dist/server/proxy.js +40 -8
- package/dist/server/routes/debug.js +7 -0
- package/dist/server/routes/models.js +5 -5
- package/dist/server/routes/proxyForward.js +3 -3
- package/dist/server/routes/shared.js +66 -21
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { stripOneMillionAlias } from "../../translation/openaiAnthropic.js";
|
|
2
|
+
import { isValidAccountId } from "../../config/accountId.js";
|
|
2
3
|
import { JsonRequestParseError } from "../errors.js";
|
|
3
4
|
export async function readJson(req) {
|
|
4
5
|
const chunks = [];
|
|
@@ -119,43 +120,87 @@ export function safePathname(rawUrl) {
|
|
|
119
120
|
return "/";
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
123
|
+
// First path segments that belong to real routes and must never be mistaken
|
|
124
|
+
// for an account prefix. (Direct matching already wins for these, so this is
|
|
125
|
+
// belt-and-suspenders against contrived nested paths.)
|
|
126
|
+
const RESERVED_FIRST_SEGMENTS = new Set([
|
|
127
|
+
"livez",
|
|
128
|
+
"healthz",
|
|
129
|
+
"models",
|
|
130
|
+
"v1",
|
|
131
|
+
"codex",
|
|
132
|
+
"anthropic",
|
|
133
|
+
"_debug"
|
|
134
|
+
]);
|
|
135
|
+
// Only these routes may be addressed with an `/<account>` prefix. The generic
|
|
136
|
+
// `/models` discovery route and all health/debug routes stay global.
|
|
137
|
+
const PREFIXABLE_KINDS = new Set([
|
|
138
|
+
"codex_models",
|
|
139
|
+
"anthropic_models",
|
|
140
|
+
"codex_responses",
|
|
141
|
+
"openai",
|
|
142
|
+
"anthropic"
|
|
143
|
+
]);
|
|
144
|
+
function matchRoute(method, pathname) {
|
|
133
145
|
if (method === "GET" && pathname === "/livez") {
|
|
134
|
-
return { kind: "livez", anthroShape: false };
|
|
146
|
+
return { kind: "livez", anthroShape: false, accountId: null };
|
|
135
147
|
}
|
|
136
148
|
if (method === "GET" && pathname === "/healthz") {
|
|
137
|
-
return { kind: "healthz", anthroShape: false };
|
|
149
|
+
return { kind: "healthz", anthroShape: false, accountId: null };
|
|
138
150
|
}
|
|
139
151
|
if (method === "GET" && (pathname === "/models" || pathname === "/v1/models")) {
|
|
140
|
-
return { kind: "models", anthroShape: false };
|
|
152
|
+
return { kind: "models", anthroShape: false, accountId: null };
|
|
141
153
|
}
|
|
142
154
|
if (method === "GET" && pathname === "/codex/v1/models") {
|
|
143
|
-
return { kind: "codex_models", anthroShape: false };
|
|
155
|
+
return { kind: "codex_models", anthroShape: false, accountId: null };
|
|
144
156
|
}
|
|
145
157
|
if (method === "GET" && pathname === "/anthropic/v1/models") {
|
|
146
|
-
return { kind: "anthropic_models", anthroShape: false };
|
|
158
|
+
return { kind: "anthropic_models", anthroShape: false, accountId: null };
|
|
147
159
|
}
|
|
148
160
|
if (method === "POST" && pathname === "/codex/v1/responses") {
|
|
149
|
-
return { kind: "codex_responses", anthroShape: false };
|
|
161
|
+
return { kind: "codex_responses", anthroShape: false, accountId: null };
|
|
150
162
|
}
|
|
151
163
|
if (method === "GET" && pathname === "/_debug") {
|
|
152
|
-
return { kind: "debug", anthroShape: false };
|
|
164
|
+
return { kind: "debug", anthroShape: false, accountId: null };
|
|
153
165
|
}
|
|
154
166
|
if (method === "POST" && pathname === "/v1/chat/completions") {
|
|
155
|
-
return { kind: "openai", anthroShape: false };
|
|
167
|
+
return { kind: "openai", anthroShape: false, accountId: null };
|
|
156
168
|
}
|
|
157
169
|
if (method === "POST" && (pathname === "/anthropic/v1/messages" || pathname === "/v1/messages")) {
|
|
158
|
-
return { kind: "anthropic", anthroShape: true };
|
|
170
|
+
return { kind: "anthropic", anthroShape: true, accountId: null };
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
export function resolveRoute(method, rawUrl) {
|
|
175
|
+
if (!method || !rawUrl) {
|
|
176
|
+
return { kind: "not_found", anthroShape: false, accountId: null };
|
|
177
|
+
}
|
|
178
|
+
let pathname;
|
|
179
|
+
try {
|
|
180
|
+
pathname = new URL(rawUrl, "http://127.0.0.1").pathname;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return { kind: "not_found", anthroShape: false, accountId: null };
|
|
184
|
+
}
|
|
185
|
+
// Try the path as-is first. This keeps every existing (unprefixed) route
|
|
186
|
+
// working unchanged and ensures a reserved first segment like `/codex/...`
|
|
187
|
+
// is always interpreted as a route, never as an account named "codex".
|
|
188
|
+
const direct = matchRoute(method, pathname);
|
|
189
|
+
if (direct) {
|
|
190
|
+
return direct;
|
|
191
|
+
}
|
|
192
|
+
// Otherwise, peel an optional leading `/<account>` segment and re-match the
|
|
193
|
+
// remainder against the prefixable routes.
|
|
194
|
+
const prefixMatch = pathname.match(/^\/([^/]+)(\/.*)$/);
|
|
195
|
+
if (prefixMatch) {
|
|
196
|
+
const candidate = prefixMatch[1];
|
|
197
|
+
const rest = prefixMatch[2];
|
|
198
|
+
if (isValidAccountId(candidate) && !RESERVED_FIRST_SEGMENTS.has(candidate)) {
|
|
199
|
+
const sub = matchRoute(method, rest);
|
|
200
|
+
if (sub && PREFIXABLE_KINDS.has(sub.kind)) {
|
|
201
|
+
return { ...sub, accountId: candidate };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
159
204
|
}
|
|
160
|
-
return { kind: "not_found", anthroShape: false };
|
|
205
|
+
return { kind: "not_found", anthroShape: false, accountId: null };
|
|
161
206
|
}
|