@serviceme/devtools-shared 0.4.5

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/dist/index.mjs ADDED
@@ -0,0 +1,1217 @@
1
+ // src/ai/providers.base-url.ts
2
+ var PROVIDER_BASE_URL_PRESETS = {
3
+ "openai-compatible": [],
4
+ "anthropic-compatible": [],
5
+ minimax: [
6
+ { label: "\u56FD\u5185", baseUrl: "https://api.minimaxi.com/anthropic" },
7
+ { label: "\u5168\u7403", baseUrl: "https://api.minimax.io/anthropic" }
8
+ ],
9
+ deepseek: [{ label: "\u5B98\u65B9", baseUrl: "https://api.deepseek.com/v1" }],
10
+ kimi: [
11
+ { label: "\u56FD\u5185", baseUrl: "https://api.moonshot.cn/v1" },
12
+ { label: "\u5168\u7403", baseUrl: "https://api.moonshot.ai/v1" }
13
+ ],
14
+ zhipu: [
15
+ { label: "\u56FD\u5185", baseUrl: "https://open.bigmodel.cn/api/agent" },
16
+ { label: "\u5168\u7403", baseUrl: "https://api.zhipuai.com/v1" }
17
+ ],
18
+ stepfun: [{ label: "\u5B98\u65B9", baseUrl: "https://api.stepfun.com/v1" }],
19
+ siliconflow: [
20
+ { label: "\u56FD\u5185", baseUrl: "https://api.siliconflow.cn/v1" },
21
+ { label: "\u5168\u7403", baseUrl: "https://api.siliconflow.com/v1" }
22
+ ],
23
+ openrouter: [{ label: "\u5B98\u65B9", baseUrl: "https://openrouter.ai/api/v1" }],
24
+ novita: [{ label: "\u5B98\u65B9", baseUrl: "https://api.novita.ai/openai/v1" }],
25
+ agnes: [
26
+ { label: "\u56FD\u5185", baseUrl: "https://api.agnes-ai.cn/v1" },
27
+ { label: "\u5168\u7403", baseUrl: "https://apihub.agnes-ai.com/v1" }
28
+ ],
29
+ "vscode-builtin": []
30
+ };
31
+ function getProviderBaseUrlPresets(type) {
32
+ return PROVIDER_BASE_URL_PRESETS[type] ?? [];
33
+ }
34
+
35
+ // src/ai/providers.cache-control.ts
36
+ var PROVIDER_CACHE_CONTROL_METADATA = {
37
+ "openai-compatible": {},
38
+ "anthropic-compatible": {},
39
+ minimax: {
40
+ supportsCacheControl: true
41
+ // Anthropic-compatible ephemeral cache (P0.1 4-breakpoint)
42
+ },
43
+ deepseek: {
44
+ supportsCacheControl: true
45
+ // OpenAI-compat prompt_cache_key
46
+ },
47
+ kimi: {},
48
+ zhipu: {},
49
+ stepfun: {},
50
+ siliconflow: {},
51
+ openrouter: {},
52
+ novita: {},
53
+ agnes: {
54
+ supportsCacheControl: true
55
+ },
56
+ "vscode-builtin": {}
57
+ };
58
+ function isProviderCacheControlAware(type) {
59
+ return Boolean(PROVIDER_CACHE_CONTROL_METADATA[type]?.supportsCacheControl);
60
+ }
61
+
62
+ // src/ai/providers.metadata.ts
63
+ var MODEL_METADATA = {
64
+ "MiniMax-M3": {
65
+ detail: "Native multimodal frontier coding model (1M context, 512K effective)",
66
+ imageInput: true,
67
+ toolCalling: true,
68
+ pricingUSD: { input: 0.3, output: 1.2, cacheRead: 0.06 },
69
+ pricingCNY: { input: 2.1, output: 8.4, cacheRead: 0.42 },
70
+ priceCategory: "medium",
71
+ thinkingSchema: "thinkingEnabled",
72
+ // Official spec is 1M context, but the >512K input tier is still
73
+ // limited-availability (needs sales access + 2x billing per the
74
+ // pricing-page footnote) and most accounts get a 400 past 512K —
75
+ // see `docs/references/minimax-vscode-main/src/models/registry.ts`.
76
+ // 512K is the safe effective cap for both input and output.
77
+ maxInputTokens: 512e3,
78
+ maxOutputTokens: 512e3
79
+ },
80
+ "MiniMax-M2.7": {
81
+ detail: "Self-iterating coding model (~60 TPS)",
82
+ imageInput: false,
83
+ toolCalling: true,
84
+ pricingUSD: { input: 0.3, output: 1.2, cacheRead: 0.06 },
85
+ pricingCNY: { input: 2.1, output: 8.4, cacheRead: 0.42 },
86
+ priceCategory: "low",
87
+ // Official spec: 204,800 total context, split 131,072 input /
88
+ // 73,728 output (no separate docs split exists beyond this).
89
+ maxInputTokens: 131072,
90
+ maxOutputTokens: 73728
91
+ },
92
+ "MiniMax-M2.7-highspeed": {
93
+ detail: "M2.7 high-speed: same quality, faster (~100 TPS)",
94
+ imageInput: false,
95
+ toolCalling: true,
96
+ pricingUSD: { input: 0.6, output: 2.4, cacheRead: 0.06 },
97
+ pricingCNY: { input: 2.1, output: 8.4, cacheRead: 0.42 },
98
+ priceCategory: "low",
99
+ // Inherits M2.7's context window.
100
+ maxInputTokens: 131072,
101
+ maxOutputTokens: 73728
102
+ },
103
+ "deepseek-v4-flash": {
104
+ detail: "Fast, general-purpose model",
105
+ imageInput: true,
106
+ toolCalling: true,
107
+ pricingUSD: { input: 0.14, output: 0.28, cacheRead: 28e-4 },
108
+ pricingCNY: { input: 1, output: 2, cacheRead: 0.02 },
109
+ priceCategory: "low",
110
+ // Official docs (api-docs.deepseek.com/quick_start/pricing, fetched
111
+ // 2026-07-27): "THINKING MODE: Supports both non-thinking and
112
+ // thinking (default) modes" — a binary on/off switch, not a
113
+ // leveled effort scale. Tool Calls confirmed supported for both
114
+ // flash and pro. Was mis-set to reasoningEffort — corrected.
115
+ thinkingSchema: "thinkingEnabled",
116
+ // V4 context window per `docs/references/deepseek-v4-for-copilot-main/src/consts.ts`.
117
+ maxInputTokens: 655360,
118
+ maxOutputTokens: 393216
119
+ },
120
+ "deepseek-v4-pro": {
121
+ detail: "Most capable reasoning model",
122
+ imageInput: true,
123
+ toolCalling: true,
124
+ pricingUSD: { input: 0.435, output: 0.87, cacheRead: 3625e-6 },
125
+ pricingCNY: { input: 2.1, output: 4.2, cacheRead: 0.025 },
126
+ priceCategory: "low",
127
+ thinkingSchema: "thinkingEnabled",
128
+ maxInputTokens: 655360,
129
+ maxOutputTokens: 393216
130
+ },
131
+ "agnes-2.0-flash": {
132
+ detail: "Fast agentic model \u2014 tool calling, coding, image understanding (512K context)",
133
+ imageInput: true,
134
+ toolCalling: true,
135
+ // Standard (post-promo) pricing per Sapiens AI's docs
136
+ // (https://wiki.agnes-ai.com — $0.03 / $0.15 per 1M tokens).
137
+ // The docs also list a temporary $0 / $0 promotional rate;
138
+ // we curate the standard rate here since a promo is
139
+ // time-limited and would silently go stale in this table.
140
+ // No separate CNY tier is published, so pricingCNY mirrors
141
+ // the USD numbers rather than inventing a discount.
142
+ pricingUSD: { input: 0.03, output: 0.15, cacheRead: null },
143
+ pricingCNY: { input: 0.03, output: 0.15, cacheRead: null },
144
+ priceCategory: "low",
145
+ // Binary Thinking on/off, same `thinkingEnabled` schema as
146
+ // MiniMax M3 — but translated differently on the wire: Agnes
147
+ // ships only the OpenAI-compatible shape, so
148
+ // `OpenAIAdapter.chat()` maps `thinkingEnabled` to
149
+ // `chat_template_kwargs.enable_thinking` (per Sapiens AI's
150
+ // docs) rather than AnthropicAdapter's `thinking.type` field.
151
+ thinkingSchema: "thinkingEnabled",
152
+ maxInputTokens: 512e3,
153
+ maxOutputTokens: 65536
154
+ },
155
+ "agnes-2.5-pro-alpha": {
156
+ detail: "Agnes 2.5 Pro Alpha \u2014 \u4ED8\u8D39\u63A8\u7406\u6A21\u578B\uFF08\u9AD8\u7EA7\u7F16\u7801\u3001\u79D1\u5B66\u63A8\u7406\u3001\u957F\u4E0A\u4E0B\u6587\u3001\u591A\u6A21\u6001\uFF09\u30021M \u4E0A\u4E0B\u6587 / 65K \u6700\u5927\u8F93\u51FA\u3002",
157
+ imageInput: true,
158
+ toolCalling: true,
159
+ // 官方价格:$0.45 input / $0.0038 cache read / $0.90 output per 1M tokens
160
+ pricingUSD: { input: 0.45, output: 0.9, cacheRead: 38e-4 },
161
+ pricingCNY: { input: 0.45, output: 0.9, cacheRead: 38e-4 },
162
+ priceCategory: "medium",
163
+ thinkingSchema: "thinkingEnabled",
164
+ // 上下文窗口 1M = maxInput 1M - maxOutput 65K = 934,976
165
+ maxInputTokens: 934976,
166
+ maxOutputTokens: 65536
167
+ },
168
+ // ── Kimi (月之暗面 / Moonshot AI) ────────────────────────────────
169
+ // Source: https://platform.kimi.com/docs/pricing/chat-k3,
170
+ // chat-k27-code, chat-k26 (fetched 2026-07-27). Prices are per 1M
171
+ // tokens; context window is the combined input+output budget the
172
+ // docs publish for the model (not two independent maxima), so the
173
+ // input/output split below sums to that published number.
174
+ // Capability audit (fetched 2026-07-27, platform.kimi.com/docs/guide/
175
+ // use-kimi-api-to-complete-tool-calls, use-reasoning-effort,
176
+ // use-thinking-models): all four models support `tools` (confirmed
177
+ // via the tool-calls guide's worked example using kimi-k3, and the
178
+ // "配置多步工具调用" section explicitly naming kimi-k2.7-code /
179
+ // kimi-k2.6). Thinking config differs per model:
180
+ // - k3: always reasoning, leveled via top-level `reasoning_effort`
181
+ // (low/high/max) -> thinkingSchema: reasoningEffort.
182
+ // - k2.7-code(-highspeed): thinking is ALWAYS on, `thinking.type`
183
+ // only accepts "enabled" (passing "disabled" errors) -- no user
184
+ // control, so no dropdown is shown (thinkingSchema omitted).
185
+ // - k2.6: thinking is a binary toggle via `thinking.type`
186
+ // ("enabled" default / "disabled") -> thinkingSchema: thinkingEnabled
187
+ // (not reasoningEffort -- k2.6 has no effort levels).
188
+ "kimi-k3": {
189
+ detail: "2.8\u4E07\u4EBF\u53C2\u6570\u65D7\u8230\u5F00\u6E90\u6A21\u578B\uFF0C1M \u4E0A\u4E0B\u6587",
190
+ imageInput: true,
191
+ toolCalling: true,
192
+ // ¥2 cache hit / ¥20 input (cache miss) / ¥100 output per 1M tokens
193
+ pricingUSD: { input: 2.8, output: 14, cacheRead: 0.28 },
194
+ pricingCNY: { input: 20, output: 100, cacheRead: 2 },
195
+ priceCategory: "high",
196
+ thinkingSchema: "reasoningEffort",
197
+ // Official context window is 1,048,576 tokens total; output
198
+ // capped at 128K (consistent with other flagship models in
199
+ // this table), remainder reserved for input.
200
+ maxInputTokens: 920576,
201
+ maxOutputTokens: 128e3
202
+ },
203
+ "kimi-k2.7-code": {
204
+ detail: "Coding \u4E13\u7528\uFF0C\u652F\u6301\u56FE\u7247+\u89C6\u9891\u8F93\u5165\uFF0C\u5DE5\u5177\u8C03\u7528\uFF0C\u59CB\u7EC8\u5F00\u542F\u601D\u8003",
205
+ imageInput: true,
206
+ toolCalling: true,
207
+ // ¥6.5 input / ¥27 output / ¥1.3 cache hit per 1M tokens
208
+ pricingUSD: { input: 0.91, output: 3.78, cacheRead: 0.182 },
209
+ pricingCNY: { input: 6.5, output: 27, cacheRead: 1.3 },
210
+ priceCategory: "medium",
211
+ // Official context window: 262,144 tokens total.
212
+ maxInputTokens: 229376,
213
+ maxOutputTokens: 32768
214
+ },
215
+ "kimi-k2.7-code-highspeed": {
216
+ detail: "K2.7 Code \u9AD8\u901F\u7248\uFF08\u53CC\u500D\u4EF7\u683C\uFF09\uFF0C\u4E0E K2.7 Code \u540C\u4E00\u6A21\u578B",
217
+ imageInput: true,
218
+ toolCalling: true,
219
+ // ¥13 input / ¥54 output / ¥2.6 cache hit per 1M tokens
220
+ pricingUSD: { input: 1.82, output: 7.57, cacheRead: 0.364 },
221
+ pricingCNY: { input: 13, output: 54, cacheRead: 2.6 },
222
+ priceCategory: "high",
223
+ maxInputTokens: 229376,
224
+ maxOutputTokens: 32768
225
+ },
226
+ "kimi-k2.6": {
227
+ detail: "K2.6 \u2014 \u652F\u6301\u56FE\u7247+\u89C6\u9891\u3001\u5DE5\u5177\u8C03\u7528\uFF0C\u601D\u8003\u53EF\u5F00\u5173",
228
+ imageInput: true,
229
+ toolCalling: true,
230
+ // ¥6.5 input / ¥27 output / ¥1.1 cache hit per 1M tokens
231
+ pricingUSD: { input: 0.91, output: 3.78, cacheRead: 0.154 },
232
+ pricingCNY: { input: 6.5, output: 27, cacheRead: 1.1 },
233
+ priceCategory: "medium",
234
+ thinkingSchema: "thinkingEnabled",
235
+ maxInputTokens: 229376,
236
+ maxOutputTokens: 32768
237
+ },
238
+ // ── Zhipu / 智谱 AI (GLM) ────────────────────────────────────────
239
+ // Source: https://docs.bigmodel.cn/cn/guide/start/model-overview
240
+ // (context windows) + https://open.bigmodel.cn/pricing (fetched
241
+ // 2026-07-27). Several GLM-5.x models publish tiered pricing by
242
+ // input length ([0,32K) vs [32K+)); we curate the higher/[32K+)
243
+ // tier here since our schema has no tiering — the ProvidersTab
244
+ // user can still override per-provider.
245
+ // toolCalling for GLM-5.x: docs.bigmodel.cn's model overview describes
246
+ // GLM-5.2 as "从代码生成走向工程交付" (engineering delivery, not just
247
+ // code gen), GLM-5.1 as "可自主工作长达 8 小时" (autonomous 8h work),
248
+ // and GLM-5-Turbo as "复杂长任务执行连续性好" (sustained complex-task
249
+ // execution) — all imply agentic tool use consistent with sibling
250
+ // GLM-5's explicit "Agentic 长程规划与执行" description. Corrected
251
+ // from false (inconsistent with the rest of the GLM-5 family).
252
+ "glm-5.2": {
253
+ detail: "GLM-5.2 \u2014 1M \u4E0A\u4E0B\u6587\uFF0C\u6700\u5927\u8F93\u51FA 128K",
254
+ imageInput: false,
255
+ toolCalling: true,
256
+ // ¥8 input / ¥28 output / ¥2 cache hit per 1M tokens (输入长度 32K+ 档)
257
+ pricingUSD: { input: 1.12, output: 3.92, cacheRead: 0.28 },
258
+ pricingCNY: { input: 8, output: 28, cacheRead: 2 },
259
+ priceCategory: "high",
260
+ maxInputTokens: 1e6,
261
+ maxOutputTokens: 128e3
262
+ },
263
+ "glm-4.7": {
264
+ detail: "200K \u4E0A\u4E0B\u6587\uFF0C\u5DE5\u5177\u8C03\u7528",
265
+ imageInput: false,
266
+ toolCalling: true,
267
+ // cc-switch 标价:$0.6 input / $2.2 output
268
+ pricingUSD: { input: 0.6, output: 2.2, cacheRead: 0.11 },
269
+ pricingCNY: { input: 4.3, output: 15.7, cacheRead: 0.79 },
270
+ priceCategory: "medium",
271
+ maxInputTokens: 2e5,
272
+ maxOutputTokens: 128e3
273
+ },
274
+ "glm-5.1": {
275
+ detail: "GLM-5.1 \u2014 200K \u4E0A\u4E0B\u6587\uFF0C\u6700\u5927\u8F93\u51FA 128K",
276
+ imageInput: false,
277
+ toolCalling: true,
278
+ // ¥8 input / ¥28 output / ¥2 cache hit per 1M tokens (输入长度 32K+ 档)
279
+ pricingUSD: { input: 1.12, output: 3.92, cacheRead: 0.28 },
280
+ pricingCNY: { input: 8, output: 28, cacheRead: 2 },
281
+ priceCategory: "high",
282
+ maxInputTokens: 2e5,
283
+ maxOutputTokens: 128e3
284
+ },
285
+ "glm-5": {
286
+ detail: "GLM-5 \u2014 200K \u4E0A\u4E0B\u6587\uFF0CAgentic \u5DE5\u5177\u8C03\u7528\uFF0C\u6700\u5927\u8F93\u51FA 128K",
287
+ imageInput: false,
288
+ toolCalling: true,
289
+ // ¥6 input / ¥22 output / ¥1.5 cache hit per 1M tokens (输入长度 32K+ 档)
290
+ pricingUSD: { input: 0.84, output: 3.08, cacheRead: 0.21 },
291
+ pricingCNY: { input: 6, output: 22, cacheRead: 1.5 },
292
+ priceCategory: "high",
293
+ maxInputTokens: 2e5,
294
+ maxOutputTokens: 128e3
295
+ },
296
+ "glm-5-turbo": {
297
+ detail: "GLM-5 Turbo \u2014 200K \u4E0A\u4E0B\u6587\uFF0C\u6700\u5927\u8F93\u51FA 128K",
298
+ imageInput: false,
299
+ toolCalling: true,
300
+ // ¥7 input / ¥26 output / ¥1.8 cache hit per 1M tokens (输入长度 32K+ 档)
301
+ pricingUSD: { input: 0.98, output: 3.64, cacheRead: 0.252 },
302
+ pricingCNY: { input: 7, output: 26, cacheRead: 1.8 },
303
+ priceCategory: "medium",
304
+ maxInputTokens: 2e5,
305
+ maxOutputTokens: 128e3
306
+ },
307
+ "glm-4.7-flashx": {
308
+ detail: "GLM-4.7 FlashX \u2014 \u5FEB\u901F\u7248",
309
+ imageInput: false,
310
+ toolCalling: false,
311
+ // ¥0.5 input / ¥3 output / ¥0.1 cache hit per 1M tokens
312
+ pricingUSD: { input: 0.07, output: 0.42, cacheRead: 0.014 },
313
+ pricingCNY: { input: 0.5, output: 3, cacheRead: 0.1 },
314
+ priceCategory: "low",
315
+ maxInputTokens: 2e5,
316
+ maxOutputTokens: 128e3
317
+ },
318
+ "glm-4.6": {
319
+ detail: "GLM-4.6 \u2014 \u5DE5\u5177\u8C03\u7528",
320
+ imageInput: false,
321
+ toolCalling: true,
322
+ pricingUSD: { input: 0.6, output: 2.2, cacheRead: 0.11 },
323
+ pricingCNY: { input: 4.3, output: 15.7, cacheRead: 0.79 },
324
+ priceCategory: "medium",
325
+ maxInputTokens: 2e5,
326
+ maxOutputTokens: 128e3
327
+ },
328
+ "glm-4.5-air": {
329
+ detail: "GLM-4.5 Air \u2014 \u5DE5\u5177\u8C03\u7528",
330
+ imageInput: false,
331
+ toolCalling: true,
332
+ pricingUSD: { input: 0, output: 0, cacheRead: null },
333
+ pricingCNY: { input: 0, output: 0, cacheRead: null },
334
+ priceCategory: "low",
335
+ maxInputTokens: 128e3,
336
+ maxOutputTokens: 96e3
337
+ },
338
+ "glm-4.5-airx": {
339
+ detail: "GLM-4.5 AirX \u2014 \u5FEB\u901F\u7248",
340
+ imageInput: false,
341
+ toolCalling: false,
342
+ pricingUSD: { input: 0, output: 0, cacheRead: null },
343
+ pricingCNY: { input: 0, output: 0, cacheRead: null },
344
+ priceCategory: "low",
345
+ maxInputTokens: 128e3,
346
+ maxOutputTokens: 96e3
347
+ },
348
+ "glm-4-long": {
349
+ detail: "GLM-4 Long \u2014 1M \u4E0A\u4E0B\u6587\uFF0C\u957F\u6587\u6863\u5904\u7406",
350
+ imageInput: false,
351
+ toolCalling: false,
352
+ // ¥1 / M tokens (single rate, input == output per 官方定价页)
353
+ pricingUSD: { input: 0.14, output: 0.14, cacheRead: null },
354
+ pricingCNY: { input: 1, output: 1, cacheRead: null },
355
+ priceCategory: "low",
356
+ maxInputTokens: 1e6,
357
+ maxOutputTokens: 4e3
358
+ },
359
+ "glm-4-flashx": {
360
+ detail: "GLM-4 FlashX \u2014 \u5FEB\u901F\u7248",
361
+ imageInput: false,
362
+ toolCalling: false,
363
+ // ¥0.1 / M tokens (single rate, input == output per 官方定价页)
364
+ pricingUSD: { input: 0.014, output: 0.014, cacheRead: null },
365
+ pricingCNY: { input: 0.1, output: 0.1, cacheRead: null },
366
+ priceCategory: "low",
367
+ maxInputTokens: 128e3,
368
+ maxOutputTokens: 16e3
369
+ },
370
+ "glm-4-plus": {
371
+ detail: "GLM-4 Plus \u2014 Function Call \u652F\u6301",
372
+ imageInput: false,
373
+ toolCalling: true,
374
+ // ¥5 input per 1M tokens
375
+ pricingUSD: { input: 0.7, output: 0.7, cacheRead: null },
376
+ pricingCNY: { input: 5, output: 5, cacheRead: null },
377
+ priceCategory: "low",
378
+ maxInputTokens: 128e3,
379
+ maxOutputTokens: 4e3
380
+ },
381
+ "glm-4.5v": {
382
+ detail: "GLM-4.5V \u89C6\u89C9\u63A8\u7406\u6A21\u578B \u2014 \u56FE\u50CF/\u89C6\u9891/\u6587\u6863/GUI",
383
+ imageInput: true,
384
+ toolCalling: true,
385
+ pricingUSD: { input: 0, output: 0, cacheRead: null },
386
+ pricingCNY: { input: 0, output: 0, cacheRead: null },
387
+ priceCategory: "medium",
388
+ maxInputTokens: 128e3,
389
+ maxOutputTokens: 8192
390
+ },
391
+ "glm-5v-turbo": {
392
+ detail: "GLM-5V Turbo \u2014 \u591A\u6A21\u6001 Coding \u6A21\u578B",
393
+ imageInput: true,
394
+ toolCalling: true,
395
+ pricingUSD: { input: 0, output: 0, cacheRead: null },
396
+ pricingCNY: { input: 0, output: 0, cacheRead: null },
397
+ priceCategory: "medium",
398
+ // Official model overview: 200K context / 128K max output
399
+ // (previously mis-set to 128K/8_192 — corrected 2026-07-27).
400
+ maxInputTokens: 2e5,
401
+ maxOutputTokens: 128e3
402
+ },
403
+ "glm-3-turbo": {
404
+ detail: "GLM-3 Turbo \u2014 \u5165\u95E8\u7EA7\uFF08\xA51/1M tokens\uFF09",
405
+ imageInput: false,
406
+ toolCalling: false,
407
+ pricingUSD: { input: 0.14, output: 0.14, cacheRead: null },
408
+ pricingCNY: { input: 1, output: 1, cacheRead: null },
409
+ priceCategory: "low",
410
+ maxInputTokens: 128e3,
411
+ maxOutputTokens: 8192
412
+ },
413
+ // ── StepFun / 阶跃星辰 ───────────────────────────────────────────
414
+ // Source: https://platform.stepfun.com/docs/zh/guides/models/
415
+ // step-3.7-flash, step-3.5-flash + guides/models (overview page,
416
+ // fetched 2026-07-27). Both flash models publish "256K tokens" as
417
+ // a single combined context number; the exact input/output split
418
+ // below matches Novita's real-world deployment of step-3.7-flash
419
+ // (262,144 total / 256,000 max output) since StepFun's own docs
420
+ // don't split it further.
421
+ "step-3.7-flash": {
422
+ detail: "Step 3.7 Flash \u2014 \u591A\u6A21\u6001\u63A8\u7406\u6A21\u578B\uFF08198B/11B MoE\uFF09",
423
+ imageInput: true,
424
+ // Official model page lists "🛠️ 工具调用: 可靠的工具调用能力,支持多步
425
+ // 任务分解与计划执行" as a core capability — was mis-set to false.
426
+ toolCalling: true,
427
+ // ¥1.35 input / ¥8.1 output / ¥0.27 cache hit per 1M tokens
428
+ pricingUSD: { input: 0.189, output: 1.134, cacheRead: 0.038 },
429
+ pricingCNY: { input: 1.35, output: 8.1, cacheRead: 0.27 },
430
+ priceCategory: "medium",
431
+ thinkingSchema: "reasoningEffort",
432
+ // Was 0 (a bug — VSCode's chat picker hides entries whose
433
+ // maxInputTokens is 0). Corrected to the official 256K context
434
+ // window (262,144 tokens) minus the published 256,000 max output.
435
+ maxInputTokens: 262144,
436
+ maxOutputTokens: 256e3
437
+ },
438
+ "step-3.5-flash": {
439
+ detail: "Step 3.5 Flash \u2014 \u63A8\u7406\u6A21\u578B",
440
+ imageInput: false,
441
+ // Official model page lists "🛠️ 工具调用: 可靠的 tools / tool_choice
442
+ // 调用能力" as a core capability — was mis-set to false.
443
+ toolCalling: true,
444
+ // ¥0.7 input / ¥2.1 output / ¥0.14 cache hit per 1M tokens
445
+ pricingUSD: { input: 0.098, output: 0.294, cacheRead: 0.02 },
446
+ pricingCNY: { input: 0.7, output: 2.1, cacheRead: 0.14 },
447
+ priceCategory: "low",
448
+ thinkingSchema: "reasoningEffort",
449
+ maxInputTokens: 256e3,
450
+ maxOutputTokens: 256e3
451
+ },
452
+ "step-1o-turbo-vision": {
453
+ detail: "Step 1o Turbo Vision \u2014 \u89C6\u89C9\u6A21\u578B",
454
+ imageInput: true,
455
+ toolCalling: false,
456
+ // ¥2.5 input / ¥8 output per 1M tokens
457
+ pricingUSD: { input: 0.35, output: 1.12, cacheRead: null },
458
+ pricingCNY: { input: 2.5, output: 8, cacheRead: null },
459
+ priceCategory: "low",
460
+ // Official model overview: 32K context window.
461
+ maxInputTokens: 32768,
462
+ maxOutputTokens: 32768
463
+ },
464
+ // ── 聚合平台占位 ────────────────────────────────────────────────────
465
+ // 这些平台是 model aggregator — 模型列表由平台动态维护。
466
+ // 当 `provider.baseUrl` 与对应平台匹配时(即 OpenRouter / Novita),
467
+ // 用户可通过 `Fetch from API` 从 `/v1/models` 拉取真实列表;
468
+ // 下面这些 metadata 条目只是为了支持 `BUILTIN_PROVIDER_PRESETS` 中的预设。
469
+ "openrouter/auto": {
470
+ detail: "OpenRouter Auto \u2014 \u81EA\u52A8\u8DEF\u7531\u5230\u5E73\u53F0\u6700\u4F73\u6A21\u578B",
471
+ imageInput: true,
472
+ toolCalling: true,
473
+ // OpenRouter 透传上游价格,自身不标价。占位 0 由用户在 provider form 调整。
474
+ pricingUSD: { input: 0, output: 0, cacheRead: null },
475
+ pricingCNY: { input: 0, output: 0, cacheRead: null },
476
+ priceCategory: "medium",
477
+ maxInputTokens: 0,
478
+ maxOutputTokens: 0
479
+ },
480
+ "novita-ai/novita-3.5-flash": {
481
+ detail: "Novita 3.5 Flash \u2014 Novita \u5E73\u53F0\u70ED\u95E8\u6A21\u578B\uFF08\u5360\u4F4D\uFF0C\u6309\u5B9E\u9645\u9009\u62E9\u8C03\u6574\uFF09",
482
+ imageInput: true,
483
+ toolCalling: true,
484
+ pricingUSD: { input: 0.1, output: 0.4, cacheRead: null },
485
+ pricingCNY: { input: 0.1, output: 0.4, cacheRead: null },
486
+ priceCategory: "low",
487
+ maxInputTokens: 32768,
488
+ maxOutputTokens: 32768
489
+ }
490
+ };
491
+ function lookupModelMetadata(modelId) {
492
+ return MODEL_METADATA[modelId];
493
+ }
494
+ function currencyForBaseUrl(baseUrl) {
495
+ try {
496
+ const hostname = new URL(baseUrl).hostname.toLowerCase();
497
+ if (hostname === "api.minimaxi.com" || hostname === "api.minimaxi.cn" || hostname === "api.deepseek.com" || hostname === "api.moonshot.cn" || hostname === "open.bigmodel.cn") {
498
+ return "CNY";
499
+ }
500
+ if (hostname === "api.minimax.io" || hostname === "api.minimaxi.io" || hostname === "api.siliconflow.cn" || hostname === "api.siliconflow.com" || hostname === "api.stepfun.com" || hostname === "openrouter.ai" || hostname === "api.novita.ai") {
501
+ return "USD";
502
+ }
503
+ } catch {
504
+ }
505
+ return "USD";
506
+ }
507
+
508
+ // src/ai/providers.presets.ts
509
+ function buildPresetModel(id, displayName) {
510
+ const meta = MODEL_METADATA[id];
511
+ if (!meta) {
512
+ throw new Error(
513
+ `buildPresetModel: no curated MODEL_METADATA entry for '${id}' \u2014 add one before referencing it from BUILTIN_PROVIDER_PRESETS.`
514
+ );
515
+ }
516
+ return {
517
+ id,
518
+ displayName,
519
+ maxInputTokens: meta.maxInputTokens,
520
+ maxOutputTokens: meta.maxOutputTokens,
521
+ detail: meta.detail,
522
+ capabilities: {
523
+ supportsImageToText: meta.imageInput,
524
+ supportsToolCalling: meta.toolCalling
525
+ },
526
+ pricing: meta.pricingUSD,
527
+ priceCategory: meta.priceCategory,
528
+ thinkingSchema: meta.thinkingSchema ?? "none"
529
+ };
530
+ }
531
+ var BUILTIN_PROVIDER_PRESETS = {
532
+ minimax: {
533
+ displayName: "MiniMax",
534
+ baseUrl: "https://api.minimaxi.com/anthropic",
535
+ // Token limits (see the `MODEL_METADATA` entries above) are
536
+ // aligned with the upstream `minimax-vscode-main` reference
537
+ // (`docs/references/minimax-vscode-main/src/models/registry.ts`),
538
+ // which scrapes the official model cards:
539
+ // - M3: official spec is 1M context, but the >512K input tier
540
+ // is still limited-availability (needs sales access + 2x
541
+ // billing per the pricing-page footnote) and most accounts
542
+ // get a 400 past 512K. We report the safe 512K effective cap
543
+ // for both input and output so VSCode's "上下文窗口" indicator
544
+ // matches what a normal account can actually push.
545
+ // - M2.7 / M2.7-highspeed: official spec is 204,800 total
546
+ // context, split 131,072 input / 73,728 output (no separate
547
+ // docs split exists beyond this; do not invent a different
548
+ // one).
549
+ // `maxInputTokens` / `maxOutputTokens` are forwarded to
550
+ // `vscode.lm.registerLanguageModelChatProvider` — VSCode's chat
551
+ // model picker hides / disables entries whose `maxInputTokens`
552
+ // is 0, so every curated entry must carry an explicit number
553
+ // (otherwise the user's added model never shows up in the
554
+ // Copilot Chat picker).
555
+ models: [
556
+ buildPresetModel("MiniMax-M3", "MiniMax-M3"),
557
+ buildPresetModel("MiniMax-M2.7", "MiniMax-M2.7"),
558
+ buildPresetModel("MiniMax-M2.7-highspeed", "MiniMax-M2.7-highspeed")
559
+ ]
560
+ },
561
+ deepseek: {
562
+ displayName: "DeepSeek",
563
+ // DeepSeek v4 ships only the OpenAI-compatible endpoint (no
564
+ // Anthropic-compatible surface). The /v1 suffix is intentional
565
+ // — it matches the public docs (https://api.deepseek.com/v1)
566
+ // and is the path the OpenAI client uses to build
567
+ // `/v1/chat/completions`. The reference implementation
568
+ // (`docs/references/deepseek-v4-for-copilot-main`) uses
569
+ // `https://api.deepseek.com` and appends `/chat/completions`
570
+ // (no /v1), which is technically a different host layout — we
571
+ // prefer the explicit /v1 here so the user can verify the path
572
+ // in their browser without ambiguity.
573
+ baseUrl: "https://api.deepseek.com/v1",
574
+ // V4 context window: 655,360 input / 393,216 output per
575
+ // `docs/references/deepseek-v4-for-copilot-main/src/consts.ts`.
576
+ // V3 (deepseek-chat / deepseek-reasoner, 64K) is no longer
577
+ // the recommended default — users still on V3 can override
578
+ // these defaults in the ProvidersTab form.
579
+ models: [
580
+ buildPresetModel("deepseek-v4-flash", "DeepSeek V4 Flash"),
581
+ buildPresetModel("deepseek-v4-pro", "DeepSeek V4 Pro")
582
+ ]
583
+ },
584
+ agnes: {
585
+ displayName: "Agnes",
586
+ // Sapiens AI's Agnes — OpenAI-compatible endpoint per
587
+ // https://wiki.agnes-ai.com (`POST /v1/chat/completions`).
588
+ baseUrl: "https://apihub.agnes-ai.com/v1",
589
+ models: [
590
+ buildPresetModel("agnes-2.5-pro-alpha", "Agnes 2.5 Pro Alpha"),
591
+ buildPresetModel("agnes-2.0-flash", "Agnes 2.0 Flash")
592
+ ]
593
+ },
594
+ kimi: {
595
+ displayName: "Kimi",
596
+ baseUrl: "https://api.moonshot.cn/v1",
597
+ models: [
598
+ buildPresetModel("kimi-k3", "Kimi K3"),
599
+ buildPresetModel("kimi-k2.7-code", "Kimi K2.7 Code"),
600
+ buildPresetModel("kimi-k2.7-code-highspeed", "Kimi K2.7 Code HighSpeed"),
601
+ buildPresetModel("kimi-k2.6", "Kimi K2.6")
602
+ ]
603
+ },
604
+ zhipu: {
605
+ displayName: "Zhipu",
606
+ baseUrl: "https://open.bigmodel.cn/api/paas/v4",
607
+ // Every id below has a curated `MODEL_METADATA` entry (see above) —
608
+ // keep this list in sync with that table. It previously only
609
+ // listed the GLM-4.x models, so newer flagship releases (GLM-5.2 /
610
+ // 5.1 / 5 / 5-Turbo / 5V-Turbo) never appeared in the ProvidersTab
611
+ // "add provider" preset even though their metadata existed.
612
+ models: [
613
+ buildPresetModel("glm-5.2", "GLM-5.2"),
614
+ buildPresetModel("glm-5.1", "GLM-5.1"),
615
+ buildPresetModel("glm-5", "GLM-5"),
616
+ buildPresetModel("glm-5-turbo", "GLM-5 Turbo"),
617
+ buildPresetModel("glm-5v-turbo", "GLM-5V Turbo"),
618
+ buildPresetModel("glm-4.7", "GLM-4.7"),
619
+ buildPresetModel("glm-4.7-flashx", "GLM-4.7 FlashX"),
620
+ buildPresetModel("glm-4.6", "GLM-4.6"),
621
+ buildPresetModel("glm-4.5v", "GLM-4.5V"),
622
+ buildPresetModel("glm-4.5-air", "GLM-4.5 Air"),
623
+ buildPresetModel("glm-4.5-airx", "GLM-4.5 AirX"),
624
+ buildPresetModel("glm-4-plus", "GLM-4 Plus"),
625
+ buildPresetModel("glm-4-long", "GLM-4 Long"),
626
+ buildPresetModel("glm-4-flashx", "GLM-4 FlashX"),
627
+ buildPresetModel("glm-3-turbo", "GLM-3 Turbo")
628
+ ]
629
+ },
630
+ stepfun: {
631
+ displayName: "StepFun",
632
+ baseUrl: "https://api.stepfun.com/v1",
633
+ models: [
634
+ buildPresetModel("step-3.7-flash", "Step 3.7 Flash"),
635
+ buildPresetModel("step-3.5-flash", "Step 3.5 Flash"),
636
+ buildPresetModel("step-1o-turbo-vision", "Step 1o Turbo Vision")
637
+ ]
638
+ },
639
+ siliconflow: {
640
+ displayName: "SiliconFlow",
641
+ baseUrl: "https://api.siliconflow.cn/v1",
642
+ // 聚合平台:模型列表动态,用户添加后通过 /v1/models 拉取。
643
+ // 占位 0 容量模型避免 picker 显示空。
644
+ models: []
645
+ },
646
+ openrouter: {
647
+ displayName: "OpenRouter",
648
+ baseUrl: "https://openrouter.ai/api/v1",
649
+ models: [buildPresetModel("openrouter/auto", "OpenRouter Auto")]
650
+ },
651
+ novita: {
652
+ displayName: "Novita",
653
+ baseUrl: "https://api.novita.ai/openai/v1",
654
+ // 聚合平台:Novita 本身不产出自有模型,只是把 Kimi K3 / GLM 5.2 /
655
+ // DeepSeek V4 / MiniMax M3 / Step 3.7 Flash 等第三方开源或授权模型
656
+ // 挂到统一 OpenAI 兼容网关下(见 https://novita.ai/llm-api)。此前
657
+ // 占位的 "novita-ai/novita-3.5-flash" 在其模型列表中查无此模型 id,
658
+ // 已移除。用户添加 provider 后通过 /v1/models 拉取真实列表。
659
+ models: []
660
+ }
661
+ };
662
+ function getBuiltinProviderPreset(type) {
663
+ switch (type) {
664
+ case "minimax":
665
+ case "deepseek":
666
+ case "agnes":
667
+ case "kimi":
668
+ case "zhipu":
669
+ case "stepfun":
670
+ case "siliconflow":
671
+ case "openrouter":
672
+ case "novita":
673
+ return BUILTIN_PROVIDER_PRESETS[type];
674
+ default:
675
+ return null;
676
+ }
677
+ }
678
+
679
+ // src/certificate-bundle.ts
680
+ var CERTIFICATE_BUNDLE_FORMATS = [
681
+ {
682
+ format: "pem",
683
+ label: "Nginx / Generic PEM",
684
+ description: "cert.pem + key.pem + fullchain.pem (Nginx, HAProxy, most Unix servers).",
685
+ icon: "file-lock-2",
686
+ requiresPassword: false,
687
+ artifactExtension: ".pem"
688
+ },
689
+ {
690
+ format: "pfx",
691
+ label: "IIS / Tomcat PFX",
692
+ description: "PKCS#12 bundle (.pfx) for Windows IIS, Tomcat, ColdFusion. Requires a password.",
693
+ icon: "shield",
694
+ requiresPassword: true,
695
+ artifactExtension: ".pfx"
696
+ },
697
+ {
698
+ format: "crt",
699
+ label: "Apache CRT",
700
+ description: "Separate .crt + .key for Apache httpd and other Unix servers that prefer DER/PEM split.",
701
+ icon: "file-badge",
702
+ requiresPassword: false,
703
+ artifactExtension: ".crt"
704
+ },
705
+ {
706
+ format: "jks",
707
+ label: "Java JKS",
708
+ description: "Java KeyStore (.jks) for Tomcat and Java applications. Requires a JDK with `keytool` on PATH.",
709
+ icon: "coffee",
710
+ requiresPassword: true,
711
+ artifactExtension: ".jks"
712
+ }
713
+ ];
714
+
715
+ // src/git-utils.ts
716
+ var GIT_REMOTE_HOST_ALIASES = {
717
+ "github-msc": "github.com"
718
+ };
719
+ function normalizeGitRemoteHost(host) {
720
+ const normalizedHost = host.trim().toLowerCase();
721
+ return GIT_REMOTE_HOST_ALIASES[normalizedHost] ?? normalizedHost;
722
+ }
723
+ function normalizeCanonicalSlug(slug) {
724
+ const trimmedSlug = slug.trim().toLowerCase();
725
+ const firstSlashIndex = trimmedSlug.indexOf("/");
726
+ if (firstSlashIndex <= 0) {
727
+ return trimmedSlug;
728
+ }
729
+ const host = trimmedSlug.slice(0, firstSlashIndex);
730
+ const path = trimmedSlug.slice(firstSlashIndex + 1);
731
+ return `${normalizeGitRemoteHost(host)}/${path}`;
732
+ }
733
+ function normalizeGitUrl(input) {
734
+ const trimmed = input.trim();
735
+ const scpMatch = !trimmed.includes("://") && trimmed.match(/^([^@]+)@([^:]+):(.+)$/);
736
+ if (scpMatch) {
737
+ const host = scpMatch[2];
738
+ const path = scpMatch[3];
739
+ return toCanonicalSlug(`ssh://${host}/${path}`);
740
+ }
741
+ try {
742
+ const url = new URL(trimmed);
743
+ const host = normalizeGitRemoteHost(url.hostname);
744
+ let pathname = url.pathname;
745
+ if (pathname.startsWith("/")) pathname = pathname.slice(1);
746
+ if (pathname.endsWith(".git")) pathname = pathname.slice(0, -4);
747
+ const parts = pathname.split("/").filter(Boolean);
748
+ if (parts.length < 2) {
749
+ throw new Error("Invalid Git URL: missing owner/repo path");
750
+ }
751
+ const normalizedPath = parts.map((part) => part.toLowerCase()).join("/");
752
+ return `${host}/${normalizedPath}`;
753
+ } catch {
754
+ if (isValidCanonicalSlug(trimmed)) return normalizeCanonicalSlug(trimmed);
755
+ throw new Error(`Unparseable Git URL: ${input}`);
756
+ }
757
+ }
758
+ function isValidCanonicalSlug(slug) {
759
+ const segment = "(?:[a-zA-Z0-9_.-]|%[0-9A-Fa-f]{2})+";
760
+ const canonicalSlugPattern = new RegExp(`^${segment}(?:\\/${segment}){2,}$`);
761
+ return canonicalSlugPattern.test(slug.trim());
762
+ }
763
+ function toCanonicalSlug(coerced) {
764
+ const url = new URL(coerced);
765
+ const host = normalizeGitRemoteHost(url.hostname);
766
+ let pathname = url.pathname;
767
+ if (pathname.startsWith("/")) pathname = pathname.slice(1);
768
+ if (pathname.endsWith(".git")) pathname = pathname.slice(0, -4);
769
+ const parts = pathname.split("/").filter(Boolean);
770
+ if (parts.length < 2) throw new Error("Invalid Git URL: missing owner/repo path");
771
+ return `${host}/${parts.map((part) => part.toLowerCase()).join("/")}`;
772
+ }
773
+
774
+ // src/github-api.ts
775
+ async function fetchGitHubUser(token) {
776
+ const resp = await fetch("https://api.github.com/user", {
777
+ headers: {
778
+ Authorization: `token ${token}`,
779
+ Accept: "application/vnd.github.v3+json"
780
+ }
781
+ });
782
+ if (resp.ok) {
783
+ const user = await resp.json();
784
+ user.email = await resolveGitHubUserEmail(token, user);
785
+ return user;
786
+ }
787
+ if (resp.status === 401) {
788
+ throw new Error("GitHub API Error: 401 Unauthorized");
789
+ }
790
+ const status = resp.status;
791
+ const statusText = resp.statusText;
792
+ let body = "";
793
+ try {
794
+ body = await resp.text();
795
+ } catch (_e) {
796
+ body = "[Failed to read response body]";
797
+ }
798
+ throw new Error(`GitHub API Error: ${status} ${statusText} - ${body}`);
799
+ }
800
+ async function resolveGitHubUserEmail(token, user) {
801
+ const directEmail = sanitizeEmail(user.email);
802
+ if (directEmail) {
803
+ return directEmail;
804
+ }
805
+ const emails = await fetchGitHubUserEmails(token);
806
+ const preferredEmail = pickPreferredGitHubEmail(emails);
807
+ return preferredEmail ?? directEmail;
808
+ }
809
+ async function fetchGitHubUserEmails(token) {
810
+ const resp = await fetch("https://api.github.com/user/emails", {
811
+ headers: {
812
+ Authorization: `token ${token}`,
813
+ Accept: "application/vnd.github.v3+json"
814
+ }
815
+ });
816
+ if (resp.ok) {
817
+ return await resp.json();
818
+ }
819
+ if (resp.status === 404 || resp.status === 403) {
820
+ return [];
821
+ }
822
+ if (resp.status === 401) {
823
+ throw new Error("GitHub API Error: 401 Unauthorized");
824
+ }
825
+ let body = "";
826
+ try {
827
+ body = await resp.text();
828
+ } catch (_e) {
829
+ body = "[Failed to read response body]";
830
+ }
831
+ throw new Error(`GitHub API Error: ${resp.status} ${resp.statusText} - ${body}`);
832
+ }
833
+ function pickPreferredGitHubEmail(emails) {
834
+ const sanitizedEmails = emails.map((emailRecord) => ({
835
+ ...emailRecord,
836
+ email: sanitizeEmail(emailRecord.email)
837
+ })).filter(
838
+ (emailRecord) => Boolean(emailRecord.email)
839
+ );
840
+ const preferred = sanitizedEmails.find((emailRecord) => emailRecord.primary && emailRecord.verified) ?? sanitizedEmails.find((emailRecord) => emailRecord.verified) ?? sanitizedEmails.find((emailRecord) => emailRecord.primary) ?? sanitizedEmails[0];
841
+ return preferred?.email ?? null;
842
+ }
843
+ function sanitizeEmail(email) {
844
+ if (!email) {
845
+ return null;
846
+ }
847
+ const normalizedEmail = email.trim();
848
+ if (!normalizedEmail) {
849
+ return null;
850
+ }
851
+ return normalizedEmail;
852
+ }
853
+ var __internal = {
854
+ pickPreferredGitHubEmail,
855
+ sanitizeEmail
856
+ };
857
+ function createOrgMembershipResult(organization, status, httpStatus, membership) {
858
+ return {
859
+ status,
860
+ httpStatus,
861
+ organization,
862
+ role: typeof membership?.role === "string" ? membership.role : null,
863
+ directMembership: typeof membership?.direct_membership === "boolean" ? membership.direct_membership : null
864
+ };
865
+ }
866
+ async function getGitHubOrgMembership(token, org) {
867
+ const normalizedOrg = org.trim().toLowerCase();
868
+ const resp = await fetch("https://api.github.com/user/memberships/orgs", {
869
+ headers: {
870
+ Authorization: `token ${token}`,
871
+ Accept: "application/vnd.github+json",
872
+ "X-GitHub-Api-Version": "2022-11-28"
873
+ }
874
+ });
875
+ if (resp.status === 401) {
876
+ return createOrgMembershipResult(org, "unauthorized", resp.status);
877
+ }
878
+ if (resp.status === 403) {
879
+ return createOrgMembershipResult(org, "forbidden", resp.status);
880
+ }
881
+ if (!resp.ok) {
882
+ let body = "";
883
+ try {
884
+ body = await resp.text();
885
+ } catch (_e) {
886
+ body = "[Failed to read response body]";
887
+ }
888
+ throw new Error(`GitHub API Error: ${resp.status} ${resp.statusText} - ${body}`);
889
+ }
890
+ const memberships = await resp.json();
891
+ const membership = memberships.find(
892
+ (entry) => entry.organization?.login?.toLowerCase() === normalizedOrg
893
+ );
894
+ if (!membership) {
895
+ return createOrgMembershipResult(org, "not_member", resp.status);
896
+ }
897
+ if (membership.state === "pending") {
898
+ return createOrgMembershipResult(org, "pending", resp.status, membership);
899
+ }
900
+ if (membership.state === "active") {
901
+ return createOrgMembershipResult(org, "active", resp.status, membership);
902
+ }
903
+ return createOrgMembershipResult(org, "not_member", resp.status, membership);
904
+ }
905
+ async function checkGitHubOrgMembership(token, org) {
906
+ const membership = await getGitHubOrgMembership(token, org);
907
+ if (membership.status === "forbidden" || membership.status === "unauthorized") {
908
+ throw new Error(`GitHub org membership indeterminate: HTTP ${membership.httpStatus}`);
909
+ }
910
+ return membership.status === "active" || membership.status === "pending";
911
+ }
912
+
913
+ // src/github-user-email.ts
914
+ function isGitHubLocalEmail(email) {
915
+ return typeof email === "string" && email.trim().toLowerCase().endsWith("@github.local");
916
+ }
917
+ function buildGitHubLocalEmail(login) {
918
+ return `${login}@github.local`;
919
+ }
920
+ function resolvePrimaryEmail(login, email) {
921
+ const normalizedEmail = email?.trim();
922
+ return normalizedEmail || buildGitHubLocalEmail(login);
923
+ }
924
+
925
+ // src/logger/index.ts
926
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
927
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
928
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
929
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
930
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
931
+ return LogLevel2;
932
+ })(LogLevel || {});
933
+ function normalizeErrorForLog(error) {
934
+ if (error === null || error === void 0) {
935
+ return { kind: "nullish", value: null };
936
+ }
937
+ const t = typeof error;
938
+ if (t === "string") {
939
+ return { kind: "string", message: error };
940
+ }
941
+ if (t === "number" || t === "boolean" || t === "bigint") {
942
+ return { kind: t, value: String(error) };
943
+ }
944
+ if (t === "object") {
945
+ const obj = error;
946
+ if (error instanceof Error) {
947
+ const result2 = {
948
+ kind: "error",
949
+ name: error.name,
950
+ message: error.message,
951
+ stack: error.stack
952
+ };
953
+ if (typeof obj.code === "string") {
954
+ result2.code = obj.code;
955
+ }
956
+ if (typeof obj.retryable === "boolean") {
957
+ result2.retryable = obj.retryable;
958
+ }
959
+ if ("details" in obj) {
960
+ result2.details = obj.details;
961
+ }
962
+ if (typeof obj.cause !== "undefined") {
963
+ result2.cause = normalizeErrorForLog(obj.cause);
964
+ }
965
+ return result2;
966
+ }
967
+ const result = { kind: "object" };
968
+ let captured = 0;
969
+ for (const [k, v] of Object.entries(obj)) {
970
+ result[k] = v;
971
+ captured += 1;
972
+ }
973
+ if (captured === 0) {
974
+ result.message = "(empty object)";
975
+ }
976
+ return result;
977
+ }
978
+ return { kind: t, value: String(error) };
979
+ }
980
+ function isProduction() {
981
+ const proc = globalThis.process;
982
+ return proc?.env?.NODE_ENV === "production";
983
+ }
984
+ function createConsoleLogger(name) {
985
+ let level = isProduction() ? 1 /* INFO */ : 0 /* DEBUG */;
986
+ const emit = (lvl, method, message, args) => {
987
+ if (lvl < level) {
988
+ return;
989
+ }
990
+ const prefixed = `[${name}] ${message}`;
991
+ switch (method) {
992
+ case "log":
993
+ console.log(prefixed, ...args);
994
+ break;
995
+ case "info":
996
+ console.info(prefixed, ...args);
997
+ break;
998
+ case "warn":
999
+ console.warn(prefixed, ...args);
1000
+ break;
1001
+ case "error":
1002
+ console.error(prefixed, ...args);
1003
+ break;
1004
+ }
1005
+ };
1006
+ return {
1007
+ debug(message, ...args) {
1008
+ emit(0 /* DEBUG */, "log", message, args);
1009
+ },
1010
+ info(message, ...args) {
1011
+ emit(1 /* INFO */, "info", message, args);
1012
+ },
1013
+ warn(message, ...args) {
1014
+ emit(2 /* WARN */, "warn", message, args);
1015
+ },
1016
+ error(message, error, ...args) {
1017
+ const payload = error === void 0 ? args : [normalizeErrorForLog(error), ...args];
1018
+ emit(3 /* ERROR */, "error", message, payload);
1019
+ },
1020
+ setLevel(next) {
1021
+ level = next;
1022
+ }
1023
+ };
1024
+ }
1025
+
1026
+ // src/messages.ts
1027
+ var WebviewMessageType = /* @__PURE__ */ ((WebviewMessageType2) => {
1028
+ WebviewMessageType2["WebviewReady"] = "webviewReady";
1029
+ WebviewMessageType2["Ready"] = "ready";
1030
+ WebviewMessageType2["Log"] = "log";
1031
+ WebviewMessageType2["ExecuteCommand"] = "executeCommand";
1032
+ WebviewMessageType2["OpenUrl"] = "openUrl";
1033
+ WebviewMessageType2["UsePrompt"] = "usePrompt";
1034
+ WebviewMessageType2["UpdateAzureProfiles"] = "updateAzureProfiles";
1035
+ WebviewMessageType2["UpdateAzureProfile"] = "updateAzureProfile";
1036
+ WebviewMessageType2["GetApiConfig"] = "getApiConfig";
1037
+ WebviewMessageType2["UpdateApiConfig"] = "updateApiConfig";
1038
+ WebviewMessageType2["SaveApiConfig"] = "saveApiConfig";
1039
+ WebviewMessageType2["ApiConfigSaveFailed"] = "apiConfigSaveFailed";
1040
+ WebviewMessageType2["ExportApiConfig"] = "exportApiConfig";
1041
+ WebviewMessageType2["ImportApiConfig"] = "importApiConfig";
1042
+ WebviewMessageType2["ApiConfigImported"] = "apiConfigImported";
1043
+ WebviewMessageType2["AddExternalTool"] = "addExternalTool";
1044
+ WebviewMessageType2["UpdateExternalTool"] = "updateExternalTool";
1045
+ WebviewMessageType2["UpdateExternalTools"] = "updateExternalTools";
1046
+ WebviewMessageType2["DeleteExternalTool"] = "deleteExternalTool";
1047
+ WebviewMessageType2["ReorderExternalTools"] = "reorderExternalTools";
1048
+ WebviewMessageType2["UpdateNgrokStatus"] = "updateNgrokStatus";
1049
+ WebviewMessageType2["UpdateServerStatus"] = "updateServerStatus";
1050
+ WebviewMessageType2["GetAuthState"] = "getAuthState";
1051
+ WebviewMessageType2["UpdateAuthState"] = "updateAuthState";
1052
+ WebviewMessageType2["Login"] = "login";
1053
+ WebviewMessageType2["Logout"] = "logout";
1054
+ WebviewMessageType2["GetAccounts"] = "getAccounts";
1055
+ WebviewMessageType2["UpdateAccounts"] = "updateAccounts";
1056
+ WebviewMessageType2["SwitchAccount"] = "switchAccount";
1057
+ WebviewMessageType2["GetUserProfile"] = "getUserProfile";
1058
+ WebviewMessageType2["UpdateUserProfile"] = "updateUserProfile";
1059
+ WebviewMessageType2["UserProfileUpdated"] = "userProfileUpdated";
1060
+ WebviewMessageType2["AddExtraEmail"] = "addExtraEmail";
1061
+ WebviewMessageType2["DeleteExtraEmail"] = "deleteExtraEmail";
1062
+ WebviewMessageType2["GetCalendarHolidays"] = "getCalendarHolidays";
1063
+ WebviewMessageType2["UpdateCalendarHolidays"] = "updateCalendarHolidays";
1064
+ WebviewMessageType2["GetCalendarLeaves"] = "getCalendarLeaves";
1065
+ WebviewMessageType2["UpdateCalendarLeaves"] = "updateCalendarLeaves";
1066
+ WebviewMessageType2["CreateCalendarLeave"] = "createCalendarLeave";
1067
+ WebviewMessageType2["DeleteCalendarLeave"] = "deleteCalendarLeave";
1068
+ WebviewMessageType2["GetCalendarNotes"] = "getCalendarNotes";
1069
+ WebviewMessageType2["UpdateCalendarNotes"] = "updateCalendarNotes";
1070
+ WebviewMessageType2["SaveCalendarNote"] = "saveCalendarNote";
1071
+ WebviewMessageType2["GetCalendarMonthSchedule"] = "getCalendarMonthSchedule";
1072
+ WebviewMessageType2["GetScheduledTasks"] = "getScheduledTasks";
1073
+ WebviewMessageType2["UpdateScheduledTasks"] = "updateScheduledTasks";
1074
+ WebviewMessageType2["CreateScheduledTask"] = "createScheduledTask";
1075
+ WebviewMessageType2["EditScheduledTask"] = "editScheduledTask";
1076
+ WebviewMessageType2["DeleteScheduledTask"] = "deleteScheduledTask";
1077
+ WebviewMessageType2["ToggleScheduledTask"] = "toggleScheduledTask";
1078
+ WebviewMessageType2["TriggerScheduledTask"] = "triggerScheduledTask";
1079
+ WebviewMessageType2["CancelTaskExecution"] = "cancelTaskExecution";
1080
+ WebviewMessageType2["GetTaskExecutionLogs"] = "getTaskExecutionLogs";
1081
+ WebviewMessageType2["ClearTaskExecutionLogs"] = "clearTaskExecutionLogs";
1082
+ WebviewMessageType2["UpdateTaskExecutionLogs"] = "updateTaskExecutionLogs";
1083
+ WebviewMessageType2["UpdateTaskExecutionState"] = "updateTaskExecutionState";
1084
+ WebviewMessageType2["GetCurrentWorkspace"] = "getCurrentWorkspace";
1085
+ WebviewMessageType2["UpdateCurrentWorkspace"] = "updateCurrentWorkspace";
1086
+ WebviewMessageType2["GetProviders"] = "getProviders";
1087
+ WebviewMessageType2["ProvidersResponse"] = "providersResponse";
1088
+ WebviewMessageType2["AddProvider"] = "addProvider";
1089
+ WebviewMessageType2["UpdateProvider"] = "updateProvider";
1090
+ WebviewMessageType2["RemoveProvider"] = "removeProvider";
1091
+ WebviewMessageType2["SetDefaultProvider"] = "setDefaultProvider";
1092
+ WebviewMessageType2["SetProviderEnabled"] = "setProviderEnabled";
1093
+ WebviewMessageType2["SetProviderOrder"] = "setProviderOrder";
1094
+ WebviewMessageType2["TestProvider"] = "testProvider";
1095
+ WebviewMessageType2["ProviderTestResultMessage"] = "providerTestResult";
1096
+ WebviewMessageType2["DefaultProviderChanged"] = "defaultProviderChanged";
1097
+ WebviewMessageType2["FetchProviderModels"] = "fetchProviderModels";
1098
+ WebviewMessageType2["FetchProviderModelsResult"] = "fetchProviderModelsResult";
1099
+ WebviewMessageType2["GetProviderUsage"] = "getProviderUsage";
1100
+ WebviewMessageType2["ProviderUsageResponse"] = "providerUsageResponse";
1101
+ WebviewMessageType2["SetCacheControlEnabled"] = "setCacheControlEnabled";
1102
+ WebviewMessageType2["GetByomSettings"] = "getByomSettings";
1103
+ WebviewMessageType2["ByomSettingsResponse"] = "byomSettingsResponse";
1104
+ WebviewMessageType2["ListSkillRepoEntries"] = "listSkillRepoEntries";
1105
+ WebviewMessageType2["GetSkillRepoEntry"] = "getSkillRepoEntry";
1106
+ WebviewMessageType2["InstallSkillRepoEntry"] = "installSkillRepoEntry";
1107
+ WebviewMessageType2["ConvertSkillRepoEntryToSymlink"] = "convertSkillRepoEntryToSymlink";
1108
+ WebviewMessageType2["UninstallSkillRepoEntry"] = "uninstallSkillRepoEntry";
1109
+ WebviewMessageType2["ListLinkedSkills"] = "listLinkedSkills";
1110
+ WebviewMessageType2["UpdateSkillRepoCatalog"] = "updateSkillRepoCatalog";
1111
+ WebviewMessageType2["UpdateSkillRepoInstall"] = "updateSkillRepoInstall";
1112
+ WebviewMessageType2["UpdateLinkedSkills"] = "updateLinkedSkills";
1113
+ WebviewMessageType2["CreateSkillRepoDraft"] = "createSkillRepoDraft";
1114
+ WebviewMessageType2["CommitSkillRepoDraft"] = "commitSkillRepoDraft";
1115
+ WebviewMessageType2["ListSkillRepoDrafts"] = "listSkillRepoDrafts";
1116
+ WebviewMessageType2["DeleteSkillRepoDraft"] = "deleteSkillRepoDraft";
1117
+ WebviewMessageType2["UpdateSkillRepoDraft"] = "updateSkillRepoDraft";
1118
+ WebviewMessageType2["ListRepositories"] = "listRepositories";
1119
+ WebviewMessageType2["AddRepository"] = "addRepository";
1120
+ WebviewMessageType2["UpdateRepository"] = "updateRepository";
1121
+ WebviewMessageType2["RemoveRepository"] = "removeRepository";
1122
+ WebviewMessageType2["EnableRepository"] = "enableRepository";
1123
+ WebviewMessageType2["DisableRepository"] = "disableRepository";
1124
+ WebviewMessageType2["SyncRepository"] = "syncRepository";
1125
+ WebviewMessageType2["SyncAllRepositories"] = "syncAllRepositories";
1126
+ WebviewMessageType2["UpdateRepositoryList"] = "updateRepositoryList";
1127
+ WebviewMessageType2["UpdateRepositoryAdd"] = "updateRepositoryAdd";
1128
+ WebviewMessageType2["UpdateRepositoryUpdate"] = "updateRepositoryUpdate";
1129
+ WebviewMessageType2["UpdateRepositoryRemove"] = "updateRepositoryRemove";
1130
+ WebviewMessageType2["UpdateRepositoryToggle"] = "updateRepositoryToggle";
1131
+ WebviewMessageType2["UpdateRepositorySyncResult"] = "updateRepositorySyncResult";
1132
+ WebviewMessageType2["GetUtilityModels"] = "getUtilityModels";
1133
+ WebviewMessageType2["UtilityModelsResponse"] = "utilityModelsResponse";
1134
+ WebviewMessageType2["UpdateUtilityModels"] = "updateUtilityModels";
1135
+ WebviewMessageType2["GetServerProxyState"] = "getServerProxyState";
1136
+ WebviewMessageType2["ServerProxyStateResponse"] = "serverProxyStateResponse";
1137
+ WebviewMessageType2["SetServerProxyEnabled"] = "setServerProxyEnabled";
1138
+ WebviewMessageType2["SetServerProxyAllowOverride"] = "setServerProxyAllowOverride";
1139
+ WebviewMessageType2["GetCachedServerUrl"] = "getCachedServerUrl";
1140
+ WebviewMessageType2["CachedServerUrlResponse"] = "cachedServerUrlResponse";
1141
+ return WebviewMessageType2;
1142
+ })(WebviewMessageType || {});
1143
+ var GetUtilityModels = "getUtilityModels";
1144
+ var UtilityModelsResponse = "utilityModelsResponse";
1145
+ var UpdateUtilityModels = "updateUtilityModels";
1146
+ var SetCacheControlEnabled = "setCacheControlEnabled";
1147
+ var GetByomSettings = "getByomSettings";
1148
+ var ByomSettingsResponse = "byomSettingsResponse";
1149
+ var GetServerProxyState = "getServerProxyState";
1150
+ var ServerProxyStateResponse = "serverProxyStateResponse";
1151
+ var SetServerProxyEnabled = "setServerProxyEnabled";
1152
+ var SetServerProxyAllowOverride = "setServerProxyAllowOverride";
1153
+ var GetCachedServerUrl = "getCachedServerUrl";
1154
+ var CachedServerUrlResponse = "cachedServerUrlResponse";
1155
+
1156
+ // src/utils/safe-cast.ts
1157
+ function parsePayload(raw) {
1158
+ return raw;
1159
+ }
1160
+ function asAbortSignal(input) {
1161
+ if (input !== null && typeof input === "object") {
1162
+ const candidate = input.signal;
1163
+ if (candidate instanceof AbortSignal) {
1164
+ return candidate;
1165
+ }
1166
+ }
1167
+ return void 0;
1168
+ }
1169
+ function safeJson(text, fallback) {
1170
+ try {
1171
+ return JSON.parse(text);
1172
+ } catch {
1173
+ return fallback;
1174
+ }
1175
+ }
1176
+ export {
1177
+ BUILTIN_PROVIDER_PRESETS,
1178
+ ByomSettingsResponse,
1179
+ CERTIFICATE_BUNDLE_FORMATS,
1180
+ CachedServerUrlResponse,
1181
+ GIT_REMOTE_HOST_ALIASES,
1182
+ GetByomSettings,
1183
+ GetCachedServerUrl,
1184
+ GetServerProxyState,
1185
+ GetUtilityModels,
1186
+ LogLevel,
1187
+ MODEL_METADATA,
1188
+ PROVIDER_BASE_URL_PRESETS,
1189
+ PROVIDER_CACHE_CONTROL_METADATA,
1190
+ ServerProxyStateResponse,
1191
+ SetCacheControlEnabled,
1192
+ SetServerProxyAllowOverride,
1193
+ SetServerProxyEnabled,
1194
+ UpdateUtilityModels,
1195
+ UtilityModelsResponse,
1196
+ WebviewMessageType,
1197
+ __internal,
1198
+ asAbortSignal,
1199
+ buildGitHubLocalEmail,
1200
+ checkGitHubOrgMembership,
1201
+ createConsoleLogger,
1202
+ currencyForBaseUrl,
1203
+ fetchGitHubUser,
1204
+ getBuiltinProviderPreset,
1205
+ getGitHubOrgMembership,
1206
+ getProviderBaseUrlPresets,
1207
+ isGitHubLocalEmail,
1208
+ isProviderCacheControlAware,
1209
+ isValidCanonicalSlug,
1210
+ lookupModelMetadata,
1211
+ normalizeCanonicalSlug,
1212
+ normalizeErrorForLog,
1213
+ normalizeGitUrl,
1214
+ parsePayload,
1215
+ resolvePrimaryEmail,
1216
+ safeJson
1217
+ };