@jeffreycao/copilot-api 1.10.9 → 1.10.11

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 (33) hide show
  1. package/README.md +53 -213
  2. package/README.zh-CN.md +47 -209
  3. package/dist/auth-BO_SkMVw.js +116 -0
  4. package/dist/auth-BO_SkMVw.js.map +1 -0
  5. package/dist/{check-usage-BdXGp1Wr.js → check-usage-D-W6VD7k.js} +3 -4
  6. package/dist/{check-usage-BdXGp1Wr.js.map → check-usage-D-W6VD7k.js.map} +1 -1
  7. package/dist/{proxy-DvlF9a-7.js → config-ztdkLu9o.js} +83 -70
  8. package/dist/config-ztdkLu9o.js.map +1 -0
  9. package/dist/{debug-C_TBkyUw.js → debug-BVHmoCzY.js} +17 -7
  10. package/dist/debug-BVHmoCzY.js.map +1 -0
  11. package/dist/main.js +5 -5
  12. package/dist/{mcp-CTb-DbQH.js → mcp-DZgcvqQY.js} +2 -2
  13. package/dist/{mcp-CTb-DbQH.js.map → mcp-DZgcvqQY.js.map} +1 -1
  14. package/dist/{server-FPXzFkg9.js → server-2tRe3sDu.js} +1798 -1713
  15. package/dist/server-2tRe3sDu.js.map +1 -0
  16. package/dist/{start-CbKg_0bY.js → start-CM-b3DRX.js} +4 -6
  17. package/dist/{start-CbKg_0bY.js.map → start-CM-b3DRX.js.map} +1 -1
  18. package/dist/token-BVXHiYEl.js +1875 -0
  19. package/dist/token-BVXHiYEl.js.map +1 -0
  20. package/dist/{tool-search-D3SN0jX-.js → tool-search-wA-fLduL.js} +1 -1
  21. package/dist/{tool-search-D3SN0jX-.js.map → tool-search-wA-fLduL.js.map} +1 -1
  22. package/package.json +2 -2
  23. package/dist/auth-BHa2OHXf.js +0 -45
  24. package/dist/auth-BHa2OHXf.js.map +0 -1
  25. package/dist/debug-C_TBkyUw.js.map +0 -1
  26. package/dist/paths-DC-mqCY3.js +0 -30
  27. package/dist/paths-DC-mqCY3.js.map +0 -1
  28. package/dist/proxy-DvlF9a-7.js.map +0 -1
  29. package/dist/server-FPXzFkg9.js.map +0 -1
  30. package/dist/token-Dj8XsAxn.js +0 -170
  31. package/dist/token-Dj8XsAxn.js.map +0 -1
  32. package/dist/utils-jHLgqAq2.js +0 -657
  33. package/dist/utils-jHLgqAq2.js.map +0 -1
@@ -1,9 +1,34 @@
1
- import { t as PATHS } from "./paths-DC-mqCY3.js";
2
1
  import consola from "consola";
3
2
  import { randomBytes } from "node:crypto";
4
3
  import fs from "node:fs";
5
- import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
6
- import { getProxyForUrl } from "proxy-from-env";
4
+ import fs$1 from "node:fs/promises";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ //#region src/lib/paths.ts
8
+ const AUTH_APP = process.env.COPILOT_API_OAUTH_APP?.trim() || "";
9
+ const ENTERPRISE_PREFIX = process.env.COPILOT_API_ENTERPRISE_URL ? "ent_" : "";
10
+ const DEFAULT_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
11
+ const APP_DIR = process.env.COPILOT_API_HOME || DEFAULT_DIR;
12
+ const PATHS = {
13
+ APP_DIR,
14
+ GITHUB_TOKEN_PATH: path.join(APP_DIR, AUTH_APP, ENTERPRISE_PREFIX + "github_token"),
15
+ CODEX_CREDENTIAL_PATH: path.join(APP_DIR, "codex_credentials.json"),
16
+ CONFIG_PATH: path.join(APP_DIR, "config.json")
17
+ };
18
+ async function ensurePaths() {
19
+ await fs$1.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true });
20
+ await ensureFile(PATHS.GITHUB_TOKEN_PATH);
21
+ await ensureFile(PATHS.CONFIG_PATH);
22
+ }
23
+ async function ensureFile(filePath) {
24
+ try {
25
+ await fs$1.access(filePath, fs$1.constants.W_OK);
26
+ } catch {
27
+ await fs$1.writeFile(filePath, "");
28
+ await fs$1.chmod(filePath, 384);
29
+ }
30
+ }
31
+ //#endregion
7
32
  //#region src/lib/config.ts
8
33
  const gpt5ExplorationPrompt = `## Exploration and reading files
9
34
  - **Think first.** Before any tool call, decide ALL files/resources you will need.
@@ -154,7 +179,7 @@ function ensureAdminApiKey(config) {
154
179
  mergedConfig: {
155
180
  ...config,
156
181
  auth: {
157
- ...config.auth ?? {},
182
+ ...config.auth,
158
183
  adminApiKey: normalizedAdminApiKey
159
184
  }
160
185
  },
@@ -165,7 +190,7 @@ function ensureAdminApiKey(config) {
165
190
  const { mergedConfig } = mergeDefaultConfig({
166
191
  ...editableConfig,
167
192
  auth: {
168
- ...editableConfig.auth ?? {},
193
+ ...editableConfig.auth,
169
194
  adminApiKey: generateAdminApiKey()
170
195
  }
171
196
  });
@@ -198,7 +223,7 @@ function getExtraPromptForModel(model) {
198
223
  }
199
224
  function getModelMappings() {
200
225
  const modelMappings = getConfig().modelMappings;
201
- if (!modelMappings) return { ...defaultConfig.modelMappings ?? {} };
226
+ if (!modelMappings) return { ...defaultConfig.modelMappings };
202
227
  const validMappings = {};
203
228
  for (const [sourceModel, targetModel] of Object.entries(modelMappings)) {
204
229
  if (!sourceModel || typeof targetModel !== "string" || targetModel.length === 0) continue;
@@ -241,31 +266,65 @@ function normalizeProviderBaseUrl(url) {
241
266
  return url.trim().replace(/\/+$/u, "");
242
267
  }
243
268
  function getDefaultProviderAuthType(providerType) {
244
- return providerType === "openai-compatible" ? "authorization" : "x-api-key";
269
+ return providerType === "anthropic" ? "x-api-key" : "authorization";
245
270
  }
246
271
  function resolveProviderAuthType(providerName, authType, providerType) {
247
- if (authType === void 0) return getDefaultProviderAuthType(providerType);
272
+ const defaultAuthType = getDefaultProviderAuthType(providerType);
273
+ if (authType === void 0) return defaultAuthType;
248
274
  if (authType === "x-api-key") return "x-api-key";
275
+ if (authType === "oauth2") {
276
+ if (providerName === "codex") return authType;
277
+ consola.warn(`Provider ${providerName} has authType 'oauth2', which is only supported by the builtin codex provider, falling back to ${defaultAuthType}`);
278
+ return defaultAuthType;
279
+ }
249
280
  if (authType === "authorization") return authType;
250
- consola.warn(`Provider ${providerName} has invalid authType '${authType}', falling back to ${getDefaultProviderAuthType(providerType)}`);
251
- return getDefaultProviderAuthType(providerType);
281
+ consola.warn(`Provider ${providerName} has invalid authType '${authType}', falling back to ${defaultAuthType}`);
282
+ return defaultAuthType;
283
+ }
284
+ function isProviderApiKeyRequired(providerName, authType) {
285
+ return !(providerName === "codex" && authType === "oauth2");
286
+ }
287
+ function getRawProviderConfig(name) {
288
+ const providerName = name.trim();
289
+ if (!providerName) return null;
290
+ return getConfig().providers?.[providerName] ?? null;
291
+ }
292
+ function setProviderConfig(name, provider) {
293
+ const providerName = name.trim();
294
+ if (!providerName) throw new Error("Provider name must be a non-empty string");
295
+ if (isReservedProviderName(providerName)) throw new Error(`Provider ${providerName} is reserved and cannot be configured in config.providers`);
296
+ const editableConfig = readEditableConfigFromDisk();
297
+ writeConfigToDisk({
298
+ ...editableConfig,
299
+ providers: {
300
+ ...editableConfig.providers,
301
+ [providerName]: provider
302
+ }
303
+ });
304
+ cachedConfig = reloadConfig();
305
+ return getRawProviderConfig(providerName) ?? provider;
252
306
  }
253
307
  function getProviderConfig(name) {
254
308
  const providerName = name.trim();
255
309
  if (!providerName) return null;
256
- const provider = getConfig().providers?.[providerName];
310
+ if (isReservedProviderName(providerName)) {
311
+ consola.warn(`Provider ${providerName} is reserved and cannot be configured in config.providers`);
312
+ return null;
313
+ }
314
+ const provider = getRawProviderConfig(providerName);
257
315
  if (!provider) return null;
258
316
  if (provider.enabled === false) return null;
259
317
  const type = provider.type ?? "anthropic";
260
- if (type !== "anthropic" && type !== "openai-compatible") {
318
+ if (type !== "anthropic" && type !== "openai-compatible" && type !== "openai-responses") {
261
319
  consola.warn(`Provider ${providerName} is ignored because type '${type}' is not supported`);
262
320
  return null;
263
321
  }
264
322
  const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? "");
265
- const apiKey = (provider.apiKey ?? "").trim();
266
323
  const authType = resolveProviderAuthType(providerName, provider.authType, type);
267
- if (!baseUrl || !apiKey) {
268
- consola.warn(`Provider ${providerName} is enabled but missing baseUrl or apiKey`);
324
+ const apiKey = (provider.apiKey ?? "").trim();
325
+ const missingFields = [...!baseUrl ? ["baseUrl"] : [], ...isProviderApiKeyRequired(providerName, authType) && !apiKey ? ["apiKey"] : []];
326
+ if (missingFields.length > 0) {
327
+ consola.warn(`Provider ${providerName} is enabled but missing ${missingFields.join(" or ")}`);
269
328
  return null;
270
329
  }
271
330
  return {
@@ -278,6 +337,13 @@ function getProviderConfig(name) {
278
337
  adjustInputTokens: provider.adjustInputTokens
279
338
  };
280
339
  }
340
+ function listEnabledProviders() {
341
+ const config = getConfig();
342
+ return Object.keys(config.providers ?? {}).filter((name) => getProviderConfig(name) !== null);
343
+ }
344
+ function isReservedProviderName(name) {
345
+ return name.trim() === "copilot";
346
+ }
281
347
  function isMessagesApiEnabled() {
282
348
  return getConfig().useMessagesApi ?? true;
283
349
  }
@@ -294,59 +360,6 @@ function getClaudeTokenMultiplier() {
294
360
  return getConfig().claudeTokenMultiplier ?? 1.15;
295
361
  }
296
362
  //#endregion
297
- //#region src/lib/proxy.ts
298
- let proxyEnvDispatcher;
299
- function getProxyEnvDispatcher() {
300
- return proxyEnvDispatcher;
301
- }
302
- function initProxyFromEnv() {
303
- try {
304
- const direct = new Agent();
305
- const proxies = /* @__PURE__ */ new Map();
306
- proxyEnvDispatcher = {
307
- dispatch(options, handler) {
308
- try {
309
- const origin = typeof options.origin === "string" ? new URL(options.origin) : options.origin;
310
- const raw = getProxyForUrl(origin.toString());
311
- const proxyUrl = raw && raw.length > 0 ? raw : void 0;
312
- if (!proxyUrl) {
313
- consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
314
- return direct.dispatch(options, handler);
315
- }
316
- let agent = proxies.get(proxyUrl);
317
- if (!agent) {
318
- agent = new ProxyAgent(proxyUrl);
319
- proxies.set(proxyUrl, agent);
320
- }
321
- let label = proxyUrl;
322
- try {
323
- const u = new URL(proxyUrl);
324
- label = `${u.protocol}//${u.host}`;
325
- } catch {}
326
- consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
327
- return agent.dispatch(options, handler);
328
- } catch {
329
- return direct.dispatch(options, handler);
330
- }
331
- },
332
- close() {
333
- return direct.close();
334
- },
335
- destroy() {
336
- return direct.destroy();
337
- }
338
- };
339
- if (typeof Bun !== "undefined") {
340
- consola.debug("WebSocket proxy configured from environment (per-URL)");
341
- return;
342
- }
343
- setGlobalDispatcher(proxyEnvDispatcher);
344
- consola.debug("HTTP proxy configured from environment (per-URL)");
345
- } catch (err) {
346
- consola.debug("Proxy setup skipped:", err);
347
- }
348
- }
349
- //#endregion
350
- export { setModelMappings as _, getConfig as a, getProviderConfig as c, isMessagesApiEnabled as d, isResponsesApiContextManagementModel as f, resolveMappedModel as g, mergeConfigWithDefaults as h, getClaudeTokenMultiplier as i, getReasoningEffortForModel as l, isResponsesApiWebSocketEnabled as m, initProxyFromEnv as n, getExtraPromptForModel as o, isResponsesApiWebSearchEnabled as p, getAnthropicApiKey as r, getModelMappings as s, getProxyEnvDispatcher as t, getSmallModel as u };
363
+ export { setModelMappings as _, getModelMappings as a, ensurePaths as b, getReasoningEffortForModel as c, isResponsesApiContextManagementModel as d, isResponsesApiWebSearchEnabled as f, resolveMappedModel as g, mergeConfigWithDefaults as h, getExtraPromptForModel as i, getSmallModel as l, listEnabledProviders as m, getClaudeTokenMultiplier as n, getProviderConfig as o, isResponsesApiWebSocketEnabled as p, getConfig as r, getRawProviderConfig as s, getAnthropicApiKey as t, isMessagesApiEnabled as u, setProviderConfig as v, PATHS as y };
351
364
 
352
- //# sourceMappingURL=proxy-DvlF9a-7.js.map
365
+ //# sourceMappingURL=config-ztdkLu9o.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-ztdkLu9o.js","names":["fs"],"sources":["../src/lib/paths.ts","../src/lib/config.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst AUTH_APP = process.env.COPILOT_API_OAUTH_APP?.trim() || \"\"\nconst ENTERPRISE_PREFIX = process.env.COPILOT_API_ENTERPRISE_URL ? \"ent_\" : \"\"\n\nconst DEFAULT_DIR = path.join(os.homedir(), \".local\", \"share\", \"copilot-api\")\nconst APP_DIR = process.env.COPILOT_API_HOME || DEFAULT_DIR\n\nconst GITHUB_TOKEN_PATH = path.join(\n APP_DIR,\n AUTH_APP,\n ENTERPRISE_PREFIX + \"github_token\",\n)\nconst CODEX_CREDENTIAL_PATH = path.join(APP_DIR, \"codex_credentials.json\")\nconst CONFIG_PATH = path.join(APP_DIR, \"config.json\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n CODEX_CREDENTIAL_PATH,\n CONFIG_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n await ensureFile(PATHS.CONFIG_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import consola from \"consola\"\nimport { randomBytes } from \"node:crypto\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n adminApiKey?: string\n }\n providers?: Record<string, ProviderConfig>\n modelMappings?: Record<string, string>\n extraPrompts?: Record<string, string>\n smallModel?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n useMessagesApi?: boolean\n useResponsesApiWebSocket?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n extraBody?: Record<string, unknown>\n contextCache?: boolean\n supportPdf?: boolean\n toolContentSupportType?: Array<ToolContentSupportType>\n}\n\nexport type ProviderAuthType = \"authorization\" | \"oauth2\" | \"x-api-key\"\nexport type ProviderType =\n | \"anthropic\"\n | \"openai-compatible\"\n | \"openai-responses\"\nexport type ToolContentSupportType = \"array\" | \"image\" | \"pdf\"\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n authType?: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: ProviderType\n baseUrl: string\n apiKey: string\n authType: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n providers: {},\n modelMappings: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4-mini\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n \"gpt-5.5\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4-mini\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n \"gpt-5.5\": \"xhigh\",\n },\n useMessagesApi: true,\n useResponsesApiWebSocket: true,\n useResponsesApiWebSearch: true,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction normalizeAdminApiKey(adminApiKey: unknown): string | null {\n if (typeof adminApiKey !== \"string\") {\n if (adminApiKey !== undefined) {\n consola.warn(\n \"Invalid auth.adminApiKey config. Expected a non-empty string.\",\n )\n }\n return null\n }\n\n const normalizedAdminApiKey = adminApiKey.trim()\n if (!normalizedAdminApiKey) {\n consola.warn(\n \"Invalid auth.adminApiKey config. Expected a non-empty string.\",\n )\n return null\n }\n\n return normalizedAdminApiKey\n}\n\nfunction generateAdminApiKey(): string {\n return randomBytes(32).toString(\"hex\")\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK | fs.constants.W_OK)\n } catch {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n return\n }\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction readEditableConfigFromDisk(): AppConfig {\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n return {}\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return {}\n }\n if (error instanceof SyntaxError) {\n throw new Error(`Config file is not valid JSON: ${PATHS.CONFIG_PATH}`)\n }\n throw error\n }\n}\n\nfunction writeConfigToDisk(config: AppConfig): void {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(config, null, 2)}\\n`,\n \"utf8\",\n )\n}\n\nfunction mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n\n if (!hasExtraPromptChanges && !hasReasoningEffortChanges) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n },\n changed: true,\n }\n}\n\nfunction ensureAdminApiKey(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalizedAdminApiKey = normalizeAdminApiKey(config.auth?.adminApiKey)\n if (normalizedAdminApiKey) {\n if (config.auth?.adminApiKey === normalizedAdminApiKey) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: {\n ...config.auth,\n adminApiKey: normalizedAdminApiKey,\n },\n },\n changed: true,\n }\n }\n\n const editableConfig = readEditableConfigFromDisk()\n const { mergedConfig } = mergeDefaultConfig({\n ...editableConfig,\n auth: {\n ...editableConfig.auth,\n adminApiKey: generateAdminApiKey(),\n },\n })\n\n return { mergedConfig, changed: true }\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n const { mergedConfig, changed } = mergeDefaultConfig(config)\n const {\n mergedConfig: mergedConfigWithAdminApiKey,\n changed: adminApiKeyChanged,\n } = ensureAdminApiKey(mergedConfig)\n const shouldPersistConfig = changed || adminApiKeyChanged\n\n if (shouldPersistConfig) {\n try {\n writeConfigToDisk(mergedConfigWithAdminApiKey)\n } catch (writeError) {\n if (adminApiKeyChanged) {\n throw writeError\n }\n\n consola.warn(\n \"Failed to write merged extraPrompts to config file\",\n writeError,\n )\n }\n }\n\n cachedConfig = mergedConfigWithAdminApiKey\n return mergedConfigWithAdminApiKey\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= mergeDefaultConfig(readConfigFromDisk()).mergedConfig\n return cachedConfig\n}\n\nexport function reloadConfig(): AppConfig {\n return mergeConfigWithDefaults()\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n return config.extraPrompts?.[model] ?? \"\"\n}\n\nexport function getModelMappings(): Record<string, string> {\n const config = getConfig()\n const modelMappings = config.modelMappings\n if (!modelMappings) {\n return { ...defaultConfig.modelMappings }\n }\n\n const validMappings: Record<string, string> = {}\n for (const [sourceModel, targetModel] of Object.entries(modelMappings)) {\n if (\n !sourceModel\n || typeof targetModel !== \"string\"\n || targetModel.length === 0\n ) {\n continue\n }\n validMappings[sourceModel] = targetModel\n }\n\n return validMappings\n}\n\nfunction validateModelMappings(\n modelMappings: Record<string, string>,\n): Record<string, string> {\n const validatedMappings: Record<string, string> = {}\n for (const [sourceModel, targetModel] of Object.entries(modelMappings)) {\n if (!sourceModel || !targetModel) {\n throw new Error(\n \"Each model mapping must use non-empty source and target values.\",\n )\n }\n validatedMappings[sourceModel] = targetModel\n }\n\n return validatedMappings\n}\n\nexport function setModelMappings(\n modelMappings: Record<string, string>,\n): Record<string, string> {\n const nextConfig = {\n ...readEditableConfigFromDisk(),\n modelMappings: validateModelMappings(modelMappings),\n }\n\n writeConfigToDisk(nextConfig)\n cachedConfig = reloadConfig()\n return getModelMappings()\n}\n\nexport function resolveMappedModel(model: string): string {\n return getModelMappings()[model] ?? model\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n return config.smallModel ?? \"gpt-5-mini\"\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n return config.modelReasoningEfforts?.[model] ?? \"high\"\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nfunction getDefaultProviderAuthType(\n providerType: ProviderType,\n): ProviderAuthType {\n return providerType === \"anthropic\" ? \"x-api-key\" : \"authorization\"\n}\n\nexport function resolveProviderAuthType(\n providerName: string,\n authType: string | undefined,\n providerType: ProviderType,\n): ProviderAuthType {\n const defaultAuthType = getDefaultProviderAuthType(providerType)\n if (authType === undefined) {\n return defaultAuthType\n }\n\n if (authType === \"x-api-key\") {\n return \"x-api-key\"\n }\n\n if (authType === \"oauth2\") {\n if (providerName === \"codex\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has authType 'oauth2', which is only supported by the builtin codex provider, falling back to ${defaultAuthType}`,\n )\n return defaultAuthType\n }\n\n if (authType === \"authorization\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has invalid authType '${authType}', falling back to ${defaultAuthType}`,\n )\n return defaultAuthType\n}\n\nfunction isProviderApiKeyRequired(\n providerName: string,\n authType: ProviderAuthType,\n): boolean {\n return !(providerName === \"codex\" && authType === \"oauth2\")\n}\n\nexport function getRawProviderConfig(name: string): ProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n return config.providers?.[providerName] ?? null\n}\n\nexport function setProviderConfig(\n name: string,\n provider: ProviderConfig,\n): ProviderConfig {\n const providerName = name.trim()\n if (!providerName) {\n throw new Error(\"Provider name must be a non-empty string\")\n }\n\n if (isReservedProviderName(providerName)) {\n throw new Error(\n `Provider ${providerName} is reserved and cannot be configured in config.providers`,\n )\n }\n\n const editableConfig = readEditableConfigFromDisk()\n const nextConfig = {\n ...editableConfig,\n providers: {\n ...editableConfig.providers,\n [providerName]: provider,\n },\n }\n\n writeConfigToDisk(nextConfig)\n cachedConfig = reloadConfig()\n return getRawProviderConfig(providerName) ?? provider\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n if (isReservedProviderName(providerName)) {\n consola.warn(\n `Provider ${providerName} is reserved and cannot be configured in config.providers`,\n )\n return null\n }\n\n const provider = getRawProviderConfig(providerName)\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? \"anthropic\"\n if (\n type !== \"anthropic\"\n && type !== \"openai-compatible\"\n && type !== \"openai-responses\"\n ) {\n consola.warn(\n `Provider ${providerName} is ignored because type '${type}' is not supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const authType = resolveProviderAuthType(\n providerName,\n provider.authType,\n type,\n )\n const apiKey = (provider.apiKey ?? \"\").trim()\n const missingFields = [\n ...(!baseUrl ? [\"baseUrl\"] : []),\n ...(isProviderApiKeyRequired(providerName, authType) && !apiKey ?\n [\"apiKey\"]\n : []),\n ]\n\n if (missingFields.length > 0) {\n consola.warn(\n `Provider ${providerName} is enabled but missing ${missingFields.join(\" or \")}`,\n )\n return null\n }\n\n return {\n name: providerName,\n type,\n baseUrl,\n apiKey,\n authType,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isReservedProviderName(name: string): boolean {\n return name.trim() === \"copilot\"\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n\nexport function isResponsesApiWebSocketEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSocket ?? true\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n const config = getConfig()\n return config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined\n}\n\nexport function isResponsesApiWebSearchEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSearch ?? true\n}\n\nexport function getClaudeTokenMultiplier(): number {\n const config = getConfig()\n return config.claudeTokenMultiplier ?? 1.15\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as PATHS } from "./paths-DC-mqCY3.js";
1
+ import { m as listEnabledProviders, s as getRawProviderConfig, y as PATHS } from "./config-ztdkLu9o.js";
2
2
  import { defineCommand } from "citty";
3
3
  import consola from "consola";
4
4
  import fs from "node:fs/promises";
@@ -22,21 +22,26 @@ function getRuntimeInfo() {
22
22
  arch: os.arch()
23
23
  };
24
24
  }
25
- async function checkTokenExists() {
25
+ async function checkFileExists(filePath) {
26
26
  try {
27
- if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
28
- return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
27
+ if (!(await fs.stat(filePath)).isFile()) return false;
28
+ return (await fs.readFile(filePath, "utf8")).trim().length > 0;
29
29
  } catch {
30
30
  return false;
31
31
  }
32
32
  }
33
33
  async function getDebugInfo() {
34
- const [version, tokenExists] = await Promise.all([getPackageVersion(), checkTokenExists()]);
34
+ const [version, tokenExists] = await Promise.all([getPackageVersion(), checkFileExists(PATHS.GITHUB_TOKEN_PATH)]);
35
35
  return {
36
+ providers: {
37
+ codexConfigured: getRawProviderConfig("codex") !== null,
38
+ enabled: listEnabledProviders()
39
+ },
36
40
  version,
37
41
  runtime: getRuntimeInfo(),
38
42
  paths: {
39
43
  APP_DIR: PATHS.APP_DIR,
44
+ CONFIG_PATH: PATHS.CONFIG_PATH,
40
45
  GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH
41
46
  },
42
47
  tokenExists
@@ -48,11 +53,16 @@ function printDebugInfoPlain(info) {
48
53
  Version: ${info.version}
49
54
  Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
50
55
 
56
+ Providers:
57
+ - enabled: ${info.providers.enabled.join(", ") || "none"}
58
+ - codex configured: ${info.providers.codexConfigured ? "Yes" : "No"}
59
+
51
60
  Paths:
52
61
  - APP_DIR: ${info.paths.APP_DIR}
62
+ - CONFIG_PATH: ${info.paths.CONFIG_PATH}
53
63
  - GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
54
64
 
55
- Token exists: ${info.tokenExists ? "Yes" : "No"}`);
65
+ GitHub token exists: ${info.tokenExists ? "Yes" : "No"}`);
56
66
  }
57
67
  function printDebugInfoJson(info) {
58
68
  console.log(JSON.stringify(info, null, 2));
@@ -79,4 +89,4 @@ const debug = defineCommand({
79
89
  //#endregion
80
90
  export { debug };
81
91
 
82
- //# sourceMappingURL=debug-C_TBkyUw.js.map
92
+ //# sourceMappingURL=debug-BVHmoCzY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-BVHmoCzY.js","names":[],"sources":["../src/debug.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { getRawProviderConfig, listEnabledProviders } from \"./lib/config\"\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n providers: {\n codexConfigured: boolean\n enabled: Array<string>\n }\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n CONFIG_PATH: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = fileURLToPath(\n new URL(\"../package.json\", import.meta.url),\n )\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkFileExists(filePath: string): Promise<boolean> {\n try {\n const stats = await fs.stat(filePath)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(filePath, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkFileExists(PATHS.GITHUB_TOKEN_PATH),\n ])\n\n return {\n providers: {\n codexConfigured: getRawProviderConfig(\"codex\") !== null,\n enabled: listEnabledProviders(),\n },\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n CONFIG_PATH: PATHS.CONFIG_PATH,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`copilot-api debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nProviders:\n- enabled: ${info.providers.enabled.join(\", \") || \"none\"}\n- codex configured: ${info.providers.codexConfigured ? \"Yes\" : \"No\"}\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- CONFIG_PATH: ${info.paths.CONFIG_PATH}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nGitHub token exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n"],"mappings":";;;;;;;AAmCA,eAAe,oBAAqC;CAClD,IAAI;EACF,MAAM,kBAAkB,cACtB,IAAI,IAAI,mBAAmB,OAAO,KAAK,IAAI,CAC5C;EAMD,OAHoB,KAAK,MAAM,MAAM,GAAG,SAAS,gBAAgB,CAG/C,CAAC;SACb;EACN,OAAO;;;AAIX,SAAS,iBAAiB;CACxB,MAAM,QAAQ,OAAO,QAAQ;CAE7B,OAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,SAAS,QAAQ,IAAI,UAAU,QAAQ,QAAQ,MAAM,EAAE;EACvD,UAAU,GAAG,UAAU;EACvB,MAAM,GAAG,MAAM;EAChB;;AAGH,eAAe,gBAAgB,UAAoC;CACjE,IAAI;EAEF,IAAI,EAAC,MADe,GAAG,KAAK,SAAS,EAC1B,QAAQ,EAAE,OAAO;EAG5B,QAAO,MADe,GAAG,SAAS,UAAU,OAAO,EACpC,MAAM,CAAC,SAAS;SACzB;EACN,OAAO;;;AAIX,eAAe,eAAmC;CAChD,MAAM,CAAC,SAAS,eAAe,MAAM,QAAQ,IAAI,CAC/C,mBAAmB,EACnB,gBAAgB,MAAM,kBAAkB,CACzC,CAAC;CAEF,OAAO;EACL,WAAW;GACT,iBAAiB,qBAAqB,QAAQ,KAAK;GACnD,SAAS,sBAAsB;GAChC;EACD;EACA,SAAS,gBAAgB;EACzB,OAAO;GACL,SAAS,MAAM;GACf,aAAa,MAAM;GACnB,mBAAmB,MAAM;GAC1B;EACD;EACD;;AAGH,SAAS,oBAAoB,MAAuB;CAClD,QAAQ,KAAK;;WAEJ,KAAK,QAAQ;WACb,KAAK,QAAQ,KAAK,GAAG,KAAK,QAAQ,QAAQ,IAAI,KAAK,QAAQ,SAAS,GAAG,KAAK,QAAQ,KAAK;;;aAGvF,KAAK,UAAU,QAAQ,KAAK,KAAK,IAAI,OAAO;sBACnC,KAAK,UAAU,kBAAkB,QAAQ,KAAK;;;aAGvD,KAAK,MAAM,QAAQ;iBACf,KAAK,MAAM,YAAY;uBACjB,KAAK,MAAM,kBAAkB;;uBAE7B,KAAK,cAAc,QAAQ,OAAO;;AAGzD,SAAS,mBAAmB,MAAuB;CACjD,QAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;AAG5C,eAAsB,SAAS,SAAyC;CACtE,MAAM,YAAY,MAAM,cAAc;CAEtC,IAAI,QAAQ,MACV,mBAAmB,UAAU;MAE7B,oBAAoB,UAAU;;AAIlC,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,SAAS;EACT,aAAa;EACd,EACF;CACD,IAAI,EAAE,QAAQ;EACZ,OAAO,SAAS,EACd,MAAM,KAAK,MACZ,CAAC;;CAEL,CAAC"}
package/dist/main.js CHANGED
@@ -39,11 +39,11 @@ if (typeof args["api-home"] === "string") process.env.COPILOT_API_HOME = args["a
39
39
  if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
40
40
  if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
41
41
  bindElectronFetch();
42
- const { auth } = await import("./auth-BHa2OHXf.js");
43
- const { checkUsage } = await import("./check-usage-BdXGp1Wr.js");
44
- const { debug } = await import("./debug-C_TBkyUw.js");
45
- const { mcp } = await import("./mcp-CTb-DbQH.js");
46
- const { start } = await import("./start-CbKg_0bY.js");
42
+ const { auth } = await import("./auth-BO_SkMVw.js");
43
+ const { checkUsage } = await import("./check-usage-D-W6VD7k.js");
44
+ const { debug } = await import("./debug-BVHmoCzY.js");
45
+ const { mcp } = await import("./mcp-DZgcvqQY.js");
46
+ const { start } = await import("./start-CM-b3DRX.js");
47
47
  await runMain(defineCommand({
48
48
  meta: {
49
49
  name: "copilot-api",
@@ -1,4 +1,4 @@
1
- import { n as createMcpToolSearchSentinel } from "./tool-search-D3SN0jX-.js";
1
+ import { n as createMcpToolSearchSentinel } from "./tool-search-wA-fLduL.js";
2
2
  import { defineCommand } from "citty";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -34,4 +34,4 @@ const mcp = defineCommand({
34
34
  //#endregion
35
35
  export { mcp };
36
36
 
37
- //# sourceMappingURL=mcp-CTb-DbQH.js.map
37
+ //# sourceMappingURL=mcp-DZgcvqQY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-CTb-DbQH.js","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { defineCommand } from \"citty\"\nimport { z } from \"zod\"\n\nimport { createMcpToolSearchSentinel } from \"./lib/tool-search\"\n\nconst SERVER_NAME = \"tool_search\"\nconst SERVER_VERSION = \"1.0.0\"\n\nexport const runMcpServer = async (): Promise<void> => {\n const server = new McpServer({\n name: SERVER_NAME,\n version: SERVER_VERSION,\n })\n\n server.registerTool(\n \"search\",\n {\n title: \"Tool Search Bridge\",\n description:\n \"Load deferred tools by exact name through the Copilot API tool_search bridge.\",\n inputSchema: {\n names: z\n .string()\n .describe(\n 'Comma-separated exact deferred tool names to load, for example \"TaskList,TaskGet,mcp__fetch__fetch\".',\n ),\n },\n _meta: {\n \"anthropic/alwaysLoad\": true,\n },\n },\n ({ names }) => ({\n content: [\n {\n type: \"text\",\n text: createMcpToolSearchSentinel(names),\n },\n ],\n }),\n )\n\n await server.connect(new StdioServerTransport())\n}\n\nexport const mcp = defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Start the Copilot API MCP tool_search bridge over stdio\",\n },\n run() {\n return runMcpServer()\n },\n})\n"],"mappings":";;;;;;AASA,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAEvB,MAAa,eAAe,YAA2B;CACrD,MAAM,SAAS,IAAI,UAAU;EAC3B,MAAM;EACN,SAAS;EACV,CAAC;CAEF,OAAO,aACL,UACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,OAAO,EACJ,QAAQ,CACR,SACC,yGACD,EACJ;EACD,OAAO,EACL,wBAAwB,MACzB;EACF,GACA,EAAE,aAAa,EACd,SAAS,CACP;EACE,MAAM;EACN,MAAM,4BAA4B,MAAM;EACzC,CACF,EACF,EACF;CAED,MAAM,OAAO,QAAQ,IAAI,sBAAsB,CAAC;;AAGlD,MAAa,MAAM,cAAc;CAC/B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,OAAO,cAAc;;CAExB,CAAC"}
1
+ {"version":3,"file":"mcp-DZgcvqQY.js","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { defineCommand } from \"citty\"\nimport { z } from \"zod\"\n\nimport { createMcpToolSearchSentinel } from \"./lib/tool-search\"\n\nconst SERVER_NAME = \"tool_search\"\nconst SERVER_VERSION = \"1.0.0\"\n\nexport const runMcpServer = async (): Promise<void> => {\n const server = new McpServer({\n name: SERVER_NAME,\n version: SERVER_VERSION,\n })\n\n server.registerTool(\n \"search\",\n {\n title: \"Tool Search Bridge\",\n description:\n \"Load deferred tools by exact name through the Copilot API tool_search bridge.\",\n inputSchema: {\n names: z\n .string()\n .describe(\n 'Comma-separated exact deferred tool names to load, for example \"TaskList,TaskGet,mcp__fetch__fetch\".',\n ),\n },\n _meta: {\n \"anthropic/alwaysLoad\": true,\n },\n },\n ({ names }) => ({\n content: [\n {\n type: \"text\",\n text: createMcpToolSearchSentinel(names),\n },\n ],\n }),\n )\n\n await server.connect(new StdioServerTransport())\n}\n\nexport const mcp = defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Start the Copilot API MCP tool_search bridge over stdio\",\n },\n run() {\n return runMcpServer()\n },\n})\n"],"mappings":";;;;;;AASA,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAEvB,MAAa,eAAe,YAA2B;CACrD,MAAM,SAAS,IAAI,UAAU;EAC3B,MAAM;EACN,SAAS;EACV,CAAC;CAEF,OAAO,aACL,UACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,OAAO,EACJ,QAAQ,CACR,SACC,yGACD,EACJ;EACD,OAAO,EACL,wBAAwB,MACzB;EACF,GACA,EAAE,aAAa,EACd,SAAS,CACP;EACE,MAAM;EACN,MAAM,4BAA4B,MAAM;EACzC,CACF,EACF,EACF;CAED,MAAM,OAAO,QAAQ,IAAI,sBAAsB,CAAC;;AAGlD,MAAa,MAAM,cAAc;CAC/B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,OAAO,cAAc;;CAExB,CAAC"}