panopticon-cli 0.4.33 → 0.5.1
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 +96 -210
- package/dist/{agents-VLK4BMVA.js → agents-5OPQKM5K.js} +6 -5
- package/dist/{chunk-OMNXYPXC.js → chunk-2V4NF7J2.js} +14 -1
- package/dist/chunk-2V4NF7J2.js.map +1 -0
- package/dist/{chunk-XKT5MHPT.js → chunk-4YSYJ4HM.js} +2 -2
- package/dist/{chunk-XFR2DLMR.js → chunk-76F6DSVS.js} +49 -10
- package/dist/chunk-76F6DSVS.js.map +1 -0
- package/dist/{chunk-PI7Y3PSN.js → chunk-F5555J3A.js} +42 -6
- package/dist/chunk-F5555J3A.js.map +1 -0
- package/dist/{chunk-KJ2TRXNK.js → chunk-FTCPTHIJ.js} +47 -420
- package/dist/chunk-FTCPTHIJ.js.map +1 -0
- package/dist/chunk-HJSM6E6U.js +1038 -0
- package/dist/chunk-HJSM6E6U.js.map +1 -0
- package/dist/{chunk-RBUO57TC.js → chunk-NLQRED36.js} +3 -3
- package/dist/chunk-NLQRED36.js.map +1 -0
- package/dist/{chunk-ASY7T35E.js → chunk-OWHXCGVO.js} +245 -90
- package/dist/chunk-OWHXCGVO.js.map +1 -0
- package/dist/{chunk-BKCWRMUX.js → chunk-VHKSS7QX.js} +106 -11
- package/dist/chunk-VHKSS7QX.js.map +1 -0
- package/dist/{chunk-GFP3PIPB.js → chunk-YGJ54GW2.js} +1 -1
- package/dist/chunk-YGJ54GW2.js.map +1 -0
- package/dist/cli/index.js +1521 -935
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/prompts/work-agent.md +2 -0
- package/dist/dashboard/public/assets/index-Ce6q21Fm.js +743 -0
- package/dist/dashboard/public/assets/{index-UjZq6ykz.css → index-NzpI0ItZ.css} +1 -1
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +4274 -2320
- package/dist/{feedback-writer-LVZ5TFYZ.js → feedback-writer-VRMMWWTW.js} +2 -2
- package/dist/git-utils-I2UDKNZH.js +131 -0
- package/dist/git-utils-I2UDKNZH.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{projects-JEIVIYC6.js → projects-CFX3RTDL.js} +4 -2
- package/dist/{remote-workspace-AHVHQEES.js → remote-workspace-7FPGF2RM.js} +2 -2
- package/dist/{review-status-EPFG4XM7.js → review-status-TDPSOU5J.js} +2 -2
- package/dist/{specialist-context-T3NBMCIE.js → specialist-context-WGUUYDWY.js} +5 -5
- package/dist/{specialist-logs-CVKD3YJ3.js → specialist-logs-XJB5TCKJ.js} +5 -5
- package/dist/{specialists-TKAP6T6Z.js → specialists-5LBRHYFA.js} +5 -5
- package/dist/{traefik-QX4ZV4YG.js → traefik-WFMQX2LY.js} +3 -3
- package/dist/{workspace-manager-KLHUCIZV.js → workspace-manager-E434Z45T.js} +2 -2
- package/package.json +1 -1
- package/scripts/record-cost-event.js +5 -5
- package/scripts/stop-hook +7 -0
- package/scripts/work-agent-stop-hook +137 -0
- package/skills/myn-standards/SKILL.md +351 -0
- package/skills/pan-new-project/SKILL.md +304 -0
- package/skills/write-spec/SKILL.md +138 -0
- package/dist/chunk-7XNJJBH6.js +0 -538
- package/dist/chunk-7XNJJBH6.js.map +0 -1
- package/dist/chunk-ASY7T35E.js.map +0 -1
- package/dist/chunk-BKCWRMUX.js.map +0 -1
- package/dist/chunk-GFP3PIPB.js.map +0 -1
- package/dist/chunk-KJ2TRXNK.js.map +0 -1
- package/dist/chunk-OMNXYPXC.js.map +0 -1
- package/dist/chunk-PI7Y3PSN.js.map +0 -1
- package/dist/chunk-RBUO57TC.js.map +0 -1
- package/dist/chunk-XFR2DLMR.js.map +0 -1
- package/dist/dashboard/public/assets/index-kAJqtLDO.js +0 -708
- /package/dist/{agents-VLK4BMVA.js.map → agents-5OPQKM5K.js.map} +0 -0
- /package/dist/{chunk-XKT5MHPT.js.map → chunk-4YSYJ4HM.js.map} +0 -0
- /package/dist/{feedback-writer-LVZ5TFYZ.js.map → feedback-writer-VRMMWWTW.js.map} +0 -0
- /package/dist/{projects-JEIVIYC6.js.map → projects-CFX3RTDL.js.map} +0 -0
- /package/dist/{remote-workspace-AHVHQEES.js.map → remote-workspace-7FPGF2RM.js.map} +0 -0
- /package/dist/{review-status-EPFG4XM7.js.map → review-status-TDPSOU5J.js.map} +0 -0
- /package/dist/{specialist-context-T3NBMCIE.js.map → specialist-context-WGUUYDWY.js.map} +0 -0
- /package/dist/{specialist-logs-CVKD3YJ3.js.map → specialist-logs-XJB5TCKJ.js.map} +0 -0
- /package/dist/{specialists-TKAP6T6Z.js.map → specialists-5LBRHYFA.js.map} +0 -0
- /package/dist/{traefik-QX4ZV4YG.js.map → traefik-WFMQX2LY.js.map} +0 -0
- /package/dist/{workspace-manager-KLHUCIZV.js.map → workspace-manager-E434Z45T.js.map} +0 -0
|
@@ -0,0 +1,1038 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SETTINGS_FILE,
|
|
3
|
+
init_paths
|
|
4
|
+
} from "./chunk-ZTFNYOC7.js";
|
|
5
|
+
import {
|
|
6
|
+
__esm,
|
|
7
|
+
init_esm_shims
|
|
8
|
+
} from "./chunk-ZHC57RCV.js";
|
|
9
|
+
|
|
10
|
+
// src/lib/settings.ts
|
|
11
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
12
|
+
function deepMerge(defaults, overrides) {
|
|
13
|
+
const result = { ...defaults };
|
|
14
|
+
for (const key of Object.keys(overrides)) {
|
|
15
|
+
const defaultVal = defaults[key];
|
|
16
|
+
const overrideVal = overrides[key];
|
|
17
|
+
if (overrideVal === void 0) continue;
|
|
18
|
+
if (typeof defaultVal === "object" && defaultVal !== null && !Array.isArray(defaultVal) && typeof overrideVal === "object" && overrideVal !== null && !Array.isArray(overrideVal)) {
|
|
19
|
+
result[key] = deepMerge(defaultVal, overrideVal);
|
|
20
|
+
} else {
|
|
21
|
+
result[key] = overrideVal;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function loadSettings() {
|
|
27
|
+
let settings;
|
|
28
|
+
if (!existsSync(SETTINGS_FILE)) {
|
|
29
|
+
settings = getDefaultSettings();
|
|
30
|
+
} else {
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(SETTINGS_FILE, "utf8");
|
|
33
|
+
const parsed = JSON.parse(content);
|
|
34
|
+
settings = deepMerge(DEFAULT_SETTINGS, parsed);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error("Warning: Failed to parse settings.json, using defaults");
|
|
37
|
+
settings = getDefaultSettings();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const envApiKeys = {};
|
|
41
|
+
if (process.env.OPENAI_API_KEY) envApiKeys.openai = process.env.OPENAI_API_KEY;
|
|
42
|
+
if (process.env.GOOGLE_API_KEY) envApiKeys.google = process.env.GOOGLE_API_KEY;
|
|
43
|
+
if (process.env.ZAI_API_KEY) envApiKeys.zai = process.env.ZAI_API_KEY;
|
|
44
|
+
if (process.env.KIMI_API_KEY) envApiKeys.kimi = process.env.KIMI_API_KEY;
|
|
45
|
+
settings.api_keys = {
|
|
46
|
+
...envApiKeys,
|
|
47
|
+
...settings.api_keys
|
|
48
|
+
};
|
|
49
|
+
return settings;
|
|
50
|
+
}
|
|
51
|
+
function saveSettings(settings) {
|
|
52
|
+
const content = JSON.stringify(settings, null, 2);
|
|
53
|
+
writeFileSync(SETTINGS_FILE, content, "utf8");
|
|
54
|
+
}
|
|
55
|
+
function validateSettings(settings) {
|
|
56
|
+
if (!settings.models) {
|
|
57
|
+
return "Missing models configuration";
|
|
58
|
+
}
|
|
59
|
+
if (!settings.models.specialists) {
|
|
60
|
+
return "Missing specialists configuration";
|
|
61
|
+
}
|
|
62
|
+
const specialists = settings.models.specialists;
|
|
63
|
+
if (!specialists.review_agent || !specialists.test_agent || !specialists.merge_agent) {
|
|
64
|
+
return "Missing specialist agent model configuration";
|
|
65
|
+
}
|
|
66
|
+
if (!settings.models.complexity) {
|
|
67
|
+
return "Missing complexity configuration";
|
|
68
|
+
}
|
|
69
|
+
const complexity = settings.models.complexity;
|
|
70
|
+
const requiredLevels = ["trivial", "simple", "medium", "complex", "expert"];
|
|
71
|
+
for (const level of requiredLevels) {
|
|
72
|
+
if (!complexity[level]) {
|
|
73
|
+
return `Missing complexity level: ${level}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!settings.api_keys) {
|
|
77
|
+
return "Missing api_keys configuration";
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function getDefaultSettings() {
|
|
82
|
+
return JSON.parse(JSON.stringify(DEFAULT_SETTINGS));
|
|
83
|
+
}
|
|
84
|
+
function getAvailableModels(settings) {
|
|
85
|
+
const anthropicModels = [
|
|
86
|
+
"claude-opus-4-6",
|
|
87
|
+
"claude-sonnet-4-6",
|
|
88
|
+
"claude-haiku-4-5"
|
|
89
|
+
];
|
|
90
|
+
const openaiModels = settings.api_keys.openai ? ["gpt-5.2-codex", "o3-deep-research", "gpt-4o", "gpt-4o-mini"] : [];
|
|
91
|
+
const googleModels = settings.api_keys.google ? ["gemini-3-pro-preview", "gemini-3-flash-preview"] : [];
|
|
92
|
+
const zaiModels = settings.api_keys.zai ? ["glm-4.7", "glm-4.7-flash"] : [];
|
|
93
|
+
const kimiModels = settings.api_keys.kimi ? ["kimi-k2", "kimi-k2.5"] : [];
|
|
94
|
+
return {
|
|
95
|
+
anthropic: anthropicModels,
|
|
96
|
+
openai: openaiModels,
|
|
97
|
+
google: googleModels,
|
|
98
|
+
zai: zaiModels,
|
|
99
|
+
kimi: kimiModels
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function isAnthropicModel(modelId) {
|
|
103
|
+
return modelId.startsWith("claude-");
|
|
104
|
+
}
|
|
105
|
+
function getClaudeModelFlag(modelId) {
|
|
106
|
+
const modelMap = {
|
|
107
|
+
"claude-opus-4-6": "opus",
|
|
108
|
+
"claude-sonnet-4-6": "sonnet",
|
|
109
|
+
"claude-sonnet-4-5": "sonnet",
|
|
110
|
+
"claude-haiku-4-5": "haiku"
|
|
111
|
+
};
|
|
112
|
+
return modelMap[modelId] || "sonnet";
|
|
113
|
+
}
|
|
114
|
+
function getAgentCommand(modelId) {
|
|
115
|
+
if (isAnthropicModel(modelId)) {
|
|
116
|
+
return {
|
|
117
|
+
command: "claude",
|
|
118
|
+
args: ["--model", getClaudeModelFlag(modelId)]
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
command: "claude-code-router",
|
|
123
|
+
args: []
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
var DEFAULT_SETTINGS;
|
|
127
|
+
var init_settings = __esm({
|
|
128
|
+
"src/lib/settings.ts"() {
|
|
129
|
+
"use strict";
|
|
130
|
+
init_esm_shims();
|
|
131
|
+
init_paths();
|
|
132
|
+
DEFAULT_SETTINGS = {
|
|
133
|
+
models: {
|
|
134
|
+
specialists: {
|
|
135
|
+
review_agent: "claude-opus-4-6",
|
|
136
|
+
test_agent: "claude-sonnet-4-6",
|
|
137
|
+
merge_agent: "claude-sonnet-4-6"
|
|
138
|
+
},
|
|
139
|
+
status_review: "claude-opus-4-6",
|
|
140
|
+
complexity: {
|
|
141
|
+
trivial: "claude-haiku-4-5",
|
|
142
|
+
simple: "claude-haiku-4-5",
|
|
143
|
+
medium: "kimi-k2.5",
|
|
144
|
+
complex: "kimi-k2.5",
|
|
145
|
+
expert: "claude-opus-4-6"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
api_keys: {}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// src/lib/providers.ts
|
|
154
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
155
|
+
import { join } from "path";
|
|
156
|
+
function getProviderForModel(modelId) {
|
|
157
|
+
if (["claude-opus-4-6", "claude-sonnet-4-6", "claude-sonnet-4-5", "claude-haiku-4-5"].includes(modelId)) {
|
|
158
|
+
return PROVIDERS.anthropic;
|
|
159
|
+
}
|
|
160
|
+
if (["gpt-5.2-codex", "o3-deep-research", "gpt-4o", "gpt-4o-mini"].includes(modelId)) {
|
|
161
|
+
return PROVIDERS.openai;
|
|
162
|
+
}
|
|
163
|
+
if (["gemini-3-pro-preview", "gemini-3-flash-preview"].includes(modelId)) {
|
|
164
|
+
return PROVIDERS.google;
|
|
165
|
+
}
|
|
166
|
+
if (["glm-4.7", "glm-4.7-flash"].includes(modelId)) {
|
|
167
|
+
return PROVIDERS.zai;
|
|
168
|
+
}
|
|
169
|
+
if (["kimi-k2", "kimi-k2.5"].includes(modelId)) {
|
|
170
|
+
return PROVIDERS.kimi;
|
|
171
|
+
}
|
|
172
|
+
return PROVIDERS.anthropic;
|
|
173
|
+
}
|
|
174
|
+
function requiresRouter(provider) {
|
|
175
|
+
return PROVIDERS[provider].compatibility === "router";
|
|
176
|
+
}
|
|
177
|
+
function getRouterProviders() {
|
|
178
|
+
return Object.values(PROVIDERS).filter((p) => p.compatibility === "router");
|
|
179
|
+
}
|
|
180
|
+
function getDirectProviders() {
|
|
181
|
+
return Object.values(PROVIDERS).filter((p) => p.compatibility === "direct");
|
|
182
|
+
}
|
|
183
|
+
function needsRouter(apiKeys) {
|
|
184
|
+
return !!(apiKeys.openai || apiKeys.google);
|
|
185
|
+
}
|
|
186
|
+
function getProviderEnv(provider, apiKey) {
|
|
187
|
+
if (provider.compatibility === "direct") {
|
|
188
|
+
const env = {};
|
|
189
|
+
if (provider.baseUrl) {
|
|
190
|
+
env.ANTHROPIC_BASE_URL = provider.baseUrl;
|
|
191
|
+
}
|
|
192
|
+
if (provider.name !== "anthropic") {
|
|
193
|
+
if (provider.authType === "credential-file") {
|
|
194
|
+
env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
195
|
+
env.CLAUDE_CODE_API_KEY_HELPER_TTL_MS = "60000";
|
|
196
|
+
} else {
|
|
197
|
+
env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (provider.name === "zai") {
|
|
201
|
+
env.API_TIMEOUT_MS = "300000";
|
|
202
|
+
}
|
|
203
|
+
return env;
|
|
204
|
+
} else {
|
|
205
|
+
return {
|
|
206
|
+
ANTHROPIC_BASE_URL: "http://localhost:3456",
|
|
207
|
+
ANTHROPIC_AUTH_TOKEN: "router-managed"
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function setupCredentialFileAuth(provider, workspacePath) {
|
|
212
|
+
if (provider.authType !== "credential-file" || !provider.credentialHelper) return;
|
|
213
|
+
const helperPath = provider.credentialHelper.replace("~", process.env.HOME || "");
|
|
214
|
+
const claudeDir = join(workspacePath, ".claude");
|
|
215
|
+
const settingsPath = join(claudeDir, "settings.local.json");
|
|
216
|
+
if (!existsSync2(claudeDir)) {
|
|
217
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
218
|
+
}
|
|
219
|
+
let settings = {};
|
|
220
|
+
if (existsSync2(settingsPath)) {
|
|
221
|
+
try {
|
|
222
|
+
settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
settings.apiKeyHelper = helperPath;
|
|
227
|
+
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
228
|
+
}
|
|
229
|
+
function clearCredentialFileAuth(workspacePath) {
|
|
230
|
+
const settingsPath = join(workspacePath, ".claude", "settings.local.json");
|
|
231
|
+
if (!existsSync2(settingsPath)) return;
|
|
232
|
+
try {
|
|
233
|
+
const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
234
|
+
if (!settings.apiKeyHelper) return;
|
|
235
|
+
delete settings.apiKeyHelper;
|
|
236
|
+
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
var PROVIDERS;
|
|
241
|
+
var init_providers = __esm({
|
|
242
|
+
"src/lib/providers.ts"() {
|
|
243
|
+
"use strict";
|
|
244
|
+
init_esm_shims();
|
|
245
|
+
PROVIDERS = {
|
|
246
|
+
anthropic: {
|
|
247
|
+
name: "anthropic",
|
|
248
|
+
displayName: "Anthropic",
|
|
249
|
+
compatibility: "direct",
|
|
250
|
+
models: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-sonnet-4-5", "claude-haiku-4-5"],
|
|
251
|
+
tested: true,
|
|
252
|
+
description: "Native Claude API"
|
|
253
|
+
},
|
|
254
|
+
kimi: {
|
|
255
|
+
name: "kimi",
|
|
256
|
+
displayName: "Kimi (Moonshot AI)",
|
|
257
|
+
compatibility: "direct",
|
|
258
|
+
baseUrl: "https://api.kimi.com/coding/",
|
|
259
|
+
authType: "credential-file",
|
|
260
|
+
credentialFile: "~/.kimi/credentials/kimi-code.json",
|
|
261
|
+
credentialHelper: "~/.panopticon/bin/kimi-token-helper.sh",
|
|
262
|
+
models: [],
|
|
263
|
+
// Kimi uses same model names as Anthropic
|
|
264
|
+
tested: true,
|
|
265
|
+
description: "Anthropic-compatible API via Kimi Code Plan (OAuth token refresh)"
|
|
266
|
+
},
|
|
267
|
+
zai: {
|
|
268
|
+
name: "zai",
|
|
269
|
+
displayName: "Z.AI (GLM)",
|
|
270
|
+
compatibility: "direct",
|
|
271
|
+
baseUrl: "https://api.z.ai/api/anthropic",
|
|
272
|
+
models: ["glm-4.7", "glm-4.7-flash"],
|
|
273
|
+
tested: true,
|
|
274
|
+
description: "Anthropic-compatible API, tested 2026-01-28"
|
|
275
|
+
},
|
|
276
|
+
openai: {
|
|
277
|
+
name: "openai",
|
|
278
|
+
displayName: "OpenAI",
|
|
279
|
+
compatibility: "router",
|
|
280
|
+
models: ["gpt-5.2-codex", "o3-deep-research", "gpt-4o", "gpt-4o-mini"],
|
|
281
|
+
tested: false,
|
|
282
|
+
description: "Requires claude-code-router for API translation"
|
|
283
|
+
},
|
|
284
|
+
google: {
|
|
285
|
+
name: "google",
|
|
286
|
+
displayName: "Google (Gemini)",
|
|
287
|
+
compatibility: "router",
|
|
288
|
+
models: ["gemini-3-pro-preview", "gemini-3-flash-preview"],
|
|
289
|
+
tested: false,
|
|
290
|
+
description: "Requires claude-code-router for API translation"
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// src/lib/model-capabilities.ts
|
|
297
|
+
function getModelCapability(model) {
|
|
298
|
+
return MODEL_CAPABILITIES[model];
|
|
299
|
+
}
|
|
300
|
+
var MODEL_DEPRECATIONS, MODEL_CAPABILITIES;
|
|
301
|
+
var init_model_capabilities = __esm({
|
|
302
|
+
"src/lib/model-capabilities.ts"() {
|
|
303
|
+
"use strict";
|
|
304
|
+
init_esm_shims();
|
|
305
|
+
MODEL_DEPRECATIONS = {
|
|
306
|
+
"claude-opus-4-5": "claude-opus-4-6",
|
|
307
|
+
"claude-sonnet-4-5": "claude-sonnet-4-6"
|
|
308
|
+
};
|
|
309
|
+
MODEL_CAPABILITIES = {
|
|
310
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
311
|
+
// ANTHROPIC MODELS
|
|
312
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
313
|
+
"claude-opus-4-6": {
|
|
314
|
+
model: "claude-opus-4-6",
|
|
315
|
+
provider: "anthropic",
|
|
316
|
+
displayName: "Claude Opus 4.6",
|
|
317
|
+
costPer1MTokens: 45,
|
|
318
|
+
// $5 in / $25 out → same pricing as 4.5
|
|
319
|
+
contextWindow: 2e5,
|
|
320
|
+
// 1M available via opt-in beta, but we use 200K
|
|
321
|
+
skills: {
|
|
322
|
+
"code-generation": 96,
|
|
323
|
+
// 80.9% SWE-bench (first >80%), 89.4% Aider Polyglot
|
|
324
|
+
"code-review": 98,
|
|
325
|
+
debugging: 97,
|
|
326
|
+
planning: 99,
|
|
327
|
+
// User confirms: "Opus 4.6 planning for sure"
|
|
328
|
+
documentation: 95,
|
|
329
|
+
testing: 92,
|
|
330
|
+
security: 98,
|
|
331
|
+
// Best for security review
|
|
332
|
+
performance: 90,
|
|
333
|
+
synthesis: 98,
|
|
334
|
+
// Best for combining info across domains
|
|
335
|
+
speed: 40,
|
|
336
|
+
// Slower but 76% more token efficient
|
|
337
|
+
"context-length": 95
|
|
338
|
+
},
|
|
339
|
+
notes: "Successor to Opus 4.5. Same pricing, 1M context available (opt-in beta). Best for planning, security, complex reasoning."
|
|
340
|
+
},
|
|
341
|
+
"claude-sonnet-4-6": {
|
|
342
|
+
model: "claude-sonnet-4-6",
|
|
343
|
+
provider: "anthropic",
|
|
344
|
+
displayName: "Claude Sonnet 4.6",
|
|
345
|
+
costPer1MTokens: 9,
|
|
346
|
+
// $3 in / $15 out → avg ~$9
|
|
347
|
+
contextWindow: 2e5,
|
|
348
|
+
skills: {
|
|
349
|
+
"code-generation": 94,
|
|
350
|
+
"code-review": 94,
|
|
351
|
+
debugging: 92,
|
|
352
|
+
planning: 90,
|
|
353
|
+
documentation: 92,
|
|
354
|
+
testing: 92,
|
|
355
|
+
security: 88,
|
|
356
|
+
performance: 88,
|
|
357
|
+
synthesis: 90,
|
|
358
|
+
speed: 70,
|
|
359
|
+
"context-length": 95
|
|
360
|
+
},
|
|
361
|
+
notes: "Successor to Sonnet 4.5. Same pricing tier. Improved coding and reasoning."
|
|
362
|
+
},
|
|
363
|
+
"claude-sonnet-4-5": {
|
|
364
|
+
model: "claude-sonnet-4-5",
|
|
365
|
+
provider: "anthropic",
|
|
366
|
+
displayName: "Claude Sonnet 4.5",
|
|
367
|
+
costPer1MTokens: 9,
|
|
368
|
+
// $3 in / $15 out → avg ~$9
|
|
369
|
+
contextWindow: 2e5,
|
|
370
|
+
skills: {
|
|
371
|
+
"code-generation": 92,
|
|
372
|
+
// 77.2% SWE-bench (82% parallel), beats GPT-5 Codex (74.5%)
|
|
373
|
+
"code-review": 92,
|
|
374
|
+
debugging: 90,
|
|
375
|
+
planning: 88,
|
|
376
|
+
documentation: 90,
|
|
377
|
+
// 100% AIME with Python
|
|
378
|
+
testing: 90,
|
|
379
|
+
// 50% Terminal-Bench, 61.4% OSWorld
|
|
380
|
+
security: 85,
|
|
381
|
+
performance: 85,
|
|
382
|
+
synthesis: 88,
|
|
383
|
+
speed: 70,
|
|
384
|
+
"context-length": 95
|
|
385
|
+
},
|
|
386
|
+
notes: "Best value: 77.2% SWE-bench at 1/5th Opus cost. Beats GPT-5 Codex."
|
|
387
|
+
},
|
|
388
|
+
"claude-haiku-4-5": {
|
|
389
|
+
model: "claude-haiku-4-5",
|
|
390
|
+
provider: "anthropic",
|
|
391
|
+
displayName: "Claude Haiku 4.5",
|
|
392
|
+
costPer1MTokens: 4,
|
|
393
|
+
// $0.80 in / $4 out → avg ~$2.4
|
|
394
|
+
contextWindow: 2e5,
|
|
395
|
+
skills: {
|
|
396
|
+
"code-generation": 75,
|
|
397
|
+
"code-review": 72,
|
|
398
|
+
debugging: 70,
|
|
399
|
+
planning: 65,
|
|
400
|
+
documentation: 75,
|
|
401
|
+
testing: 70,
|
|
402
|
+
security: 60,
|
|
403
|
+
performance: 65,
|
|
404
|
+
synthesis: 68,
|
|
405
|
+
speed: 95,
|
|
406
|
+
// Fastest Anthropic
|
|
407
|
+
"context-length": 95
|
|
408
|
+
},
|
|
409
|
+
notes: "Fast and cheap, good for simple tasks and exploration"
|
|
410
|
+
},
|
|
411
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
412
|
+
// OPENAI MODELS
|
|
413
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
414
|
+
"gpt-5.2-codex": {
|
|
415
|
+
model: "gpt-5.2-codex",
|
|
416
|
+
provider: "openai",
|
|
417
|
+
displayName: "GPT-5.2 Codex",
|
|
418
|
+
costPer1MTokens: 75,
|
|
419
|
+
// Premium tier ~$75/M
|
|
420
|
+
contextWindow: 128e3,
|
|
421
|
+
skills: {
|
|
422
|
+
"code-generation": 95,
|
|
423
|
+
// 80% SWE-bench Verified, 55.6% SWE-bench Pro
|
|
424
|
+
"code-review": 90,
|
|
425
|
+
debugging: 92,
|
|
426
|
+
// 92.4% GPQA Diamond
|
|
427
|
+
planning: 88,
|
|
428
|
+
documentation: 85,
|
|
429
|
+
testing: 90,
|
|
430
|
+
security: 85,
|
|
431
|
+
performance: 88,
|
|
432
|
+
// 52.9% ARC-AGI-2 (best reasoning)
|
|
433
|
+
synthesis: 88,
|
|
434
|
+
// 100% AIME 2025 without tools
|
|
435
|
+
speed: 55,
|
|
436
|
+
"context-length": 75
|
|
437
|
+
},
|
|
438
|
+
notes: "Premium coding: 80% SWE-bench. Best raw reasoning (52.9% ARC-AGI-2). Expensive."
|
|
439
|
+
},
|
|
440
|
+
"o3-deep-research": {
|
|
441
|
+
model: "o3-deep-research",
|
|
442
|
+
provider: "openai",
|
|
443
|
+
displayName: "O3 Deep Research",
|
|
444
|
+
costPer1MTokens: 100,
|
|
445
|
+
// Expensive reasoning model
|
|
446
|
+
contextWindow: 2e5,
|
|
447
|
+
skills: {
|
|
448
|
+
"code-generation": 85,
|
|
449
|
+
"code-review": 95,
|
|
450
|
+
debugging: 98,
|
|
451
|
+
// Best for debugging
|
|
452
|
+
planning: 95,
|
|
453
|
+
documentation: 88,
|
|
454
|
+
testing: 85,
|
|
455
|
+
security: 92,
|
|
456
|
+
performance: 92,
|
|
457
|
+
synthesis: 95,
|
|
458
|
+
speed: 20,
|
|
459
|
+
// Very slow (reasoning chains)
|
|
460
|
+
"context-length": 95
|
|
461
|
+
},
|
|
462
|
+
notes: "Deep reasoning model, excellent for complex debugging and analysis"
|
|
463
|
+
},
|
|
464
|
+
"gpt-4o": {
|
|
465
|
+
model: "gpt-4o",
|
|
466
|
+
provider: "openai",
|
|
467
|
+
displayName: "GPT-4o",
|
|
468
|
+
costPer1MTokens: 15,
|
|
469
|
+
// $5 in / $15 out
|
|
470
|
+
contextWindow: 128e3,
|
|
471
|
+
skills: {
|
|
472
|
+
"code-generation": 88,
|
|
473
|
+
"code-review": 85,
|
|
474
|
+
debugging: 85,
|
|
475
|
+
planning: 82,
|
|
476
|
+
documentation: 88,
|
|
477
|
+
testing: 82,
|
|
478
|
+
security: 78,
|
|
479
|
+
performance: 80,
|
|
480
|
+
synthesis: 85,
|
|
481
|
+
speed: 75,
|
|
482
|
+
"context-length": 75
|
|
483
|
+
},
|
|
484
|
+
notes: "Good all-rounder, competitive with Sonnet"
|
|
485
|
+
},
|
|
486
|
+
"gpt-4o-mini": {
|
|
487
|
+
model: "gpt-4o-mini",
|
|
488
|
+
provider: "openai",
|
|
489
|
+
displayName: "GPT-4o Mini",
|
|
490
|
+
costPer1MTokens: 1,
|
|
491
|
+
// Very cheap
|
|
492
|
+
contextWindow: 128e3,
|
|
493
|
+
skills: {
|
|
494
|
+
"code-generation": 72,
|
|
495
|
+
"code-review": 68,
|
|
496
|
+
debugging: 65,
|
|
497
|
+
planning: 60,
|
|
498
|
+
documentation: 70,
|
|
499
|
+
testing: 65,
|
|
500
|
+
security: 55,
|
|
501
|
+
performance: 60,
|
|
502
|
+
synthesis: 62,
|
|
503
|
+
speed: 92,
|
|
504
|
+
"context-length": 75
|
|
505
|
+
},
|
|
506
|
+
notes: "Budget option, good for simple tasks"
|
|
507
|
+
},
|
|
508
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
509
|
+
// GOOGLE MODELS
|
|
510
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
511
|
+
"gemini-3-pro-preview": {
|
|
512
|
+
model: "gemini-3-pro-preview",
|
|
513
|
+
provider: "google",
|
|
514
|
+
displayName: "Gemini 3 Pro",
|
|
515
|
+
costPer1MTokens: 12,
|
|
516
|
+
// $4.2 in / $18.9 out
|
|
517
|
+
contextWindow: 1e6,
|
|
518
|
+
// 1M context!
|
|
519
|
+
skills: {
|
|
520
|
+
"code-generation": 90,
|
|
521
|
+
// 2439 Elo LiveCodeBench Pro (first >1500 on LMArena)
|
|
522
|
+
"code-review": 88,
|
|
523
|
+
debugging: 85,
|
|
524
|
+
planning: 85,
|
|
525
|
+
documentation: 88,
|
|
526
|
+
testing: 85,
|
|
527
|
+
// ~95% AIME 2025
|
|
528
|
+
security: 78,
|
|
529
|
+
performance: 85,
|
|
530
|
+
// Strong multimodal
|
|
531
|
+
synthesis: 90,
|
|
532
|
+
// Best for combining large codebases
|
|
533
|
+
speed: 80,
|
|
534
|
+
"context-length": 100
|
|
535
|
+
// Best context - 1M tokens
|
|
536
|
+
},
|
|
537
|
+
notes: "First to exceed 1500 Elo on LMArena. Best for large codebase analysis with 1M context."
|
|
538
|
+
},
|
|
539
|
+
"gemini-3-flash-preview": {
|
|
540
|
+
model: "gemini-3-flash-preview",
|
|
541
|
+
provider: "google",
|
|
542
|
+
displayName: "Gemini 3 Flash",
|
|
543
|
+
costPer1MTokens: 0.5,
|
|
544
|
+
// Very cheap
|
|
545
|
+
contextWindow: 1e6,
|
|
546
|
+
skills: {
|
|
547
|
+
"code-generation": 75,
|
|
548
|
+
"code-review": 70,
|
|
549
|
+
debugging: 68,
|
|
550
|
+
planning: 62,
|
|
551
|
+
documentation: 72,
|
|
552
|
+
testing: 68,
|
|
553
|
+
security: 55,
|
|
554
|
+
performance: 65,
|
|
555
|
+
synthesis: 70,
|
|
556
|
+
speed: 98,
|
|
557
|
+
// Fastest overall
|
|
558
|
+
"context-length": 100
|
|
559
|
+
},
|
|
560
|
+
notes: "Extremely fast and cheap, huge context, great for exploration"
|
|
561
|
+
},
|
|
562
|
+
"gemini-2.5-pro": {
|
|
563
|
+
model: "gemini-2.5-pro",
|
|
564
|
+
provider: "google",
|
|
565
|
+
displayName: "Gemini 2.5 Pro",
|
|
566
|
+
costPer1MTokens: 12,
|
|
567
|
+
contextWindow: 1e6,
|
|
568
|
+
skills: {
|
|
569
|
+
"code-generation": 92,
|
|
570
|
+
"code-review": 90,
|
|
571
|
+
debugging: 88,
|
|
572
|
+
planning: 88,
|
|
573
|
+
documentation: 90,
|
|
574
|
+
testing: 87,
|
|
575
|
+
security: 82,
|
|
576
|
+
performance: 88,
|
|
577
|
+
synthesis: 92,
|
|
578
|
+
speed: 75,
|
|
579
|
+
"context-length": 100
|
|
580
|
+
},
|
|
581
|
+
notes: "Advanced reasoning and code capabilities with 1M context"
|
|
582
|
+
},
|
|
583
|
+
"gemini-2.5-flash": {
|
|
584
|
+
model: "gemini-2.5-flash",
|
|
585
|
+
provider: "google",
|
|
586
|
+
displayName: "Gemini 2.5 Flash",
|
|
587
|
+
costPer1MTokens: 0.6,
|
|
588
|
+
contextWindow: 1e6,
|
|
589
|
+
skills: {
|
|
590
|
+
"code-generation": 78,
|
|
591
|
+
"code-review": 73,
|
|
592
|
+
debugging: 70,
|
|
593
|
+
planning: 65,
|
|
594
|
+
documentation: 75,
|
|
595
|
+
testing: 70,
|
|
596
|
+
security: 58,
|
|
597
|
+
performance: 68,
|
|
598
|
+
synthesis: 73,
|
|
599
|
+
speed: 95,
|
|
600
|
+
"context-length": 100
|
|
601
|
+
},
|
|
602
|
+
notes: "Fast and efficient with large context support"
|
|
603
|
+
},
|
|
604
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
605
|
+
// Z.AI MODELS
|
|
606
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
607
|
+
"glm-4.7": {
|
|
608
|
+
model: "glm-4.7",
|
|
609
|
+
provider: "zai",
|
|
610
|
+
displayName: "GLM 4.7",
|
|
611
|
+
costPer1MTokens: 5,
|
|
612
|
+
contextWindow: 2e5,
|
|
613
|
+
// 200K context, 128K output
|
|
614
|
+
skills: {
|
|
615
|
+
"code-generation": 88,
|
|
616
|
+
// 73.8% SWE-bench, 84.9 LiveCodeBench v6 (open-source SOTA)
|
|
617
|
+
"code-review": 85,
|
|
618
|
+
debugging: 85,
|
|
619
|
+
// Strong debugging with Interleaved Thinking
|
|
620
|
+
planning: 82,
|
|
621
|
+
// 95.7% AIME 2025 (beats Gemini 3 & GPT-5.1)
|
|
622
|
+
documentation: 80,
|
|
623
|
+
testing: 82,
|
|
624
|
+
// 87.4 τ²-Bench (SOTA for tool use)
|
|
625
|
+
security: 72,
|
|
626
|
+
performance: 78,
|
|
627
|
+
synthesis: 85,
|
|
628
|
+
// Preserved Thinking retains context across turns
|
|
629
|
+
speed: 80,
|
|
630
|
+
"context-length": 95
|
|
631
|
+
// 200K context
|
|
632
|
+
},
|
|
633
|
+
notes: "Top open-source for agentic coding. 73.8% SWE-bench, best tool use. 400B params with Interleaved Thinking."
|
|
634
|
+
},
|
|
635
|
+
"glm-4.7-flash": {
|
|
636
|
+
model: "glm-4.7-flash",
|
|
637
|
+
provider: "zai",
|
|
638
|
+
displayName: "GLM 4.7 Flash",
|
|
639
|
+
costPer1MTokens: 1.5,
|
|
640
|
+
contextWindow: 128e3,
|
|
641
|
+
skills: {
|
|
642
|
+
"code-generation": 72,
|
|
643
|
+
"code-review": 68,
|
|
644
|
+
debugging: 65,
|
|
645
|
+
planning: 62,
|
|
646
|
+
documentation: 70,
|
|
647
|
+
testing: 65,
|
|
648
|
+
security: 55,
|
|
649
|
+
performance: 62,
|
|
650
|
+
synthesis: 65,
|
|
651
|
+
speed: 92,
|
|
652
|
+
// Fast inference
|
|
653
|
+
"context-length": 75
|
|
654
|
+
},
|
|
655
|
+
notes: "Fast and affordable. Good for quick iterations and exploration."
|
|
656
|
+
},
|
|
657
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
658
|
+
// KIMI MODELS
|
|
659
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
660
|
+
"kimi-k2": {
|
|
661
|
+
model: "kimi-k2",
|
|
662
|
+
provider: "kimi",
|
|
663
|
+
displayName: "Kimi K2",
|
|
664
|
+
costPer1MTokens: 1.4,
|
|
665
|
+
// $0.16 in / $2.63 out → very cheap
|
|
666
|
+
contextWindow: 131e3,
|
|
667
|
+
skills: {
|
|
668
|
+
"code-generation": 82,
|
|
669
|
+
// 65.8% SWE-bench (beats GPT-4.1 at 54.6%)
|
|
670
|
+
"code-review": 80,
|
|
671
|
+
debugging: 78,
|
|
672
|
+
planning: 75,
|
|
673
|
+
documentation: 80,
|
|
674
|
+
testing: 75,
|
|
675
|
+
security: 70,
|
|
676
|
+
performance: 72,
|
|
677
|
+
synthesis: 78,
|
|
678
|
+
speed: 80,
|
|
679
|
+
"context-length": 75
|
|
680
|
+
},
|
|
681
|
+
notes: "Strong value: 65.8% SWE-bench at very low cost. Good for routine tasks."
|
|
682
|
+
},
|
|
683
|
+
"kimi-k2.5": {
|
|
684
|
+
model: "kimi-k2.5",
|
|
685
|
+
provider: "kimi",
|
|
686
|
+
displayName: "Kimi K2.5",
|
|
687
|
+
costPer1MTokens: 8,
|
|
688
|
+
// ~5.1x cheaper than GPT-5.2
|
|
689
|
+
contextWindow: 256e3,
|
|
690
|
+
skills: {
|
|
691
|
+
"code-generation": 92,
|
|
692
|
+
// 76.8% SWE-bench, 85 LiveCodeBench v6
|
|
693
|
+
"code-review": 90,
|
|
694
|
+
debugging: 90,
|
|
695
|
+
// Strong analytical capabilities
|
|
696
|
+
planning: 88,
|
|
697
|
+
// User confirms "highly capable"
|
|
698
|
+
documentation: 88,
|
|
699
|
+
testing: 88,
|
|
700
|
+
// 92% coding accuracy
|
|
701
|
+
security: 82,
|
|
702
|
+
performance: 85,
|
|
703
|
+
synthesis: 92,
|
|
704
|
+
// Can coordinate 100 sub-agents, 1500 tool calls
|
|
705
|
+
speed: 75,
|
|
706
|
+
// MoE: 1T total params, 32B active
|
|
707
|
+
"context-length": 98
|
|
708
|
+
// 256K context
|
|
709
|
+
},
|
|
710
|
+
notes: "Best open-source coding model. 5x cheaper than GPT-5.2. Excellent for frontend dev and multi-agent orchestration."
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// src/lib/config-yaml.ts
|
|
717
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, writeFileSync as writeFileSync3, copyFileSync } from "fs";
|
|
718
|
+
import { join as join2 } from "path";
|
|
719
|
+
import { homedir } from "os";
|
|
720
|
+
import yaml from "js-yaml";
|
|
721
|
+
function normalizeProviderConfig(providerConfig, fallbackKey) {
|
|
722
|
+
if (providerConfig === void 0) {
|
|
723
|
+
return { enabled: false };
|
|
724
|
+
}
|
|
725
|
+
if (typeof providerConfig === "boolean") {
|
|
726
|
+
return { enabled: providerConfig, api_key: fallbackKey };
|
|
727
|
+
}
|
|
728
|
+
return {
|
|
729
|
+
enabled: providerConfig.enabled,
|
|
730
|
+
api_key: providerConfig.api_key || fallbackKey
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function resolveEnvVar(value) {
|
|
734
|
+
if (!value) return void 0;
|
|
735
|
+
return value.replace(/\$\{?([A-Z_][A-Z0-9_]*)\}?/g, (match, varName) => {
|
|
736
|
+
const envValue = process.env[varName];
|
|
737
|
+
return envValue !== void 0 ? envValue : match;
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
function loadYamlFile(filePath) {
|
|
741
|
+
if (!existsSync3(filePath)) {
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
746
|
+
const parsed = yaml.load(content);
|
|
747
|
+
return parsed || {};
|
|
748
|
+
} catch (error) {
|
|
749
|
+
console.error(`Error loading YAML config from ${filePath}:`, error);
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function findProjectRoot(startDir = process.cwd()) {
|
|
754
|
+
let currentDir = startDir;
|
|
755
|
+
while (currentDir !== "/") {
|
|
756
|
+
if (existsSync3(join2(currentDir, ".git"))) {
|
|
757
|
+
return currentDir;
|
|
758
|
+
}
|
|
759
|
+
currentDir = join2(currentDir, "..");
|
|
760
|
+
}
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
function loadProjectConfig() {
|
|
764
|
+
const projectRoot = findProjectRoot();
|
|
765
|
+
if (!projectRoot) {
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
const projectConfigPath = join2(projectRoot, ".panopticon.yaml");
|
|
769
|
+
return loadYamlFile(projectConfigPath);
|
|
770
|
+
}
|
|
771
|
+
function loadGlobalConfig() {
|
|
772
|
+
return loadYamlFile(GLOBAL_CONFIG_PATH);
|
|
773
|
+
}
|
|
774
|
+
function mergeShadowConfig(result, config) {
|
|
775
|
+
if (!config?.shadow) return;
|
|
776
|
+
if (config.shadow.enabled !== void 0) {
|
|
777
|
+
result.enabled = config.shadow.enabled;
|
|
778
|
+
}
|
|
779
|
+
if (config.shadow.trackers) {
|
|
780
|
+
if (config.shadow.trackers.linear !== void 0) {
|
|
781
|
+
result.trackers.linear = config.shadow.trackers.linear;
|
|
782
|
+
}
|
|
783
|
+
if (config.shadow.trackers.github !== void 0) {
|
|
784
|
+
result.trackers.github = config.shadow.trackers.github;
|
|
785
|
+
}
|
|
786
|
+
if (config.shadow.trackers.gitlab !== void 0) {
|
|
787
|
+
result.trackers.gitlab = config.shadow.trackers.gitlab;
|
|
788
|
+
}
|
|
789
|
+
if (config.shadow.trackers.rally !== void 0) {
|
|
790
|
+
result.trackers.rally = config.shadow.trackers.rally;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function mergeConfigs(...configs) {
|
|
795
|
+
const result = {
|
|
796
|
+
...DEFAULT_CONFIG,
|
|
797
|
+
enabledProviders: new Set(DEFAULT_CONFIG.enabledProviders),
|
|
798
|
+
shadow: {
|
|
799
|
+
enabled: DEFAULT_CONFIG.shadow.enabled,
|
|
800
|
+
trackers: { ...DEFAULT_CONFIG.shadow.trackers }
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
const validConfigs = configs.filter((c) => c !== null);
|
|
804
|
+
for (const config of validConfigs.reverse()) {
|
|
805
|
+
if (config.models?.providers) {
|
|
806
|
+
const providers = config.models.providers;
|
|
807
|
+
const legacyKeys = config.api_keys || {};
|
|
808
|
+
result.enabledProviders.add("anthropic");
|
|
809
|
+
const openai = normalizeProviderConfig(providers.openai, legacyKeys.openai);
|
|
810
|
+
if (openai.enabled) {
|
|
811
|
+
result.enabledProviders.add("openai");
|
|
812
|
+
if (openai.api_key) {
|
|
813
|
+
result.apiKeys.openai = resolveEnvVar(openai.api_key);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
const google = normalizeProviderConfig(providers.google, legacyKeys.google);
|
|
817
|
+
if (google.enabled) {
|
|
818
|
+
result.enabledProviders.add("google");
|
|
819
|
+
if (google.api_key) {
|
|
820
|
+
result.apiKeys.google = resolveEnvVar(google.api_key);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const zai = normalizeProviderConfig(providers.zai, legacyKeys.zai);
|
|
824
|
+
if (zai.enabled) {
|
|
825
|
+
result.enabledProviders.add("zai");
|
|
826
|
+
if (zai.api_key) {
|
|
827
|
+
result.apiKeys.zai = resolveEnvVar(zai.api_key);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const kimi = normalizeProviderConfig(providers.kimi, legacyKeys.kimi);
|
|
831
|
+
if (kimi.enabled) {
|
|
832
|
+
result.enabledProviders.add("kimi");
|
|
833
|
+
if (kimi.api_key) {
|
|
834
|
+
result.apiKeys.kimi = resolveEnvVar(kimi.api_key);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (config.api_keys) {
|
|
839
|
+
if (config.api_keys.openai) {
|
|
840
|
+
result.apiKeys.openai = resolveEnvVar(config.api_keys.openai);
|
|
841
|
+
result.enabledProviders.add("openai");
|
|
842
|
+
}
|
|
843
|
+
if (config.api_keys.google) {
|
|
844
|
+
result.apiKeys.google = resolveEnvVar(config.api_keys.google);
|
|
845
|
+
result.enabledProviders.add("google");
|
|
846
|
+
}
|
|
847
|
+
if (config.api_keys.zai) {
|
|
848
|
+
result.apiKeys.zai = resolveEnvVar(config.api_keys.zai);
|
|
849
|
+
result.enabledProviders.add("zai");
|
|
850
|
+
}
|
|
851
|
+
if (config.api_keys.kimi) {
|
|
852
|
+
result.apiKeys.kimi = resolveEnvVar(config.api_keys.kimi);
|
|
853
|
+
result.enabledProviders.add("kimi");
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (config.models?.overrides) {
|
|
857
|
+
result.overrides = {
|
|
858
|
+
...result.overrides,
|
|
859
|
+
...config.models.overrides
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
if (config.models?.gemini_thinking_level) {
|
|
863
|
+
result.geminiThinkingLevel = config.models.gemini_thinking_level;
|
|
864
|
+
}
|
|
865
|
+
if (config.tracker_keys) {
|
|
866
|
+
if (config.tracker_keys.linear) {
|
|
867
|
+
result.trackerKeys.linear = resolveEnvVar(config.tracker_keys.linear);
|
|
868
|
+
}
|
|
869
|
+
if (config.tracker_keys.github) {
|
|
870
|
+
result.trackerKeys.github = resolveEnvVar(config.tracker_keys.github);
|
|
871
|
+
}
|
|
872
|
+
if (config.tracker_keys.gitlab) {
|
|
873
|
+
result.trackerKeys.gitlab = resolveEnvVar(config.tracker_keys.gitlab);
|
|
874
|
+
}
|
|
875
|
+
if (config.tracker_keys.rally) {
|
|
876
|
+
result.trackerKeys.rally = resolveEnvVar(config.tracker_keys.rally);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
mergeShadowConfig(result.shadow, config);
|
|
880
|
+
}
|
|
881
|
+
return result;
|
|
882
|
+
}
|
|
883
|
+
function detectDeprecatedModels(config) {
|
|
884
|
+
if (!config?.models?.overrides) {
|
|
885
|
+
return [];
|
|
886
|
+
}
|
|
887
|
+
const migrations = [];
|
|
888
|
+
for (const [workType, modelId] of Object.entries(config.models.overrides)) {
|
|
889
|
+
if (modelId && MODEL_DEPRECATIONS[modelId]) {
|
|
890
|
+
migrations.push({
|
|
891
|
+
workType,
|
|
892
|
+
from: modelId,
|
|
893
|
+
to: MODEL_DEPRECATIONS[modelId]
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
return migrations;
|
|
898
|
+
}
|
|
899
|
+
function applyMigrations(config, migrations) {
|
|
900
|
+
if (!config.models) {
|
|
901
|
+
config.models = {};
|
|
902
|
+
}
|
|
903
|
+
if (!config.models.overrides) {
|
|
904
|
+
config.models.overrides = {};
|
|
905
|
+
}
|
|
906
|
+
for (const { workType, to } of migrations) {
|
|
907
|
+
config.models.overrides[workType] = to;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function backupGlobalConfig() {
|
|
911
|
+
try {
|
|
912
|
+
const backupPath = `${GLOBAL_CONFIG_PATH}.bak`;
|
|
913
|
+
copyFileSync(GLOBAL_CONFIG_PATH, backupPath);
|
|
914
|
+
console.log(`\u2713 Backed up config.yaml \u2192 config.yaml.bak`);
|
|
915
|
+
return true;
|
|
916
|
+
} catch (error) {
|
|
917
|
+
console.error(`Failed to create config backup:`, error);
|
|
918
|
+
return false;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
function writeGlobalConfig(config) {
|
|
922
|
+
const yamlContent = yaml.dump(config, {
|
|
923
|
+
indent: 2,
|
|
924
|
+
lineWidth: 100,
|
|
925
|
+
noRefs: true
|
|
926
|
+
});
|
|
927
|
+
writeFileSync3(GLOBAL_CONFIG_PATH, yamlContent, "utf-8");
|
|
928
|
+
}
|
|
929
|
+
function loadConfig() {
|
|
930
|
+
let globalConfig = loadGlobalConfig();
|
|
931
|
+
const projectConfig = loadProjectConfig();
|
|
932
|
+
let migrationResult;
|
|
933
|
+
if (globalConfig && hasGlobalConfig()) {
|
|
934
|
+
const migrations = detectDeprecatedModels(globalConfig);
|
|
935
|
+
if (migrations.length > 0) {
|
|
936
|
+
const backedUp = backupGlobalConfig();
|
|
937
|
+
applyMigrations(globalConfig, migrations);
|
|
938
|
+
writeGlobalConfig(globalConfig);
|
|
939
|
+
console.log("\n\u{1F504} Model ID Migration:");
|
|
940
|
+
for (const { workType, from, to } of migrations) {
|
|
941
|
+
console.log(` ${workType}: ${from} \u2192 ${to}`);
|
|
942
|
+
}
|
|
943
|
+
console.log("");
|
|
944
|
+
migrationResult = { migrated: migrations, backedUp };
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
const config = mergeConfigs(projectConfig, globalConfig);
|
|
948
|
+
if (process.env.OPENAI_API_KEY && !config.apiKeys.openai) {
|
|
949
|
+
config.apiKeys.openai = process.env.OPENAI_API_KEY;
|
|
950
|
+
config.enabledProviders.add("openai");
|
|
951
|
+
}
|
|
952
|
+
if (process.env.GOOGLE_API_KEY && !config.apiKeys.google) {
|
|
953
|
+
config.apiKeys.google = process.env.GOOGLE_API_KEY;
|
|
954
|
+
config.enabledProviders.add("google");
|
|
955
|
+
}
|
|
956
|
+
if (process.env.ZAI_API_KEY && !config.apiKeys.zai) {
|
|
957
|
+
config.apiKeys.zai = process.env.ZAI_API_KEY;
|
|
958
|
+
config.enabledProviders.add("zai");
|
|
959
|
+
}
|
|
960
|
+
if (process.env.KIMI_API_KEY && !config.apiKeys.kimi) {
|
|
961
|
+
config.apiKeys.kimi = process.env.KIMI_API_KEY;
|
|
962
|
+
config.enabledProviders.add("kimi");
|
|
963
|
+
}
|
|
964
|
+
if (process.env.LINEAR_API_KEY && !config.trackerKeys.linear) {
|
|
965
|
+
config.trackerKeys.linear = process.env.LINEAR_API_KEY;
|
|
966
|
+
}
|
|
967
|
+
if (process.env.GITHUB_TOKEN && !config.trackerKeys.github) {
|
|
968
|
+
config.trackerKeys.github = process.env.GITHUB_TOKEN;
|
|
969
|
+
}
|
|
970
|
+
if (process.env.GITLAB_TOKEN && !config.trackerKeys.gitlab) {
|
|
971
|
+
config.trackerKeys.gitlab = process.env.GITLAB_TOKEN;
|
|
972
|
+
}
|
|
973
|
+
if (process.env.RALLY_API_KEY && !config.trackerKeys.rally) {
|
|
974
|
+
config.trackerKeys.rally = process.env.RALLY_API_KEY;
|
|
975
|
+
}
|
|
976
|
+
if (process.env.SHADOW_MODE !== void 0) {
|
|
977
|
+
const envShadowMode = ["true", "1", "yes"].includes(process.env.SHADOW_MODE.toLowerCase());
|
|
978
|
+
config.shadow.enabled = envShadowMode;
|
|
979
|
+
}
|
|
980
|
+
return { config, migration: migrationResult };
|
|
981
|
+
}
|
|
982
|
+
function hasGlobalConfig() {
|
|
983
|
+
return existsSync3(GLOBAL_CONFIG_PATH);
|
|
984
|
+
}
|
|
985
|
+
var DEFAULT_CONFIG, GLOBAL_CONFIG_PATH;
|
|
986
|
+
var init_config_yaml = __esm({
|
|
987
|
+
"src/lib/config-yaml.ts"() {
|
|
988
|
+
"use strict";
|
|
989
|
+
init_esm_shims();
|
|
990
|
+
init_model_capabilities();
|
|
991
|
+
DEFAULT_CONFIG = {
|
|
992
|
+
enabledProviders: /* @__PURE__ */ new Set(["anthropic"]),
|
|
993
|
+
// Only Anthropic by default
|
|
994
|
+
apiKeys: {},
|
|
995
|
+
overrides: {},
|
|
996
|
+
geminiThinkingLevel: 3,
|
|
997
|
+
trackerKeys: {},
|
|
998
|
+
shadow: {
|
|
999
|
+
enabled: false,
|
|
1000
|
+
trackers: {
|
|
1001
|
+
linear: false,
|
|
1002
|
+
github: false,
|
|
1003
|
+
gitlab: false,
|
|
1004
|
+
rally: false
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
GLOBAL_CONFIG_PATH = join2(homedir(), ".panopticon", "config.yaml");
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
export {
|
|
1013
|
+
loadSettings,
|
|
1014
|
+
saveSettings,
|
|
1015
|
+
validateSettings,
|
|
1016
|
+
getDefaultSettings,
|
|
1017
|
+
getAvailableModels,
|
|
1018
|
+
isAnthropicModel,
|
|
1019
|
+
getClaudeModelFlag,
|
|
1020
|
+
getAgentCommand,
|
|
1021
|
+
init_settings,
|
|
1022
|
+
MODEL_CAPABILITIES,
|
|
1023
|
+
getModelCapability,
|
|
1024
|
+
init_model_capabilities,
|
|
1025
|
+
loadConfig,
|
|
1026
|
+
init_config_yaml,
|
|
1027
|
+
PROVIDERS,
|
|
1028
|
+
getProviderForModel,
|
|
1029
|
+
requiresRouter,
|
|
1030
|
+
getRouterProviders,
|
|
1031
|
+
getDirectProviders,
|
|
1032
|
+
needsRouter,
|
|
1033
|
+
getProviderEnv,
|
|
1034
|
+
setupCredentialFileAuth,
|
|
1035
|
+
clearCredentialFileAuth,
|
|
1036
|
+
init_providers
|
|
1037
|
+
};
|
|
1038
|
+
//# sourceMappingURL=chunk-HJSM6E6U.js.map
|