panopticon-cli 0.4.33 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +96 -210
  2. package/dist/{agents-VLK4BMVA.js → agents-E43Y3HNU.js} +5 -5
  3. package/dist/{chunk-ASY7T35E.js → chunk-AAFQANKW.js} +231 -76
  4. package/dist/chunk-AAFQANKW.js.map +1 -0
  5. package/dist/{chunk-KJ2TRXNK.js → chunk-FTCPTHIJ.js} +47 -420
  6. package/dist/chunk-FTCPTHIJ.js.map +1 -0
  7. package/dist/{chunk-PI7Y3PSN.js → chunk-GR6ZZMCX.js} +25 -6
  8. package/dist/chunk-GR6ZZMCX.js.map +1 -0
  9. package/dist/chunk-HJSM6E6U.js +1038 -0
  10. package/dist/chunk-HJSM6E6U.js.map +1 -0
  11. package/dist/{chunk-BKCWRMUX.js → chunk-HZT2AOPN.js} +81 -9
  12. package/dist/chunk-HZT2AOPN.js.map +1 -0
  13. package/dist/{chunk-XFR2DLMR.js → chunk-NTO3EDB3.js} +3 -3
  14. package/dist/{chunk-XFR2DLMR.js.map → chunk-NTO3EDB3.js.map} +1 -1
  15. package/dist/{chunk-RBUO57TC.js → chunk-PPRFKTVC.js} +2 -2
  16. package/dist/chunk-PPRFKTVC.js.map +1 -0
  17. package/dist/{chunk-XKT5MHPT.js → chunk-WQG2TYCB.js} +2 -2
  18. package/dist/cli/index.js +1383 -880
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/dashboard/prompts/work-agent.md +2 -0
  21. package/dist/dashboard/public/assets/{index-UjZq6ykz.css → index-BxpjweAL.css} +1 -1
  22. package/dist/dashboard/public/assets/index-DQHkwvvJ.js +743 -0
  23. package/dist/dashboard/public/index.html +2 -2
  24. package/dist/dashboard/server.js +3593 -2052
  25. package/dist/index.d.ts +10 -1
  26. package/dist/index.js +5 -3
  27. package/dist/index.js.map +1 -1
  28. package/dist/{specialist-context-T3NBMCIE.js → specialist-context-ZC6A4M3I.js} +4 -4
  29. package/dist/{specialist-logs-CVKD3YJ3.js → specialist-logs-KLGJCEUL.js} +4 -4
  30. package/dist/{specialists-TKAP6T6Z.js → specialists-O4HWDJL5.js} +4 -4
  31. package/dist/{traefik-QX4ZV4YG.js → traefik-QN7R5I6V.js} +2 -2
  32. package/dist/{workspace-manager-KLHUCIZV.js → workspace-manager-IE4JL2JP.js} +2 -2
  33. package/package.json +1 -1
  34. package/scripts/stop-hook +7 -0
  35. package/scripts/work-agent-stop-hook +137 -0
  36. package/skills/myn-standards/SKILL.md +351 -0
  37. package/skills/write-spec/SKILL.md +138 -0
  38. package/dist/chunk-7XNJJBH6.js +0 -538
  39. package/dist/chunk-7XNJJBH6.js.map +0 -1
  40. package/dist/chunk-ASY7T35E.js.map +0 -1
  41. package/dist/chunk-BKCWRMUX.js.map +0 -1
  42. package/dist/chunk-KJ2TRXNK.js.map +0 -1
  43. package/dist/chunk-PI7Y3PSN.js.map +0 -1
  44. package/dist/chunk-RBUO57TC.js.map +0 -1
  45. package/dist/dashboard/public/assets/index-kAJqtLDO.js +0 -708
  46. /package/dist/{agents-VLK4BMVA.js.map → agents-E43Y3HNU.js.map} +0 -0
  47. /package/dist/{chunk-XKT5MHPT.js.map → chunk-WQG2TYCB.js.map} +0 -0
  48. /package/dist/{specialist-context-T3NBMCIE.js.map → specialist-context-ZC6A4M3I.js.map} +0 -0
  49. /package/dist/{specialist-logs-CVKD3YJ3.js.map → specialist-logs-KLGJCEUL.js.map} +0 -0
  50. /package/dist/{specialists-TKAP6T6Z.js.map → specialists-O4HWDJL5.js.map} +0 -0
  51. /package/dist/{traefik-QX4ZV4YG.js.map → traefik-QN7R5I6V.js.map} +0 -0
  52. /package/dist/{workspace-manager-KLHUCIZV.js.map → workspace-manager-IE4JL2JP.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