@nick3/copilot-api 1.10.9 → 1.10.30
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 +140 -45
- package/README.zh-CN.md +140 -45
- package/dist/{account-COtMmvzU.js → account-DpW8RaT6.js} +3 -3
- package/dist/{account-COtMmvzU.js.map → account-DpW8RaT6.js.map} +1 -1
- package/dist/admin/AGENTS.md +19 -0
- package/dist/admin/assets/{index-BAh4eOwM.js → index-BGmG-ckX.js} +34 -34
- package/dist/admin/index.html +1 -1
- package/dist/auth-CnwhQOu6.js +327 -0
- package/dist/auth-CnwhQOu6.js.map +1 -0
- package/dist/{check-usage-DdevqHE5.js → check-usage-CseltoFJ.js} +4 -42
- package/dist/check-usage-CseltoFJ.js.map +1 -0
- package/dist/config-XZv75uoU.js +591 -0
- package/dist/config-XZv75uoU.js.map +1 -0
- package/dist/{debug-BMo6ltbp.js → debug-D8xHblDV.js} +18 -7
- package/dist/debug-D8xHblDV.js.map +1 -0
- package/dist/main.js +5 -10
- package/dist/main.js.map +1 -1
- package/dist/mcp-http-BhELuvog.js +2 -0
- package/dist/mcp-http-DI4Vz01p.js +82 -0
- package/dist/mcp-http-DI4Vz01p.js.map +1 -0
- package/dist/mcp-http-config-DMdUDz1D.js +39 -0
- package/dist/mcp-http-config-DMdUDz1D.js.map +1 -0
- package/dist/mcp-pLTPS0tO.js +79 -0
- package/dist/mcp-pLTPS0tO.js.map +1 -0
- package/dist/{tool-search-BrN7M0Dd.js → mcp-server-DEqHrXFq.js} +25 -2
- package/dist/mcp-server-DEqHrXFq.js.map +1 -0
- package/dist/{paths-CclKwouX.js → paths-Bpsb62LK.js} +3 -1
- package/dist/paths-Bpsb62LK.js.map +1 -0
- package/dist/{poll-access-token-BAgM2-7k.js → poll-access-token-GzVkiTH8.js} +71 -4
- package/dist/poll-access-token-GzVkiTH8.js.map +1 -0
- package/dist/{request-outbound-BJjWS_jF.js → request-outbound-BkEA8Wgb.js} +1 -1
- package/dist/{request-outbound-Pu1kp2x8.js → request-outbound-DZTxxtcx.js} +3 -3
- package/dist/{request-outbound-Pu1kp2x8.js.map → request-outbound-DZTxxtcx.js.map} +1 -1
- package/dist/{proxy-_U-hgwIn.js → responses-bridge-registry-JjUvTCST.js} +127 -581
- package/dist/responses-bridge-registry-JjUvTCST.js.map +1 -0
- package/dist/{server-GxNB5Syq.js → server-BYKxAFro.js} +678 -249
- package/dist/server-BYKxAFro.js.map +1 -0
- package/dist/start-DVlCJ0Ma.js +526 -0
- package/dist/start-DVlCJ0Ma.js.map +1 -0
- package/dist/token-9O2KJcF5.js +946 -0
- package/dist/token-9O2KJcF5.js.map +1 -0
- package/package.json +2 -2
- package/dist/auth-B0y-2njL.js +0 -226
- package/dist/auth-B0y-2njL.js.map +0 -1
- package/dist/check-usage-DdevqHE5.js.map +0 -1
- package/dist/debug-BMo6ltbp.js.map +0 -1
- package/dist/get-copilot-token-8Rm-rVsp.js +0 -17
- package/dist/get-copilot-token-8Rm-rVsp.js.map +0 -1
- package/dist/mcp-9Hgepkc5.js +0 -37
- package/dist/mcp-9Hgepkc5.js.map +0 -1
- package/dist/paths-CclKwouX.js.map +0 -1
- package/dist/poll-access-token-BAgM2-7k.js.map +0 -1
- package/dist/proxy-_U-hgwIn.js.map +0 -1
- package/dist/server-GxNB5Syq.js.map +0 -1
- package/dist/start-DdrurmQ3.js +0 -274
- package/dist/start-DdrurmQ3.js.map +0 -1
- package/dist/tool-search-BrN7M0Dd.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-XZv75uoU.js","names":[],"sources":["../src/lib/config.ts"],"sourcesContent":["import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport type LogLevel = \"error\" | \"warn\" | \"info\" | \"debug\"\n\nexport interface DevModeConfig {\n enabled: boolean\n capture4xx: boolean\n capture5xx: boolean\n captureOther: boolean\n}\n\nexport interface QuotaRefreshConfig {\n enabled?: boolean\n intervalMinutes?: number\n startupDelaySeconds?: number\n staggerMinSeconds?: number\n staggerMaxSeconds?: number\n}\n\nexport interface ResolvedQuotaRefreshConfig {\n enabled: boolean\n intervalMinutes: number\n startupDelaySeconds: number\n staggerMinSeconds: number\n staggerMaxSeconds: number\n}\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n accountAffinity?: boolean\n /** @deprecated */\n apiKey?: string\n /** @deprecated use useResponsesApiContextManagement */\n responsesApiContextManagementModels?: Array<string>\n useResponsesApiContextManagement?: boolean\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n modelAliases?: Record<string, { target: string; allowOriginal?: boolean }>\n allowOriginalModelNamesForAliases?: boolean\n modelMappings?: Record<string, string>\n forceAgent?: boolean\n compactUseSmallModel?: boolean\n messageStartInputTokensFallback?: boolean\n modelRefreshIntervalHours?: number\n sessionAffinityRetentionDays?: number\n useMessagesApi?: boolean\n useResponsesApiWebSocket?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n logLevel?: LogLevel\n devMode?: DevModeConfig\n quotaRefresh?: QuotaRefreshConfig\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 const PROVIDER_TYPE_ANTHROPIC = \"anthropic\" as const\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 DEFAULT_QUOTA_REFRESH_CONFIG: ResolvedQuotaRefreshConfig = {\n enabled: true,\n intervalMinutes: 360,\n startupDelaySeconds: 60,\n staggerMinSeconds: 2,\n staggerMaxSeconds: 5,\n}\n\nconst MIN_QUOTA_REFRESH_INTERVAL_MINUTES = 30\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 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 accountAffinity: true,\n useResponsesApiContextManagement: true,\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 allowOriginalModelNamesForAliases: false,\n modelMappings: {},\n forceAgent: false,\n compactUseSmallModel: true,\n messageStartInputTokensFallback: false,\n modelRefreshIntervalHours: 24,\n sessionAffinityRetentionDays: 7,\n useMessagesApi: true,\n useResponsesApiWebSocket: true,\n useResponsesApiWebSearch: true,\n logLevel: \"info\",\n devMode: {\n enabled: false,\n capture4xx: false,\n capture5xx: false,\n captureOther: false,\n },\n quotaRefresh: DEFAULT_QUOTA_REFRESH_CONFIG,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction normalizeAuthApiKeys(value: unknown): Array<string> {\n if (!Array.isArray(value)) return []\n\n return [\n ...new Set(\n value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0),\n ),\n ]\n}\n\nfunction normalizeNonNegativeNumber(value: unknown): number | undefined {\n if (typeof value !== \"number\") return undefined\n if (!Number.isFinite(value)) return undefined\n if (value < 0) return undefined\n return value\n}\n\nfunction normalizeQuotaRefreshIntervalMinutes(value: unknown): number {\n const normalized = normalizeNonNegativeNumber(value)\n const minutes = normalized ?? DEFAULT_QUOTA_REFRESH_CONFIG.intervalMinutes\n\n if (minutes > 0 && minutes < MIN_QUOTA_REFRESH_INTERVAL_MINUTES) {\n return MIN_QUOTA_REFRESH_INTERVAL_MINUTES\n }\n\n return minutes\n}\n\nexport function normalizeQuotaRefreshConfig(\n value: unknown,\n): ResolvedQuotaRefreshConfig {\n const raw = isPlainObject(value) ? value : {}\n const staggerMinSeconds =\n normalizeNonNegativeNumber(raw.staggerMinSeconds)\n ?? DEFAULT_QUOTA_REFRESH_CONFIG.staggerMinSeconds\n const rawStaggerMaxSeconds =\n normalizeNonNegativeNumber(raw.staggerMaxSeconds)\n ?? DEFAULT_QUOTA_REFRESH_CONFIG.staggerMaxSeconds\n\n return {\n enabled:\n typeof raw.enabled === \"boolean\" ?\n raw.enabled\n : DEFAULT_QUOTA_REFRESH_CONFIG.enabled,\n intervalMinutes: normalizeQuotaRefreshIntervalMinutes(raw.intervalMinutes),\n startupDelaySeconds:\n normalizeNonNegativeNumber(raw.startupDelaySeconds)\n ?? DEFAULT_QUOTA_REFRESH_CONFIG.startupDelaySeconds,\n staggerMinSeconds,\n staggerMaxSeconds: Math.max(staggerMinSeconds, rawStaggerMaxSeconds),\n }\n}\n\nconst LOG_LEVELS = new Set<LogLevel>([\"error\", \"warn\", \"info\", \"debug\"])\n\nfunction normalizeLogLevel(value: unknown): LogLevel | undefined {\n if (typeof value !== \"string\") return undefined\n return LOG_LEVELS.has(value as LogLevel) ? (value as LogLevel) : undefined\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK)\n return\n } catch {\n // Fall through to try creating the default config file.\n }\n\n try {\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 // Ignore chmod errors (e.g. unsupported filesystem).\n }\n } catch {\n // Best-effort only: if we can't create the file, reads will fall back to defaults.\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 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 reloadConfig(): AppConfig {\n return mergeConfigWithDefaults()\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 const hasForceAgent = typeof config.forceAgent === \"boolean\"\n const defaultForceAgent = defaultConfig.forceAgent ?? false\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 const hasForceAgentChanges = !hasForceAgent\n\n if (\n !hasExtraPromptChanges\n && !hasReasoningEffortChanges\n && !hasForceAgentChanges\n ) {\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 forceAgent: hasForceAgent ? config.forceAgent : defaultForceAgent,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAuth(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const authConfig = isPlainObject(config.auth) ? config.auth : undefined\n const rawApiKeys =\n Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : undefined\n const normalizedApiKeys = normalizeAuthApiKeys(rawApiKeys)\n const nextAuth = { apiKeys: normalizedApiKeys }\n\n if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: nextAuth,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAccountAffinity(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n // Migration: map old freeModelLoadBalancing to accountAffinity\n const raw = config as Record<string, unknown>\n const hasOld = typeof raw.freeModelLoadBalancing === \"boolean\"\n const hasNew = typeof config.accountAffinity === \"boolean\"\n\n if (hasOld) {\n const next = { ...config } as Record<string, unknown>\n if (!hasNew) {\n next.accountAffinity = raw.freeModelLoadBalancing\n }\n delete next.freeModelLoadBalancing\n return { mergedConfig: next, changed: true }\n }\n\n if (hasNew) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n accountAffinity: defaultConfig.accountAffinity ?? true,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultModelRefreshInterval(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultSessionAffinityRetention(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n sessionAffinityRetentionDays:\n defaultConfig.sessionAffinityRetentionDays ?? 7,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultLogLevel(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeLogLevel(config.logLevel)\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n logLevel: defaultConfig.logLevel ?? \"info\",\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultDevMode(config: AppConfig): ConfigMergeResult {\n const current = config.devMode\n if (\n current\n && typeof current.enabled === \"boolean\"\n && typeof current.capture4xx === \"boolean\"\n && typeof current.capture5xx === \"boolean\"\n && typeof current.captureOther === \"boolean\"\n ) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n devMode: {\n enabled: current?.enabled === true,\n capture4xx: current?.capture4xx === true,\n capture5xx: current?.capture5xx === true,\n captureOther: current?.captureOther === true,\n },\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultQuotaRefresh(config: AppConfig): ConfigMergeResult {\n const quotaRefresh = normalizeQuotaRefreshConfig(config.quotaRefresh)\n\n if (JSON.stringify(config.quotaRefresh) === JSON.stringify(quotaRefresh)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n quotaRefresh,\n },\n changed: true,\n }\n}\n\ntype ConfigMergeResult = {\n mergedConfig: AppConfig\n changed: boolean\n}\n\ntype ConfigMergeFn = (config: AppConfig) => ConfigMergeResult\n\nfunction applyConfigMerges(\n config: AppConfig,\n mergeFns: ReadonlyArray<ConfigMergeFn>,\n): ConfigMergeResult {\n return mergeFns.reduce<ConfigMergeResult>(\n (acc, mergeFn) => {\n const result = mergeFn(acc.mergedConfig)\n return {\n mergedConfig: result.mergedConfig,\n changed: acc.changed || result.changed,\n }\n },\n { mergedConfig: config, changed: false },\n )\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n\n const { mergedConfig, changed } = applyConfigMerges(config, [\n mergeDefaultAuth,\n mergeDefaultConfig,\n mergeDefaultAccountAffinity,\n mergeDefaultModelRefreshInterval,\n mergeDefaultSessionAffinityRetention,\n mergeDefaultLogLevel,\n mergeDefaultDevMode,\n mergeDefaultQuotaRefresh,\n ])\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\"Failed to write merged config defaults\", writeError)\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= mergeDefaultConfig(readConfigFromDisk()).mergedConfig\n return cachedConfig\n}\n\ntype ModelAliasSpec = {\n target: string\n allowOriginal?: boolean\n}\n\ntype ModelAliasMap = Record<string, string>\n\ntype ModelAliasInfoMap = Record<string, ModelAliasSpec>\n\ntype ModelAliasRawMap = Record<string, unknown>\n\nfunction normalizeAliasKey(value: string): string | null {\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasTarget(value: string): string | null {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasSpec(value: unknown): ModelAliasSpec | null {\n if (typeof value === \"string\") {\n const normalizedTarget = normalizeAliasTarget(value)\n return normalizedTarget ? { target: normalizedTarget } : null\n }\n if (!value || typeof value !== \"object\") {\n return null\n }\n\n const targetValue = (value as { target?: unknown }).target\n if (typeof targetValue !== \"string\") {\n return null\n }\n\n const normalizedTarget = normalizeAliasTarget(targetValue)\n if (!normalizedTarget) {\n return null\n }\n\n const allowOriginalValue = (value as { allowOriginal?: unknown })\n .allowOriginal\n const allowOriginal =\n typeof allowOriginalValue === \"boolean\" ? allowOriginalValue : undefined\n return { target: normalizedTarget, allowOriginal }\n}\n\nexport function getModelAliasesInfo(): ModelAliasInfoMap {\n const config = getConfig()\n const raw = (config.modelAliases ?? {}) as ModelAliasRawMap\n const normalized: ModelAliasInfoMap = {}\n\n for (const [alias, rawSpec] of Object.entries(raw)) {\n const normalizedAlias = normalizeAliasKey(alias)\n const normalizedSpec = normalizeAliasSpec(rawSpec)\n if (!normalizedAlias || !normalizedSpec) {\n continue\n }\n if (!Object.hasOwn(normalized, normalizedAlias)) {\n normalized[normalizedAlias] = normalizedSpec\n }\n }\n\n return normalized\n}\n\nexport function getModelAliases(): ModelAliasMap {\n const info = getModelAliasesInfo()\n const normalized: ModelAliasMap = {}\n\n for (const [alias, spec] of Object.entries(info)) {\n normalized[alias] = spec.target\n }\n\n return normalized\n}\n\nexport function resolveModelAlias(modelId: string): string {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return modelId\n const aliases = getModelAliases()\n return aliases[normalized] ?? modelId\n}\n\nexport function isOriginalModelNameAllowedForAliases(): boolean {\n const config = getConfig()\n return config.allowOriginalModelNamesForAliases ?? false\n}\n\nexport function getAliasTargetSet(): Set<string> {\n const aliases = getModelAliasesInfo()\n const allowOriginalDefault = isOriginalModelNameAllowedForAliases()\n const targetAllowMap = new Map<string, boolean>()\n\n for (const { target, allowOriginal } of Object.values(aliases)) {\n const normalizedTarget = target.toLowerCase()\n const effectiveAllow = allowOriginal ?? allowOriginalDefault\n const currentAllow = targetAllowMap.get(normalizedTarget)\n if (currentAllow === true) {\n continue\n }\n if (effectiveAllow) {\n targetAllowMap.set(normalizedTarget, true)\n } else if (currentAllow === undefined) {\n targetAllowMap.set(normalizedTarget, false)\n }\n }\n\n const blockedTargets = new Set<string>()\n for (const [target, allowed] of targetAllowMap.entries()) {\n if (!allowed) {\n blockedTargets.add(target)\n }\n }\n\n return blockedTargets\n}\n\nexport function isOriginalModelNameAllowedForTarget(modelId: string): boolean {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return true\n const blockedTargets = getAliasTargetSet()\n return !blockedTargets.has(normalized)\n}\n\nexport function getPreferredAliasForTarget(modelId: string): string | null {\n const aliases = getModelAliases()\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n return aliasKeys[0] ?? null\n}\n\nfunction getAliasKeysForTarget(\n target: string,\n aliases: ModelAliasMap,\n): Array<string> {\n const normalizedTarget = target.toLowerCase()\n return Object.entries(aliases)\n .filter(([, model]) => model.toLowerCase() === normalizedTarget)\n .map(([alias]) => alias)\n .sort()\n}\n\nfunction getAliasFallbackValue<T extends string>(\n record: Record<string, T> | undefined,\n modelId: string,\n aliases: ModelAliasMap,\n): T | undefined {\n if (!record) return undefined\n\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n if (aliasKeys.length === 0) return undefined\n\n const recordByAlias = new Map<string, T>()\n for (const [key, value] of Object.entries(record)) {\n const normalized = normalizeAliasKey(key)\n if (normalized) {\n recordByAlias.set(normalized, value)\n }\n }\n\n for (const alias of aliasKeys) {\n const value = recordByAlias.get(alias)\n if (value !== undefined) {\n return value\n }\n }\n\n return undefined\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n const direct = config.extraPrompts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(config.extraPrompts, model, aliases)\n return fallback ?? \"\"\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 ...readConfigFromDisk(),\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 const model = config.smallModel ?? \"gpt-5-mini\"\n if (isOriginalModelNameAllowedForTarget(model)) {\n return model\n }\n\n return getPreferredAliasForTarget(model) ?? model\n}\n\nexport function getLogLevel(): LogLevel {\n const config = getConfig()\n const normalized = normalizeLogLevel(config.logLevel)\n return normalized ?? defaultConfig.logLevel ?? \"info\"\n}\n\nexport function isAccountAffinityEnabled(): boolean {\n const config = getConfig()\n return config.accountAffinity ?? true\n}\n\nexport function getModelRefreshIntervalHours(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.modelRefreshIntervalHours,\n )\n return normalized ?? defaultConfig.modelRefreshIntervalHours ?? 24\n}\n\nexport function getModelRefreshIntervalMs(): number {\n const hours = getModelRefreshIntervalHours()\n if (!Number.isFinite(hours) || hours <= 0) return 0\n return hours * 60 * 60 * 1000\n}\n\nexport function getQuotaRefreshConfig(): ResolvedQuotaRefreshConfig {\n return normalizeQuotaRefreshConfig(getConfig().quotaRefresh)\n}\n\nexport function getSessionAffinityRetentionDays(): number {\n const config = getConfig()\n const normalized = normalizeNonNegativeNumber(\n config.sessionAffinityRetentionDays,\n )\n return normalized ?? defaultConfig.sessionAffinityRetentionDays ?? 7\n}\n\nexport function getSessionAffinityRetentionMs(): number {\n const days = getSessionAffinityRetentionDays()\n if (!Number.isFinite(days) || days <= 0) return 0\n return days * 24 * 60 * 60 * 1000\n}\n\nexport function isMessageStartInputTokensFallbackEnabled(): boolean {\n const config = getConfig()\n return config.messageStartInputTokensFallback ?? false\n}\n\nexport function shouldCompactUseSmallModel(): boolean {\n const config = getConfig()\n return config.compactUseSmallModel ?? true\n}\n\nexport function isResponsesApiContextManagementEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiContextManagement ?? true\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n const direct = config.modelReasoningEfforts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(\n config.modelReasoningEfforts,\n model,\n aliases,\n )\n return fallback ?? \"high\"\n}\n\nexport function isForceAgentEnabled(): boolean {\n const config = getConfig()\n return config.forceAgent ?? false\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 = readConfigFromDisk()\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 ?? PROVIDER_TYPE_ANTHROPIC\n if (\n type !== PROVIDER_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,5 @@
|
|
|
1
|
-
import { t as PATHS } from "./paths-
|
|
1
|
+
import { t as PATHS } from "./paths-Bpsb62LK.js";
|
|
2
|
+
import { p as getRawProviderConfig, w as listEnabledProviders } from "./config-XZv75uoU.js";
|
|
2
3
|
import { defineCommand } from "citty";
|
|
3
4
|
import consola from "consola";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
@@ -22,21 +23,26 @@ function getRuntimeInfo() {
|
|
|
22
23
|
arch: os.arch()
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
|
-
async function
|
|
26
|
+
async function checkFileExists(filePath) {
|
|
26
27
|
try {
|
|
27
|
-
if (!(await fs.stat(
|
|
28
|
-
return (await fs.readFile(
|
|
28
|
+
if (!(await fs.stat(filePath)).isFile()) return false;
|
|
29
|
+
return (await fs.readFile(filePath, "utf8")).trim().length > 0;
|
|
29
30
|
} catch {
|
|
30
31
|
return false;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
async function getDebugInfo() {
|
|
34
|
-
const [version, tokenExists] = await Promise.all([getPackageVersion(),
|
|
35
|
+
const [version, tokenExists] = await Promise.all([getPackageVersion(), checkFileExists(PATHS.GITHUB_TOKEN_PATH)]);
|
|
35
36
|
return {
|
|
37
|
+
providers: {
|
|
38
|
+
codexConfigured: getRawProviderConfig("codex") !== null,
|
|
39
|
+
enabled: listEnabledProviders()
|
|
40
|
+
},
|
|
36
41
|
version,
|
|
37
42
|
runtime: getRuntimeInfo(),
|
|
38
43
|
paths: {
|
|
39
44
|
APP_DIR: PATHS.APP_DIR,
|
|
45
|
+
CONFIG_PATH: PATHS.CONFIG_PATH,
|
|
40
46
|
GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH
|
|
41
47
|
},
|
|
42
48
|
tokenExists
|
|
@@ -48,11 +54,16 @@ function printDebugInfoPlain(info) {
|
|
|
48
54
|
Version: ${info.version}
|
|
49
55
|
Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
|
|
50
56
|
|
|
57
|
+
Providers:
|
|
58
|
+
- enabled: ${info.providers.enabled.join(", ") || "none"}
|
|
59
|
+
- codex configured: ${info.providers.codexConfigured ? "Yes" : "No"}
|
|
60
|
+
|
|
51
61
|
Paths:
|
|
52
62
|
- APP_DIR: ${info.paths.APP_DIR}
|
|
63
|
+
- CONFIG_PATH: ${info.paths.CONFIG_PATH}
|
|
53
64
|
- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
GitHub token exists: ${info.tokenExists ? "Yes" : "No"}`);
|
|
56
67
|
}
|
|
57
68
|
function printDebugInfoJson(info) {
|
|
58
69
|
console.log(JSON.stringify(info, null, 2));
|
|
@@ -79,4 +90,4 @@ const debug = defineCommand({
|
|
|
79
90
|
//#endregion
|
|
80
91
|
export { debug };
|
|
81
92
|
|
|
82
|
-
//# sourceMappingURL=debug-
|
|
93
|
+
//# sourceMappingURL=debug-D8xHblDV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-D8xHblDV.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
|
@@ -19,22 +19,17 @@ const args = parseArgs(process.argv, cliArgs);
|
|
|
19
19
|
if (typeof args["api-home"] === "string") process.env.COPILOT_API_HOME = args["api-home"];
|
|
20
20
|
if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
|
|
21
21
|
if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
|
|
22
|
-
const { auth } = await import("./auth-B0y-2njL.js");
|
|
23
|
-
const { checkUsage } = await import("./check-usage-DdevqHE5.js");
|
|
24
|
-
const { debug } = await import("./debug-BMo6ltbp.js");
|
|
25
|
-
const { mcp } = await import("./mcp-9Hgepkc5.js");
|
|
26
|
-
const { start } = await import("./start-DdrurmQ3.js");
|
|
27
22
|
await runMain(defineCommand({
|
|
28
23
|
meta: {
|
|
29
24
|
name: "copilot-api",
|
|
30
25
|
description: "A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools."
|
|
31
26
|
},
|
|
32
27
|
subCommands: {
|
|
33
|
-
auth,
|
|
34
|
-
start,
|
|
35
|
-
"check-usage": checkUsage,
|
|
36
|
-
debug,
|
|
37
|
-
mcp
|
|
28
|
+
auth: () => import("./auth-CnwhQOu6.js").then((mod) => mod.auth),
|
|
29
|
+
start: () => import("./start-DVlCJ0Ma.js").then((mod) => mod.start),
|
|
30
|
+
"check-usage": () => import("./check-usage-CseltoFJ.js").then((mod) => mod.checkUsage),
|
|
31
|
+
debug: () => import("./debug-D8xHblDV.js").then((mod) => mod.debug),
|
|
32
|
+
mcp: () => import("./mcp-pLTPS0tO.js").then((mod) => mod.mcp)
|
|
38
33
|
},
|
|
39
34
|
args: cliArgs
|
|
40
35
|
}));
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","names":[],"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand, runMain, parseArgs } from \"citty\"\n\nconst cliArgs = {\n \"api-home\": {\n type: \"string\",\n description: \"Path to the API home directory.\",\n },\n \"oauth-app\": {\n type: \"string\",\n description: \"OAuth app identifier.\",\n },\n \"enterprise-url\": {\n type: \"string\",\n description: \"Enterprise URL for GitHub.\",\n },\n} as const\n\nconst args = parseArgs(process.argv, cliArgs)\n\n// Set environment variables before loading other modules\nif (typeof args[\"api-home\"] === \"string\") {\n process.env.COPILOT_API_HOME = args[\"api-home\"]\n}\nif (typeof args[\"oauth-app\"] === \"string\") {\n process.env.COPILOT_API_OAUTH_APP = args[\"oauth-app\"]\n}\nif (typeof args[\"enterprise-url\"] === \"string\") {\n process.env.COPILOT_API_ENTERPRISE_URL = args[\"enterprise-url\"]\n}\n\
|
|
1
|
+
{"version":3,"file":"main.js","names":[],"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand, runMain, parseArgs } from \"citty\"\n\nconst cliArgs = {\n \"api-home\": {\n type: \"string\",\n description: \"Path to the API home directory.\",\n },\n \"oauth-app\": {\n type: \"string\",\n description: \"OAuth app identifier.\",\n },\n \"enterprise-url\": {\n type: \"string\",\n description: \"Enterprise URL for GitHub.\",\n },\n} as const\n\nconst args = parseArgs(process.argv, cliArgs)\n\n// Set environment variables before loading other modules\nif (typeof args[\"api-home\"] === \"string\") {\n process.env.COPILOT_API_HOME = args[\"api-home\"]\n}\nif (typeof args[\"oauth-app\"] === \"string\") {\n process.env.COPILOT_API_OAUTH_APP = args[\"oauth-app\"]\n}\nif (typeof args[\"enterprise-url\"] === \"string\") {\n process.env.COPILOT_API_ENTERPRISE_URL = args[\"enterprise-url\"]\n}\n\nconst main = defineCommand({\n meta: {\n name: \"copilot-api\",\n description:\n \"A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.\",\n },\n subCommands: {\n auth: () => import(\"./auth\").then((mod) => mod.auth),\n start: () => import(\"./start\").then((mod) => mod.start),\n \"check-usage\": () => import(\"./check-usage\").then((mod) => mod.checkUsage),\n debug: () => import(\"./debug\").then((mod) => mod.debug),\n mcp: () => import(\"./mcp\").then((mod) => mod.mcp),\n },\n args: cliArgs,\n})\n\nawait runMain(main)\n"],"mappings":";;;AAIA,MAAM,UAAU;CACd,YAAY;EACV,MAAM;EACN,aAAa;EACd;CACD,aAAa;EACX,MAAM;EACN,aAAa;EACd;CACD,kBAAkB;EAChB,MAAM;EACN,aAAa;EACd;CACF;AAED,MAAM,OAAO,UAAU,QAAQ,MAAM,QAAQ;AAG7C,IAAI,OAAO,KAAK,gBAAgB,UAC9B,QAAQ,IAAI,mBAAmB,KAAK;AAEtC,IAAI,OAAO,KAAK,iBAAiB,UAC/B,QAAQ,IAAI,wBAAwB,KAAK;AAE3C,IAAI,OAAO,KAAK,sBAAsB,UACpC,QAAQ,IAAI,6BAA6B,KAAK;AAmBhD,MAAM,QAhBO,cAAc;CACzB,MAAM;EACJ,MAAM;EACN,aACE;EACH;CACD,aAAa;EACX,YAAY,OAAO,sBAAU,MAAM,QAAQ,IAAI,KAAK;EACpD,aAAa,OAAO,uBAAW,MAAM,QAAQ,IAAI,MAAM;EACvD,qBAAqB,OAAO,6BAAiB,MAAM,QAAQ,IAAI,WAAW;EAC1E,aAAa,OAAO,uBAAW,MAAM,QAAQ,IAAI,MAAM;EACvD,WAAW,OAAO,qBAAS,MAAM,QAAQ,IAAI,IAAI;EAClD;CACD,MAAM;CACP,CAEiB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { a as resolveMcpHttpCorsOrigin, n as DEFAULT_MCP_HTTP_PATH } from "./mcp-http-config-DMdUDz1D.js";
|
|
2
|
+
import { t as createToolSearchMcpServer } from "./mcp-server-DEqHrXFq.js";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
5
|
+
import { Hono } from "hono";
|
|
6
|
+
import { cors } from "hono/cors";
|
|
7
|
+
import { serve } from "srvx";
|
|
8
|
+
//#region src/mcp-http.ts
|
|
9
|
+
const mcpHttpCorsOptions = {
|
|
10
|
+
origin: (origin) => resolveMcpHttpCorsOrigin(origin),
|
|
11
|
+
allowMethods: [
|
|
12
|
+
"GET",
|
|
13
|
+
"POST",
|
|
14
|
+
"DELETE",
|
|
15
|
+
"OPTIONS"
|
|
16
|
+
],
|
|
17
|
+
allowHeaders: [
|
|
18
|
+
"Content-Type",
|
|
19
|
+
"Last-Event-ID",
|
|
20
|
+
"MCP-Protocol-Version",
|
|
21
|
+
"Mcp-Session-Id",
|
|
22
|
+
"mcp-protocol-version",
|
|
23
|
+
"mcp-session-id"
|
|
24
|
+
],
|
|
25
|
+
exposeHeaders: [
|
|
26
|
+
"MCP-Protocol-Version",
|
|
27
|
+
"Mcp-Session-Id",
|
|
28
|
+
"mcp-protocol-version",
|
|
29
|
+
"mcp-session-id"
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
const handleStreamableHttpMcpRequest = async (request) => {
|
|
33
|
+
try {
|
|
34
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
35
|
+
enableJsonResponse: true,
|
|
36
|
+
sessionIdGenerator: void 0
|
|
37
|
+
});
|
|
38
|
+
const server = createToolSearchMcpServer();
|
|
39
|
+
server.server.onerror = (error) => {
|
|
40
|
+
consola.warn("MCP HTTP protocol error", {
|
|
41
|
+
method: request.method,
|
|
42
|
+
url: request.url,
|
|
43
|
+
message: error.message
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
await server.connect(transport);
|
|
47
|
+
return await transport.handleRequest(request);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
consola.error("Failed to handle MCP HTTP request", error);
|
|
50
|
+
return Response.json({
|
|
51
|
+
jsonrpc: "2.0",
|
|
52
|
+
error: {
|
|
53
|
+
code: -32603,
|
|
54
|
+
message: "Internal server error"
|
|
55
|
+
},
|
|
56
|
+
id: null
|
|
57
|
+
}, { status: 500 });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const createMcpHttpApp = (path = DEFAULT_MCP_HTTP_PATH) => {
|
|
61
|
+
const app = new Hono();
|
|
62
|
+
app.use("*", cors(mcpHttpCorsOptions));
|
|
63
|
+
if (path !== "/") app.get("/", (c) => c.text("MCP server running"));
|
|
64
|
+
app.all(path, (c) => handleStreamableHttpMcpRequest(c.req.raw));
|
|
65
|
+
return app;
|
|
66
|
+
};
|
|
67
|
+
const runMcpHttpServer = (options) => {
|
|
68
|
+
const app = createMcpHttpApp(options.path);
|
|
69
|
+
const endpoint = `http://${options.host}:${options.port}${options.path}`;
|
|
70
|
+
consola.warn("MCP Streamable HTTP is unauthenticated. Bind only to trusted networks.");
|
|
71
|
+
consola.info(`MCP endpoint: ${endpoint}`);
|
|
72
|
+
serve({
|
|
73
|
+
fetch: app.fetch,
|
|
74
|
+
hostname: options.host,
|
|
75
|
+
port: options.port,
|
|
76
|
+
bun: { idleTimeout: 0 }
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { runMcpHttpServer as i, handleStreamableHttpMcpRequest as n, mcpHttpCorsOptions as r, createMcpHttpApp as t };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=mcp-http-DI4Vz01p.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-http-DI4Vz01p.js","names":[],"sources":["../src/mcp-http.ts"],"sourcesContent":["import { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\"\nimport consola from \"consola\"\nimport { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { serve } from \"srvx\"\n\nimport {\n DEFAULT_MCP_HTTP_PATH,\n resolveMcpHttpCorsOrigin,\n type McpHttpServerOptions,\n} from \"~/mcp-http-config\"\nimport { createToolSearchMcpServer } from \"~/mcp-server\"\n\nexport const mcpHttpCorsOptions = {\n origin: (origin: string) => resolveMcpHttpCorsOrigin(origin),\n allowMethods: [\"GET\", \"POST\", \"DELETE\", \"OPTIONS\"],\n allowHeaders: [\n \"Content-Type\",\n \"Last-Event-ID\",\n \"MCP-Protocol-Version\",\n \"Mcp-Session-Id\",\n \"mcp-protocol-version\",\n \"mcp-session-id\",\n ],\n exposeHeaders: [\n \"MCP-Protocol-Version\",\n \"Mcp-Session-Id\",\n \"mcp-protocol-version\",\n \"mcp-session-id\",\n ],\n}\n\nexport const handleStreamableHttpMcpRequest = async (\n request: Request,\n): Promise<Response> => {\n try {\n const transport = new WebStandardStreamableHTTPServerTransport({\n enableJsonResponse: true,\n sessionIdGenerator: undefined,\n })\n const server = createToolSearchMcpServer()\n server.server.onerror = (error) => {\n consola.warn(\"MCP HTTP protocol error\", {\n method: request.method,\n url: request.url,\n message: error.message,\n })\n }\n\n await server.connect(transport)\n return await transport.handleRequest(request)\n } catch (error) {\n consola.error(\"Failed to handle MCP HTTP request\", error)\n\n return Response.json(\n {\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: \"Internal server error\",\n },\n id: null,\n },\n { status: 500 },\n )\n }\n}\n\nexport const createMcpHttpApp = (path = DEFAULT_MCP_HTTP_PATH): Hono => {\n const app = new Hono()\n\n app.use(\"*\", cors(mcpHttpCorsOptions))\n if (path !== \"/\") {\n app.get(\"/\", (c) => c.text(\"MCP server running\"))\n }\n app.all(path, (c) => handleStreamableHttpMcpRequest(c.req.raw))\n\n return app\n}\n\nexport const runMcpHttpServer = (options: McpHttpServerOptions): void => {\n const app = createMcpHttpApp(options.path)\n const endpoint = `http://${options.host}:${options.port}${options.path}`\n\n consola.warn(\n \"MCP Streamable HTTP is unauthenticated. Bind only to trusted networks.\",\n )\n consola.info(`MCP endpoint: ${endpoint}`)\n\n serve({\n fetch: app.fetch,\n hostname: options.host,\n port: options.port,\n bun: {\n idleTimeout: 0,\n },\n })\n}\n"],"mappings":";;;;;;;;AAaA,MAAa,qBAAqB;CAChC,SAAS,WAAmB,yBAAyB,OAAO;CAC5D,cAAc;EAAC;EAAO;EAAQ;EAAU;EAAU;CAClD,cAAc;EACZ;EACA;EACA;EACA;EACA;EACA;EACD;CACD,eAAe;EACb;EACA;EACA;EACA;EACD;CACF;AAED,MAAa,iCAAiC,OAC5C,YACsB;CACtB,IAAI;EACF,MAAM,YAAY,IAAI,yCAAyC;GAC7D,oBAAoB;GACpB,oBAAoB,KAAA;GACrB,CAAC;EACF,MAAM,SAAS,2BAA2B;EAC1C,OAAO,OAAO,WAAW,UAAU;GACjC,QAAQ,KAAK,2BAA2B;IACtC,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,SAAS,MAAM;IAChB,CAAC;;EAGJ,MAAM,OAAO,QAAQ,UAAU;EAC/B,OAAO,MAAM,UAAU,cAAc,QAAQ;UACtC,OAAO;EACd,QAAQ,MAAM,qCAAqC,MAAM;EAEzD,OAAO,SAAS,KACd;GACE,SAAS;GACT,OAAO;IACL,MAAM;IACN,SAAS;IACV;GACD,IAAI;GACL,EACD,EAAE,QAAQ,KAAK,CAChB;;;AAIL,MAAa,oBAAoB,OAAO,0BAAgC;CACtE,MAAM,MAAM,IAAI,MAAM;CAEtB,IAAI,IAAI,KAAK,KAAK,mBAAmB,CAAC;CACtC,IAAI,SAAS,KACX,IAAI,IAAI,MAAM,MAAM,EAAE,KAAK,qBAAqB,CAAC;CAEnD,IAAI,IAAI,OAAO,MAAM,+BAA+B,EAAE,IAAI,IAAI,CAAC;CAE/D,OAAO;;AAGT,MAAa,oBAAoB,YAAwC;CACvE,MAAM,MAAM,iBAAiB,QAAQ,KAAK;CAC1C,MAAM,WAAW,UAAU,QAAQ,KAAK,GAAG,QAAQ,OAAO,QAAQ;CAElE,QAAQ,KACN,yEACD;CACD,QAAQ,KAAK,iBAAiB,WAAW;CAEzC,MAAM;EACJ,OAAO,IAAI;EACX,UAAU,QAAQ;EAClB,MAAM,QAAQ;EACd,KAAK,EACH,aAAa,GACd;EACF,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/mcp-http-config.ts
|
|
2
|
+
const MCP_HTTP_ENABLED_ENV = "COPILOT_API_ENABLE_MCP_HTTP";
|
|
3
|
+
const MCP_HTTP_ALLOWED_ORIGINS_ENV = "COPILOT_API_MCP_HTTP_ALLOWED_ORIGINS";
|
|
4
|
+
const DEFAULT_MCP_HTTP_HOST = "127.0.0.1";
|
|
5
|
+
const DEFAULT_MCP_HTTP_PORT = 4142;
|
|
6
|
+
const DEFAULT_MCP_HTTP_PATH = "/mcp";
|
|
7
|
+
const LOOPBACK_CORS_HOSTS = new Set([
|
|
8
|
+
"localhost",
|
|
9
|
+
"127.0.0.1",
|
|
10
|
+
"::1",
|
|
11
|
+
"[::1]"
|
|
12
|
+
]);
|
|
13
|
+
function isMcpHttpEnabledValue(value) {
|
|
14
|
+
const normalized = value?.trim().toLowerCase();
|
|
15
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
16
|
+
}
|
|
17
|
+
function isMcpHttpEnabledFromEnv(env = process.env) {
|
|
18
|
+
return isMcpHttpEnabledValue(env[MCP_HTTP_ENABLED_ENV]);
|
|
19
|
+
}
|
|
20
|
+
function parseMcpHttpAllowedOrigins(value = process.env[MCP_HTTP_ALLOWED_ORIGINS_ENV]) {
|
|
21
|
+
return value?.split(",").map((origin) => origin.trim()).filter(Boolean) ?? [];
|
|
22
|
+
}
|
|
23
|
+
function isLoopbackCorsOrigin(origin) {
|
|
24
|
+
try {
|
|
25
|
+
const url = new URL(origin);
|
|
26
|
+
return (url.protocol === "http:" || url.protocol === "https:") && LOOPBACK_CORS_HOSTS.has(url.hostname);
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function resolveMcpHttpCorsOrigin(origin, allowedOrigins = parseMcpHttpAllowedOrigins()) {
|
|
32
|
+
if (!origin) return;
|
|
33
|
+
if (allowedOrigins.includes("*")) return "*";
|
|
34
|
+
if (allowedOrigins.includes(origin) || isLoopbackCorsOrigin(origin)) return origin;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { resolveMcpHttpCorsOrigin as a, isMcpHttpEnabledFromEnv as i, DEFAULT_MCP_HTTP_PATH as n, DEFAULT_MCP_HTTP_PORT as r, DEFAULT_MCP_HTTP_HOST as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=mcp-http-config-DMdUDz1D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-http-config-DMdUDz1D.js","names":[],"sources":["../src/mcp-http-config.ts"],"sourcesContent":["export const MCP_HTTP_ENABLED_ENV = \"COPILOT_API_ENABLE_MCP_HTTP\"\nexport const MCP_HTTP_ALLOWED_ORIGINS_ENV =\n \"COPILOT_API_MCP_HTTP_ALLOWED_ORIGINS\"\nexport const DEFAULT_MCP_HTTP_HOST = \"127.0.0.1\"\nexport const DEFAULT_MCP_HTTP_PORT = 4142\nexport const DEFAULT_MCP_HTTP_PATH = \"/mcp\"\n\nconst LOOPBACK_CORS_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\"])\n\nexport interface McpHttpServerOptions {\n host: string\n path: string\n port: number\n}\n\nexport function isMcpHttpEnabledValue(value: string | undefined): boolean {\n const normalized = value?.trim().toLowerCase()\n\n return (\n normalized === \"1\"\n || normalized === \"true\"\n || normalized === \"yes\"\n || normalized === \"on\"\n )\n}\n\nexport function isMcpHttpEnabledFromEnv(\n env: Record<string, string | undefined> = process.env,\n): boolean {\n return isMcpHttpEnabledValue(env[MCP_HTTP_ENABLED_ENV])\n}\n\nexport function parseMcpHttpAllowedOrigins(\n value: string | undefined = process.env[MCP_HTTP_ALLOWED_ORIGINS_ENV],\n): Array<string> {\n return (\n value\n ?.split(\",\")\n .map((origin) => origin.trim())\n .filter(Boolean) ?? []\n )\n}\n\nfunction isLoopbackCorsOrigin(origin: string): boolean {\n try {\n const url = new URL(origin)\n\n return (\n (url.protocol === \"http:\" || url.protocol === \"https:\")\n && LOOPBACK_CORS_HOSTS.has(url.hostname)\n )\n } catch {\n return false\n }\n}\n\nexport function resolveMcpHttpCorsOrigin(\n origin: string | undefined,\n allowedOrigins = parseMcpHttpAllowedOrigins(),\n): string | undefined {\n if (!origin) {\n return undefined\n }\n\n if (allowedOrigins.includes(\"*\")) {\n return \"*\"\n }\n\n if (allowedOrigins.includes(origin) || isLoopbackCorsOrigin(origin)) {\n return origin\n }\n\n return undefined\n}\n"],"mappings":";AAAA,MAAa,uBAAuB;AACpC,MAAa,+BACX;AACF,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AACrC,MAAa,wBAAwB;AAErC,MAAM,sBAAsB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAO;CAAQ,CAAC;AAQ/E,SAAgB,sBAAsB,OAAoC;CACxE,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;CAE9C,OACE,eAAe,OACZ,eAAe,UACf,eAAe,SACf,eAAe;;AAItB,SAAgB,wBACd,MAA0C,QAAQ,KACzC;CACT,OAAO,sBAAsB,IAAI,sBAAsB;;AAGzD,SAAgB,2BACd,QAA4B,QAAQ,IAAI,+BACzB;CACf,OACE,OACI,MAAM,IAAI,CACX,KAAK,WAAW,OAAO,MAAM,CAAC,CAC9B,OAAO,QAAQ,IAAI,EAAE;;AAI5B,SAAS,qBAAqB,QAAyB;CACrD,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,OAAO;EAE3B,QACG,IAAI,aAAa,WAAW,IAAI,aAAa,aAC3C,oBAAoB,IAAI,IAAI,SAAS;SAEpC;EACN,OAAO;;;AAIX,SAAgB,yBACd,QACA,iBAAiB,4BAA4B,EACzB;CACpB,IAAI,CAAC,QACH;CAGF,IAAI,eAAe,SAAS,IAAI,EAC9B,OAAO;CAGT,IAAI,eAAe,SAAS,OAAO,IAAI,qBAAqB,OAAO,EACjE,OAAO"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { n as DEFAULT_MCP_HTTP_PATH, r as DEFAULT_MCP_HTTP_PORT, t as DEFAULT_MCP_HTTP_HOST } from "./mcp-http-config-DMdUDz1D.js";
|
|
2
|
+
import { t as createToolSearchMcpServer } from "./mcp-server-DEqHrXFq.js";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
//#region src/mcp.ts
|
|
7
|
+
const runMcpServer = async () => {
|
|
8
|
+
await createToolSearchMcpServer().connect(new StdioServerTransport());
|
|
9
|
+
};
|
|
10
|
+
function parseMcpTransport(value) {
|
|
11
|
+
const transport = (value ?? "stdio").trim();
|
|
12
|
+
if (transport === "stdio" || transport === "http") return transport;
|
|
13
|
+
throw new Error("--transport must be either stdio or http");
|
|
14
|
+
}
|
|
15
|
+
function parseMcpHttpPort(value) {
|
|
16
|
+
const portRaw = (value ?? String(4142)).trim();
|
|
17
|
+
if (!/^\d+$/.test(portRaw)) throw new Error("--port must be an integer from 1 to 65535");
|
|
18
|
+
const port = Number.parseInt(portRaw, 10);
|
|
19
|
+
if (port < 1 || port > 65535) throw new Error("--port must be an integer from 1 to 65535");
|
|
20
|
+
return port;
|
|
21
|
+
}
|
|
22
|
+
function parseMcpHttpOptions(args) {
|
|
23
|
+
const host = (args.host ?? "127.0.0.1").trim();
|
|
24
|
+
const path = (args.path ?? "/mcp").trim();
|
|
25
|
+
if (host.length === 0) throw new Error("--host must not be empty");
|
|
26
|
+
if (!path.startsWith("/")) throw new Error("--path must start with /");
|
|
27
|
+
return {
|
|
28
|
+
host,
|
|
29
|
+
path,
|
|
30
|
+
port: parseMcpHttpPort(args.port)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async function runMcpCommand(args) {
|
|
34
|
+
if (parseMcpTransport(args.transport) === "stdio") {
|
|
35
|
+
await runMcpServer();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const options = parseMcpHttpOptions(args);
|
|
39
|
+
const { runMcpHttpServer } = await import("./mcp-http-BhELuvog.js");
|
|
40
|
+
runMcpHttpServer(options);
|
|
41
|
+
}
|
|
42
|
+
const mcp = defineCommand({
|
|
43
|
+
meta: {
|
|
44
|
+
name: "mcp",
|
|
45
|
+
description: "Start the Copilot API MCP tool_search bridge over stdio or Streamable HTTP"
|
|
46
|
+
},
|
|
47
|
+
args: {
|
|
48
|
+
transport: {
|
|
49
|
+
type: "string",
|
|
50
|
+
default: "stdio",
|
|
51
|
+
description: "Transport to use: stdio or http"
|
|
52
|
+
},
|
|
53
|
+
port: {
|
|
54
|
+
type: "string",
|
|
55
|
+
default: String(DEFAULT_MCP_HTTP_PORT),
|
|
56
|
+
description: "HTTP transport port"
|
|
57
|
+
},
|
|
58
|
+
host: {
|
|
59
|
+
type: "string",
|
|
60
|
+
default: DEFAULT_MCP_HTTP_HOST,
|
|
61
|
+
description: "HTTP transport host"
|
|
62
|
+
},
|
|
63
|
+
path: {
|
|
64
|
+
type: "string",
|
|
65
|
+
default: DEFAULT_MCP_HTTP_PATH,
|
|
66
|
+
description: "HTTP transport path"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
run({ args }) {
|
|
70
|
+
return runMcpCommand(args).catch((error) => {
|
|
71
|
+
consola.error(error instanceof Error ? error.message : String(error));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
//#endregion
|
|
77
|
+
export { mcp };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=mcp-pLTPS0tO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-pLTPS0tO.js","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport {\n DEFAULT_MCP_HTTP_HOST,\n DEFAULT_MCP_HTTP_PATH,\n DEFAULT_MCP_HTTP_PORT,\n type McpHttpServerOptions,\n} from \"~/mcp-http-config\"\nimport { createToolSearchMcpServer } from \"~/mcp-server\"\n\ntype McpTransport = \"stdio\" | \"http\"\n\ninterface McpCommandArgs {\n host?: string\n path?: string\n port?: string\n transport?: string\n}\n\nexport const runMcpServer = async (): Promise<void> => {\n const server = createToolSearchMcpServer()\n\n await server.connect(new StdioServerTransport())\n}\n\nfunction parseMcpTransport(value: string | undefined): McpTransport {\n const transport = (value ?? \"stdio\").trim()\n\n if (transport === \"stdio\" || transport === \"http\") {\n return transport\n }\n\n throw new Error(\"--transport must be either stdio or http\")\n}\n\nfunction parseMcpHttpPort(value: string | undefined): number {\n const portRaw = (value ?? String(DEFAULT_MCP_HTTP_PORT)).trim()\n\n if (!/^\\d+$/.test(portRaw)) {\n throw new Error(\"--port must be an integer from 1 to 65535\")\n }\n\n const port = Number.parseInt(portRaw, 10)\n if (port < 1 || port > 65535) {\n throw new Error(\"--port must be an integer from 1 to 65535\")\n }\n\n return port\n}\n\nexport function parseMcpHttpOptions(\n args: Pick<McpCommandArgs, \"host\" | \"path\" | \"port\">,\n): McpHttpServerOptions {\n const host = (args.host ?? DEFAULT_MCP_HTTP_HOST).trim()\n const path = (args.path ?? DEFAULT_MCP_HTTP_PATH).trim()\n\n if (host.length === 0) {\n throw new Error(\"--host must not be empty\")\n }\n\n if (!path.startsWith(\"/\")) {\n throw new Error(\"--path must start with /\")\n }\n\n return {\n host,\n path,\n port: parseMcpHttpPort(args.port),\n }\n}\n\nexport async function runMcpCommand(args: McpCommandArgs): Promise<void> {\n const transport = parseMcpTransport(args.transport)\n\n if (transport === \"stdio\") {\n await runMcpServer()\n return\n }\n\n const options = parseMcpHttpOptions(args)\n const { runMcpHttpServer } = await import(\"./mcp-http\")\n runMcpHttpServer(options)\n}\n\nexport const mcp = defineCommand({\n meta: {\n name: \"mcp\",\n description:\n \"Start the Copilot API MCP tool_search bridge over stdio or Streamable HTTP\",\n },\n args: {\n transport: {\n type: \"string\",\n default: \"stdio\",\n description: \"Transport to use: stdio or http\",\n },\n port: {\n type: \"string\",\n default: String(DEFAULT_MCP_HTTP_PORT),\n description: \"HTTP transport port\",\n },\n host: {\n type: \"string\",\n default: DEFAULT_MCP_HTTP_HOST,\n description: \"HTTP transport host\",\n },\n path: {\n type: \"string\",\n default: DEFAULT_MCP_HTTP_PATH,\n description: \"HTTP transport path\",\n },\n },\n run({ args }) {\n return runMcpCommand(args).catch((error: unknown) => {\n consola.error(error instanceof Error ? error.message : String(error))\n process.exit(1)\n })\n },\n})\n"],"mappings":";;;;;;AAuBA,MAAa,eAAe,YAA2B;CAGrD,MAFe,2BAEH,CAAC,QAAQ,IAAI,sBAAsB,CAAC;;AAGlD,SAAS,kBAAkB,OAAyC;CAClE,MAAM,aAAa,SAAS,SAAS,MAAM;CAE3C,IAAI,cAAc,WAAW,cAAc,QACzC,OAAO;CAGT,MAAM,IAAI,MAAM,2CAA2C;;AAG7D,SAAS,iBAAiB,OAAmC;CAC3D,MAAM,WAAW,SAAS,OAAA,KAA6B,EAAE,MAAM;CAE/D,IAAI,CAAC,QAAQ,KAAK,QAAQ,EACxB,MAAM,IAAI,MAAM,4CAA4C;CAG9D,MAAM,OAAO,OAAO,SAAS,SAAS,GAAG;CACzC,IAAI,OAAO,KAAK,OAAO,OACrB,MAAM,IAAI,MAAM,4CAA4C;CAG9D,OAAO;;AAGT,SAAgB,oBACd,MACsB;CACtB,MAAM,QAAQ,KAAK,QAAA,aAA+B,MAAM;CACxD,MAAM,QAAQ,KAAK,QAAA,QAA+B,MAAM;CAExD,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,2BAA2B;CAG7C,IAAI,CAAC,KAAK,WAAW,IAAI,EACvB,MAAM,IAAI,MAAM,2BAA2B;CAG7C,OAAO;EACL;EACA;EACA,MAAM,iBAAiB,KAAK,KAAK;EAClC;;AAGH,eAAsB,cAAc,MAAqC;CAGvE,IAFkB,kBAAkB,KAAK,UAE5B,KAAK,SAAS;EACzB,MAAM,cAAc;EACpB;;CAGF,MAAM,UAAU,oBAAoB,KAAK;CACzC,MAAM,EAAE,qBAAqB,MAAM,OAAO;CAC1C,iBAAiB,QAAQ;;AAG3B,MAAa,MAAM,cAAc;CAC/B,MAAM;EACJ,MAAM;EACN,aACE;EACH;CACD,MAAM;EACJ,WAAW;GACT,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,MAAM;GACJ,MAAM;GACN,SAAS,OAAO,sBAAsB;GACtC,aAAa;GACd;EACD,MAAM;GACJ,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,MAAM;GACJ,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACF;CACD,IAAI,EAAE,QAAQ;EACZ,OAAO,cAAc,KAAK,CAAC,OAAO,UAAmB;GACnD,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC;GACrE,QAAQ,KAAK,EAAE;IACf;;CAEL,CAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1
3
|
//#region src/lib/tool-search.ts
|
|
2
4
|
const BRIDGE_TOOL_SEARCH_NAME = "mcp__tool_search__search";
|
|
3
5
|
const BRIDGE_TOOL_SEARCH_ALIASES = [
|
|
@@ -105,6 +107,27 @@ const selectDeferredToolsByNames = (names, tools) => {
|
|
|
105
107
|
});
|
|
106
108
|
};
|
|
107
109
|
//#endregion
|
|
108
|
-
|
|
110
|
+
//#region src/mcp-server.ts
|
|
111
|
+
const MCP_TOOL_SEARCH_SERVER_NAME = "tool_search";
|
|
112
|
+
const MCP_TOOL_SEARCH_SERVER_VERSION = "1.0.0";
|
|
113
|
+
const MCP_TOOL_SEARCH_TOOL_NAME = "search";
|
|
114
|
+
const createToolSearchMcpServer = () => {
|
|
115
|
+
const server = new McpServer({
|
|
116
|
+
name: MCP_TOOL_SEARCH_SERVER_NAME,
|
|
117
|
+
version: MCP_TOOL_SEARCH_SERVER_VERSION
|
|
118
|
+
});
|
|
119
|
+
server.registerTool(MCP_TOOL_SEARCH_TOOL_NAME, {
|
|
120
|
+
title: "Tool Search Bridge",
|
|
121
|
+
description: "Load deferred tools by exact name through the Copilot API tool_search bridge.",
|
|
122
|
+
inputSchema: { names: z.string().describe("Comma-separated exact deferred tool names to load, for example \"TaskList,TaskGet,mcp__fetch__fetch\".") },
|
|
123
|
+
_meta: { "anthropic/alwaysLoad": true }
|
|
124
|
+
}, ({ names }) => ({ content: [{
|
|
125
|
+
type: "text",
|
|
126
|
+
text: createMcpToolSearchSentinel(names)
|
|
127
|
+
}] }));
|
|
128
|
+
return server;
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
export { isDeferredToolName as a, parseMcpToolSearchSentinel as c, isBridgeToolSearchName as i, selectDeferredToolsByNames as l, BRIDGE_TOOL_SEARCH_NAME as n, listDeferredToolNames as o, formatToolSearchBridgeArguments as r, normalizeToolSearchBridgeArguments as s, createToolSearchMcpServer as t, shouldEnableResponsesToolSearch as u };
|
|
109
132
|
|
|
110
|
-
//# sourceMappingURL=
|
|
133
|
+
//# sourceMappingURL=mcp-server-DEqHrXFq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server-DEqHrXFq.js","names":["record"],"sources":["../src/lib/tool-search.ts","../src/mcp-server.ts"],"sourcesContent":["export const BRIDGE_TOOL_SEARCH_NAME = \"mcp__tool_search__search\"\nexport const BRIDGE_TOOL_SEARCH_ALIASES = [\n BRIDGE_TOOL_SEARCH_NAME,\n \"tool_search_search\",\n \"mcp__plugin_tool-search_tool_search__search\",\n] as const\nexport const MCP_TOOL_SEARCH_SENTINEL_TYPE = \"copilot_api_tool_search\"\n\nexport const ALWAYS_LOADED_TOOL_NAMES = [\n \"Agent\",\n \"AskUserQuestion\",\n \"Bash\",\n \"Edit\",\n \"EnterPlanMode\",\n \"ExitPlanMode\",\n \"Glob\",\n \"Grep\",\n \"Read\",\n \"Skill\",\n \"TodoWrite\",\n \"ToolSearch\",\n \"WebFetch\",\n \"Write\",\n \"apply_patch\",\n \"bash\",\n \"glob\",\n \"grep\",\n \"plan_exit\",\n \"question\",\n \"read\",\n \"skill\",\n \"task\",\n \"todowrite\",\n \"webfetch\",\n] as const\n\nconst alwaysLoadedToolNameSet = new Set<string>(ALWAYS_LOADED_TOOL_NAMES)\nconst bridgeToolSearchNameSet = new Set<string>(BRIDGE_TOOL_SEARCH_ALIASES)\n\nexport interface ToolSearchToolLike {\n name: string\n description?: string\n input_schema?: Record<string, unknown>\n defer_loading?: boolean\n}\n\nexport interface McpToolSearchSentinel {\n type: typeof MCP_TOOL_SEARCH_SENTINEL_TYPE\n names: Array<string>\n}\n\nexport const isBridgeToolSearchName = (name: string): boolean =>\n bridgeToolSearchNameSet.has(name)\n\nexport const isAlwaysLoadedToolName = (name: string): boolean =>\n alwaysLoadedToolNameSet.has(name)\n\nexport const isDeferredToolName = (name: string): boolean =>\n !isBridgeToolSearchName(name) && !isAlwaysLoadedToolName(name)\n\nexport const supportsResponsesToolSearchModel = (model: string): boolean => {\n const match = /^gpt-(\\d+)(?:\\.(\\d+))?/iu.exec(model)\n if (!match) {\n return false\n }\n\n const major = Number.parseInt(match[1], 10)\n const minor = match[2] ? Number.parseInt(match[2], 10) : 0\n\n return major > 5 || (major === 5 && minor >= 4)\n}\n\nexport const hasBridgeToolSearchTool = (\n tools: Array<ToolSearchToolLike> | undefined,\n): boolean =>\n Array.isArray(tools)\n && tools.some((tool) => isBridgeToolSearchName(tool.name))\n\nexport const resolveBridgeToolSearchName = (\n tools: Array<ToolSearchToolLike> | undefined,\n): string => {\n if (!Array.isArray(tools)) {\n return BRIDGE_TOOL_SEARCH_NAME\n }\n\n return (\n tools.find((tool) => isBridgeToolSearchName(tool.name))?.name\n ?? BRIDGE_TOOL_SEARCH_NAME\n )\n}\n\nexport const hasDeferredToolCandidate = (\n tools: Array<ToolSearchToolLike> | undefined,\n): boolean =>\n Array.isArray(tools) && tools.some((tool) => isDeferredToolName(tool.name))\n\nexport const shouldEnableResponsesToolSearch = (params: {\n model: string\n tools?: Array<ToolSearchToolLike>\n}): boolean =>\n supportsResponsesToolSearchModel(params.model)\n && hasBridgeToolSearchTool(params.tools)\n && hasDeferredToolCandidate(params.tools)\n\nexport const hasDeferredNamespaceTool = (\n tools: Array<unknown> | null | undefined,\n): boolean =>\n Array.isArray(tools)\n && tools.some((tool) => {\n if (!tool || typeof tool !== \"object\") {\n return false\n }\n\n const record = tool as Record<string, unknown>\n if (record.type !== \"namespace\" || typeof record.name !== \"string\") {\n return false\n }\n\n if (!isDeferredToolName(record.name)) {\n return false\n }\n\n const namespaceTools = record.tools\n return (\n Array.isArray(namespaceTools)\n && namespaceTools.some(\n (entry) =>\n entry\n && typeof entry === \"object\"\n && (entry as Record<string, unknown>).defer_loading === true,\n )\n )\n })\n\nexport const listDeferredToolNames = (\n tools: Array<ToolSearchToolLike>,\n): Array<string> => [\n ...new Set(\n tools\n .filter((tool) => isDeferredToolName(tool.name))\n .map((tool) => tool.name),\n ),\n]\n\nconst extractDeferredToolNamesSource = (\n record: Record<string, unknown>,\n): unknown => record.names ?? record.query ?? record.paths\n\nexport const parseDeferredToolNames = (names: unknown): Array<string> => {\n let rawNames: Array<string> = []\n\n if (typeof names === \"string\") {\n rawNames = names.split(\",\")\n } else if (Array.isArray(names)) {\n rawNames = names.flatMap((name) =>\n typeof name === \"string\" ? name.split(\",\") : [],\n )\n }\n\n return [\n ...new Set(\n rawNames.map((name) => name.trim()).filter((name) => name.length > 0),\n ),\n ]\n}\n\nexport const createMcpToolSearchSentinel = (names: unknown): string =>\n JSON.stringify({\n type: MCP_TOOL_SEARCH_SENTINEL_TYPE,\n names: parseDeferredToolNames(names),\n } satisfies McpToolSearchSentinel)\n\nexport const parseMcpToolSearchSentinel = (\n text: string,\n): McpToolSearchSentinel | null => {\n try {\n const parsed: unknown = JSON.parse(text)\n if (!parsed || typeof parsed !== \"object\") {\n return null\n }\n\n const record = parsed as Record<string, unknown>\n if (record.type !== MCP_TOOL_SEARCH_SENTINEL_TYPE) {\n return null\n }\n\n const names = parseDeferredToolNames(extractDeferredToolNamesSource(record))\n if (names.length === 0) {\n return null\n }\n\n return {\n type: MCP_TOOL_SEARCH_SENTINEL_TYPE,\n names,\n }\n } catch {\n return null\n }\n}\n\nexport const normalizeToolSearchBridgeArguments = (\n argumentsValue: Record<string, unknown> | string,\n): Record<string, unknown> => {\n if (typeof argumentsValue !== \"string\") {\n const names = parseDeferredToolNames(\n extractDeferredToolNamesSource(argumentsValue),\n )\n return names.length > 0 ? { names } : {}\n }\n\n try {\n const parsed: unknown = JSON.parse(argumentsValue)\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n const record = parsed as Record<string, unknown>\n const names = parseDeferredToolNames(\n extractDeferredToolNamesSource(record),\n )\n return names.length > 0 ? { names } : {}\n }\n } catch {\n // Treat a raw string as the comma-separated protocol payload.\n }\n\n const names = parseDeferredToolNames(argumentsValue)\n return names.length > 0 ? { names } : {}\n}\n\nexport const formatToolSearchBridgeArguments = (\n argumentsValue: Record<string, unknown> | string,\n): Record<string, unknown> => {\n const normalized = normalizeToolSearchBridgeArguments(argumentsValue)\n const names = normalized.names\n\n if (!Array.isArray(names) || names.length === 0) {\n return {}\n }\n\n return { names: names.join(\",\") }\n}\n\nexport const selectDeferredToolsByNames = (\n names: unknown,\n tools: Array<ToolSearchToolLike>,\n): Array<ToolSearchToolLike> => {\n const requestedNames = parseDeferredToolNames(names)\n if (requestedNames.length === 0) {\n return []\n }\n\n const deferredToolByName = new Map(\n tools\n .filter((tool) => isDeferredToolName(tool.name))\n .map((tool) => [tool.name, tool]),\n )\n\n return requestedNames.flatMap((name) => {\n const tool = deferredToolByName.get(name)\n return tool ? [tool] : []\n })\n}\n\nexport const hasDeferredMcpNamespaceTool = hasDeferredNamespaceTool\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { z } from \"zod\"\n\nimport { createMcpToolSearchSentinel } from \"~/lib/tool-search\"\n\nexport const MCP_TOOL_SEARCH_SERVER_NAME = \"tool_search\"\nexport const MCP_TOOL_SEARCH_SERVER_VERSION = \"1.0.0\"\nexport const MCP_TOOL_SEARCH_TOOL_NAME = \"search\"\n\nexport const createToolSearchMcpServer = (): McpServer => {\n const server = new McpServer({\n name: MCP_TOOL_SEARCH_SERVER_NAME,\n version: MCP_TOOL_SEARCH_SERVER_VERSION,\n })\n\n server.registerTool(\n MCP_TOOL_SEARCH_TOOL_NAME,\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 return server\n}\n"],"mappings":"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"}
|
|
@@ -7,12 +7,14 @@ const ENTERPRISE_PREFIX = process.env.COPILOT_API_ENTERPRISE_URL ? "ent_" : "";
|
|
|
7
7
|
const DEFAULT_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
|
|
8
8
|
const APP_DIR = process.env.COPILOT_API_HOME || DEFAULT_DIR;
|
|
9
9
|
const GITHUB_TOKEN_PATH = path.join(APP_DIR, AUTH_APP, ENTERPRISE_PREFIX + "github_token");
|
|
10
|
+
const CODEX_CREDENTIAL_PATH = path.join(APP_DIR, "codex_credentials.json");
|
|
10
11
|
const CONFIG_PATH = path.join(APP_DIR, "config.json");
|
|
11
12
|
const MODELS_PATH = path.join(APP_DIR, "models.json");
|
|
12
13
|
const TOKENS_DIR = path.join(APP_DIR, "tokens");
|
|
13
14
|
const PATHS = {
|
|
14
15
|
APP_DIR,
|
|
15
16
|
GITHUB_TOKEN_PATH,
|
|
17
|
+
CODEX_CREDENTIAL_PATH,
|
|
16
18
|
CONFIG_PATH,
|
|
17
19
|
MODELS_PATH,
|
|
18
20
|
TOKENS_DIR,
|
|
@@ -44,4 +46,4 @@ async function ensureFile(filePath) {
|
|
|
44
46
|
//#endregion
|
|
45
47
|
export { accountTokenPath as n, ensurePaths as r, PATHS as t };
|
|
46
48
|
|
|
47
|
-
//# sourceMappingURL=paths-
|
|
49
|
+
//# sourceMappingURL=paths-Bpsb62LK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths-Bpsb62LK.js","names":[],"sources":["../src/lib/paths.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\")\nconst MODELS_PATH = path.join(APP_DIR, \"models.json\")\n\n// Multi-account paths\nconst TOKENS_DIR = path.join(APP_DIR, \"tokens\")\nconst ACCOUNTS_REGISTRY_PATH = path.join(APP_DIR, \"accounts-registry.json\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n CODEX_CREDENTIAL_PATH,\n CONFIG_PATH,\n MODELS_PATH,\n TOKENS_DIR,\n ACCOUNTS_REGISTRY_PATH,\n}\n\n/**\n * Get the token file path for a specific account.\n * @param id - The account ID (GitHub login)\n * @returns The absolute path to the account's token file\n */\nexport function accountTokenPath(id: string): string {\n return path.join(TOKENS_DIR, `github_${id}`)\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true })\n await fs.mkdir(PATHS.TOKENS_DIR, { 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"],"mappings":";;;;AAIA,MAAM,WAAW,QAAQ,IAAI,uBAAuB,MAAM,IAAI;AAC9D,MAAM,oBAAoB,QAAQ,IAAI,6BAA6B,SAAS;AAE5E,MAAM,cAAc,KAAK,KAAK,GAAG,SAAS,EAAE,UAAU,SAAS,cAAc;AAC7E,MAAM,UAAU,QAAQ,IAAI,oBAAoB;AAEhD,MAAM,oBAAoB,KAAK,KAC7B,SACA,UACA,oBAAoB,eACrB;AACD,MAAM,wBAAwB,KAAK,KAAK,SAAS,yBAAyB;AAC1E,MAAM,cAAc,KAAK,KAAK,SAAS,cAAc;AACrD,MAAM,cAAc,KAAK,KAAK,SAAS,cAAc;AAGrD,MAAM,aAAa,KAAK,KAAK,SAAS,SAAS;AAG/C,MAAa,QAAQ;CACnB;CACA;CACA;CACA;CACA;CACA;CACA,wBAT6B,KAAK,KAAK,SAAS,yBAShD;CACD;;;;;;AAOD,SAAgB,iBAAiB,IAAoB;CACnD,OAAO,KAAK,KAAK,YAAY,UAAU,KAAK;;AAG9C,eAAsB,cAA6B;CACjD,MAAM,GAAG,MAAM,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;CAClD,MAAM,GAAG,MAAM,KAAK,KAAK,MAAM,SAAS,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;CACvE,MAAM,GAAG,MAAM,MAAM,YAAY,EAAE,WAAW,MAAM,CAAC;CACrD,MAAM,WAAW,MAAM,kBAAkB;CACzC,MAAM,WAAW,MAAM,YAAY;;AAGrC,eAAe,WAAW,UAAiC;CACzD,IAAI;EACF,MAAM,GAAG,OAAO,UAAU,GAAG,UAAU,KAAK;SACtC;EACN,MAAM,GAAG,UAAU,UAAU,GAAG;EAChC,MAAM,GAAG,MAAM,UAAU,IAAM"}
|