panopticon-cli 0.4.5 → 0.4.6

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 (68) hide show
  1. package/README.md +84 -2695
  2. package/dist/{agents-B5NRTVHK.js → agents-54LDKMHR.js} +8 -3
  3. package/dist/chunk-44EOY2ZL.js +58 -0
  4. package/dist/chunk-44EOY2ZL.js.map +1 -0
  5. package/dist/chunk-BWGFN44T.js +224 -0
  6. package/dist/chunk-BWGFN44T.js.map +1 -0
  7. package/dist/chunk-F7NQZD6H.js +49 -0
  8. package/dist/chunk-F7NQZD6H.js.map +1 -0
  9. package/dist/chunk-HCTJFIJJ.js +159 -0
  10. package/dist/chunk-HCTJFIJJ.js.map +1 -0
  11. package/dist/chunk-JM6V62LT.js +650 -0
  12. package/dist/chunk-JM6V62LT.js.map +1 -0
  13. package/dist/chunk-K45YD6A3.js +254 -0
  14. package/dist/chunk-K45YD6A3.js.map +1 -0
  15. package/dist/chunk-KGPRXDMX.js +137 -0
  16. package/dist/chunk-KGPRXDMX.js.map +1 -0
  17. package/dist/chunk-KQAEUOML.js +278 -0
  18. package/dist/chunk-KQAEUOML.js.map +1 -0
  19. package/dist/chunk-NYVQC3D7.js +90 -0
  20. package/dist/chunk-NYVQC3D7.js.map +1 -0
  21. package/dist/chunk-PUR532O7.js +1556 -0
  22. package/dist/chunk-PUR532O7.js.map +1 -0
  23. package/dist/chunk-VTDDVLCK.js +1977 -0
  24. package/dist/chunk-VTDDVLCK.js.map +1 -0
  25. package/dist/chunk-Z24TY3XN.js +916 -0
  26. package/dist/chunk-Z24TY3XN.js.map +1 -0
  27. package/dist/chunk-ZHC57RCV.js +44 -0
  28. package/dist/chunk-ZHC57RCV.js.map +1 -0
  29. package/dist/{chunk-ITI4IC5A.js → chunk-ZZ3477GY.js} +69 -100
  30. package/dist/chunk-ZZ3477GY.js.map +1 -0
  31. package/dist/cli/index.js +4664 -2912
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/dashboard/public/assets/index-CRqsEkmn.css +32 -0
  34. package/dist/dashboard/public/assets/index-DPSUbu4A.js +645 -0
  35. package/dist/dashboard/public/index.html +15 -3
  36. package/dist/dashboard/server.js +45663 -17860
  37. package/dist/dns-L3L2BB27.js +30 -0
  38. package/dist/dns-L3L2BB27.js.map +1 -0
  39. package/dist/index.d.ts +63 -3
  40. package/dist/index.js +42 -18
  41. package/dist/index.js.map +1 -1
  42. package/dist/projects-ESIB34QQ.js +43 -0
  43. package/dist/projects-ESIB34QQ.js.map +1 -0
  44. package/dist/remote-agents-Z3R2A5BN.js +25 -0
  45. package/dist/remote-agents-Z3R2A5BN.js.map +1 -0
  46. package/dist/remote-workspace-HI4VML6H.js +179 -0
  47. package/dist/remote-workspace-HI4VML6H.js.map +1 -0
  48. package/dist/specialist-context-SNCJ7O7G.js +256 -0
  49. package/dist/specialist-context-SNCJ7O7G.js.map +1 -0
  50. package/dist/specialist-logs-A7ODEK2T.js +43 -0
  51. package/dist/specialist-logs-A7ODEK2T.js.map +1 -0
  52. package/dist/specialists-C7XLNSXQ.js +121 -0
  53. package/dist/specialists-C7XLNSXQ.js.map +1 -0
  54. package/dist/traefik-WI3KSRGG.js +12 -0
  55. package/dist/traefik-WI3KSRGG.js.map +1 -0
  56. package/package.json +1 -1
  57. package/templates/traefik/docker-compose.yml +1 -1
  58. package/templates/traefik/dynamic/panopticon.yml.template +41 -0
  59. package/templates/traefik/traefik.yml +8 -0
  60. package/dist/chunk-7HHDVXBM.js +0 -349
  61. package/dist/chunk-7HHDVXBM.js.map +0 -1
  62. package/dist/chunk-H45CLB7E.js +0 -2044
  63. package/dist/chunk-H45CLB7E.js.map +0 -1
  64. package/dist/chunk-ITI4IC5A.js.map +0 -1
  65. package/dist/dashboard/public/assets/index-BDd8hGYb.css +0 -32
  66. package/dist/dashboard/public/assets/index-sFwLPko-.js +0 -556
  67. package/templates/traefik/dynamic/panopticon.yml +0 -51
  68. /package/dist/{agents-B5NRTVHK.js.map → agents-54LDKMHR.js.map} +0 -0
@@ -0,0 +1,1556 @@
1
+ import {
2
+ AGENTS_DIR,
3
+ PANOPTICON_HOME,
4
+ init_paths
5
+ } from "./chunk-KGPRXDMX.js";
6
+ import {
7
+ __esm,
8
+ init_esm_shims
9
+ } from "./chunk-ZHC57RCV.js";
10
+
11
+ // src/lib/tmux.ts
12
+ import { execSync } from "child_process";
13
+ import { writeFileSync, chmodSync, appendFileSync, mkdirSync, existsSync } from "fs";
14
+ import { join } from "path";
15
+ function ensureLogDir() {
16
+ const logDir = join(PANOPTICON_HOME, "logs");
17
+ if (!existsSync(logDir)) {
18
+ mkdirSync(logDir, { recursive: true });
19
+ }
20
+ }
21
+ function logSendKeys(sessionName, keys, caller) {
22
+ try {
23
+ ensureLogDir();
24
+ const stack = new Error().stack || "";
25
+ const stackLines = stack.split("\n").slice(3, 6);
26
+ const callerInfo = caller || stackLines.map((l) => l.trim()).join(" <- ");
27
+ const entry = {
28
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
29
+ sessionName,
30
+ keysLength: keys.length,
31
+ keysPreview: keys.length > 200 ? keys.slice(0, 200) + "..." : keys,
32
+ caller: callerInfo,
33
+ pid: process.pid
34
+ };
35
+ appendFileSync(SENDKEYS_LOG_FILE, JSON.stringify(entry) + "\n", "utf-8");
36
+ } catch {
37
+ }
38
+ }
39
+ function listSessions() {
40
+ try {
41
+ const output = execSync('tmux list-sessions -F "#{session_name}|#{session_created}|#{session_attached}|#{session_windows}"', {
42
+ encoding: "utf8"
43
+ });
44
+ return output.trim().split("\n").filter(Boolean).map((line) => {
45
+ const [name, created, attached, windows] = line.split("|");
46
+ return {
47
+ name,
48
+ created: new Date(parseInt(created) * 1e3),
49
+ attached: attached === "1",
50
+ windows: parseInt(windows)
51
+ };
52
+ });
53
+ } catch {
54
+ return [];
55
+ }
56
+ }
57
+ function sessionExists(name) {
58
+ try {
59
+ execSync(`tmux has-session -t ${name} 2>/dev/null`);
60
+ return true;
61
+ } catch {
62
+ return false;
63
+ }
64
+ }
65
+ function createSession(name, cwd, initialCommand, options) {
66
+ const escapedCwd = cwd.replace(/"/g, '\\"');
67
+ let envFlags = "";
68
+ if (options?.env) {
69
+ for (const [key, value] of Object.entries(options.env)) {
70
+ envFlags += ` -e ${key}="${value.replace(/"/g, '\\"')}"`;
71
+ }
72
+ }
73
+ if (initialCommand && (initialCommand.includes("`") || initialCommand.includes("\n") || initialCommand.length > 500)) {
74
+ execSync(`tmux new-session -d -s ${name} -c "${escapedCwd}"${envFlags}`);
75
+ execSync("sleep 0.5");
76
+ const tmpFile = `/tmp/pan-cmd-${name}.sh`;
77
+ writeFileSync(tmpFile, initialCommand);
78
+ chmodSync(tmpFile, "755");
79
+ execSync(`tmux send-keys -t ${name} "bash ${tmpFile}"`);
80
+ execSync(`tmux send-keys -t ${name} C-m`);
81
+ } else if (initialCommand) {
82
+ const cmd = `tmux new-session -d -s ${name} -c "${escapedCwd}"${envFlags} "${initialCommand.replace(/"/g, '\\"')}"`;
83
+ execSync(cmd);
84
+ } else {
85
+ execSync(`tmux new-session -d -s ${name} -c "${escapedCwd}"${envFlags}`);
86
+ }
87
+ }
88
+ function killSession(name) {
89
+ execSync(`tmux kill-session -t ${name}`);
90
+ }
91
+ function sendKeys(sessionName, keys, caller) {
92
+ logSendKeys(sessionName, keys, caller);
93
+ const escapedKeys = keys.replace(/"/g, '\\"');
94
+ execSync(`tmux send-keys -t ${sessionName} "${escapedKeys}"`);
95
+ execSync(`tmux send-keys -t ${sessionName} C-m`);
96
+ }
97
+ function capturePane(sessionName, lines = 50) {
98
+ try {
99
+ return execSync(`tmux capture-pane -t ${sessionName} -p -S -${lines}`, {
100
+ encoding: "utf8"
101
+ });
102
+ } catch {
103
+ return "";
104
+ }
105
+ }
106
+ function getAgentSessions() {
107
+ return listSessions().filter((s) => s.name.startsWith("agent-"));
108
+ }
109
+ var SENDKEYS_LOG_FILE;
110
+ var init_tmux = __esm({
111
+ "src/lib/tmux.ts"() {
112
+ "use strict";
113
+ init_esm_shims();
114
+ init_paths();
115
+ SENDKEYS_LOG_FILE = join(PANOPTICON_HOME, "logs", "sendkeys.jsonl");
116
+ }
117
+ });
118
+
119
+ // src/lib/hooks.ts
120
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2, readdirSync, unlinkSync } from "fs";
121
+ import { join as join2 } from "path";
122
+ function getHookDir(agentId) {
123
+ return join2(AGENTS_DIR, agentId);
124
+ }
125
+ function getHookFile(agentId) {
126
+ return join2(getHookDir(agentId), "hook.json");
127
+ }
128
+ function getMailDir(agentId) {
129
+ return join2(getHookDir(agentId), "mail");
130
+ }
131
+ function initHook(agentId) {
132
+ const hookDir = getHookDir(agentId);
133
+ const mailDir = getMailDir(agentId);
134
+ mkdirSync2(hookDir, { recursive: true });
135
+ mkdirSync2(mailDir, { recursive: true });
136
+ const hookFile = getHookFile(agentId);
137
+ if (!existsSync2(hookFile)) {
138
+ const hook = {
139
+ agentId,
140
+ items: []
141
+ };
142
+ writeFileSync2(hookFile, JSON.stringify(hook, null, 2));
143
+ }
144
+ }
145
+ function getHook(agentId) {
146
+ const hookFile = getHookFile(agentId);
147
+ if (!existsSync2(hookFile)) {
148
+ return null;
149
+ }
150
+ try {
151
+ const content = readFileSync(hookFile, "utf-8");
152
+ return JSON.parse(content);
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+ function pushToHook(agentId, item) {
158
+ initHook(agentId);
159
+ const hook = getHook(agentId) || { agentId, items: [] };
160
+ const newItem = {
161
+ ...item,
162
+ id: `hook-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
163
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
164
+ };
165
+ hook.items.push(newItem);
166
+ writeFileSync2(getHookFile(agentId), JSON.stringify(hook, null, 2));
167
+ return newItem;
168
+ }
169
+ function checkHook(agentId) {
170
+ const hook = getHook(agentId);
171
+ if (!hook || hook.items.length === 0) {
172
+ const mailDir = getMailDir(agentId);
173
+ if (existsSync2(mailDir)) {
174
+ const mails = readdirSync(mailDir).filter((f) => f.endsWith(".json"));
175
+ if (mails.length > 0) {
176
+ const mailItems = mails.map((file) => {
177
+ try {
178
+ const content = readFileSync(join2(mailDir, file), "utf-8");
179
+ return JSON.parse(content);
180
+ } catch {
181
+ return null;
182
+ }
183
+ }).filter(Boolean);
184
+ return {
185
+ hasWork: mailItems.length > 0,
186
+ urgentCount: mailItems.filter((i) => i.priority === "urgent").length,
187
+ items: mailItems
188
+ };
189
+ }
190
+ }
191
+ return { hasWork: false, urgentCount: 0, items: [] };
192
+ }
193
+ const now = /* @__PURE__ */ new Date();
194
+ const activeItems = hook.items.filter((item) => {
195
+ if (item.expiresAt) {
196
+ return new Date(item.expiresAt) > now;
197
+ }
198
+ return true;
199
+ });
200
+ const priorityOrder = { urgent: 0, high: 1, normal: 2, low: 3 };
201
+ activeItems.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
202
+ return {
203
+ hasWork: activeItems.length > 0,
204
+ urgentCount: activeItems.filter((i) => i.priority === "urgent").length,
205
+ items: activeItems
206
+ };
207
+ }
208
+ function popFromHook(agentId, itemId) {
209
+ const hook = getHook(agentId);
210
+ if (!hook) return false;
211
+ const index = hook.items.findIndex((i) => i.id === itemId);
212
+ if (index === -1) return false;
213
+ hook.items.splice(index, 1);
214
+ hook.lastChecked = (/* @__PURE__ */ new Date()).toISOString();
215
+ writeFileSync2(getHookFile(agentId), JSON.stringify(hook, null, 2));
216
+ return true;
217
+ }
218
+ function clearHook(agentId) {
219
+ const hook = getHook(agentId);
220
+ if (!hook) return;
221
+ hook.items = [];
222
+ hook.lastChecked = (/* @__PURE__ */ new Date()).toISOString();
223
+ writeFileSync2(getHookFile(agentId), JSON.stringify(hook, null, 2));
224
+ }
225
+ function sendMail(toAgentId, from, message, priority = "normal") {
226
+ initHook(toAgentId);
227
+ const mailDir = getMailDir(toAgentId);
228
+ const mailItem = {
229
+ id: `mail-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
230
+ type: "message",
231
+ priority,
232
+ source: from,
233
+ payload: { message },
234
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
235
+ };
236
+ writeFileSync2(
237
+ join2(mailDir, `${mailItem.id}.json`),
238
+ JSON.stringify(mailItem, null, 2)
239
+ );
240
+ }
241
+ function generateFixedPointPrompt(agentId) {
242
+ const { hasWork, urgentCount, items } = checkHook(agentId);
243
+ if (!hasWork) return null;
244
+ const lines = [
245
+ "# FPP: Work Found on Your Hook",
246
+ "",
247
+ '> "Any runnable action is a fixed point and must resolve before the system can rest."',
248
+ ""
249
+ ];
250
+ if (urgentCount > 0) {
251
+ lines.push(`\u26A0\uFE0F **${urgentCount} URGENT item(s) require immediate attention**`);
252
+ lines.push("");
253
+ }
254
+ lines.push(`## Pending Work Items (${items.length})`);
255
+ lines.push("");
256
+ for (const item of items) {
257
+ const priorityEmoji = {
258
+ urgent: "\u{1F534}",
259
+ high: "\u{1F7E0}",
260
+ normal: "\u{1F7E2}",
261
+ low: "\u26AA"
262
+ }[item.priority];
263
+ lines.push(`### ${priorityEmoji} ${item.type.toUpperCase()}: ${item.id}`);
264
+ lines.push(`- Source: ${item.source}`);
265
+ lines.push(`- Created: ${item.createdAt}`);
266
+ if (item.payload.issueId) {
267
+ lines.push(`- Issue: ${item.payload.issueId}`);
268
+ }
269
+ if (item.payload.message) {
270
+ lines.push(`- Message: ${item.payload.message}`);
271
+ }
272
+ if (item.payload.action) {
273
+ lines.push(`- Action: ${item.payload.action}`);
274
+ }
275
+ lines.push("");
276
+ }
277
+ lines.push("---");
278
+ lines.push("");
279
+ lines.push("Execute these items in priority order. Use `bd hook pop <id>` after completing each item.");
280
+ return lines.join("\n");
281
+ }
282
+ var init_hooks = __esm({
283
+ "src/lib/hooks.ts"() {
284
+ "use strict";
285
+ init_esm_shims();
286
+ init_paths();
287
+ }
288
+ });
289
+
290
+ // src/lib/work-types.ts
291
+ function getAllWorkTypes() {
292
+ return Object.keys(WORK_TYPES);
293
+ }
294
+ function isValidWorkType(id) {
295
+ return id in WORK_TYPES;
296
+ }
297
+ function validateWorkType(id) {
298
+ if (!isValidWorkType(id)) {
299
+ throw new Error(
300
+ `Invalid work type ID: ${id}. Valid types: ${getAllWorkTypes().join(", ")}`
301
+ );
302
+ }
303
+ }
304
+ var WORK_TYPES;
305
+ var init_work_types = __esm({
306
+ "src/lib/work-types.ts"() {
307
+ "use strict";
308
+ init_esm_shims();
309
+ WORK_TYPES = {
310
+ // Issue agent phases (6)
311
+ "issue-agent:exploration": {
312
+ phase: "exploration",
313
+ category: "issue-agent",
314
+ description: "Exploring codebase and understanding requirements"
315
+ },
316
+ "issue-agent:planning": {
317
+ phase: "planning",
318
+ category: "issue-agent",
319
+ description: "Planning implementation approach and architecture"
320
+ },
321
+ "issue-agent:implementation": {
322
+ phase: "implementation",
323
+ category: "issue-agent",
324
+ description: "Writing code to implement features or fixes"
325
+ },
326
+ "issue-agent:testing": {
327
+ phase: "testing",
328
+ category: "issue-agent",
329
+ description: "Running tests and verifying functionality"
330
+ },
331
+ "issue-agent:documentation": {
332
+ phase: "documentation",
333
+ category: "issue-agent",
334
+ description: "Writing documentation and updating docs"
335
+ },
336
+ "issue-agent:review-response": {
337
+ phase: "review-response",
338
+ category: "issue-agent",
339
+ description: "Responding to code review feedback"
340
+ },
341
+ // Specialist agents (3)
342
+ "specialist-review-agent": {
343
+ category: "specialist",
344
+ description: "Comprehensive code review specialist"
345
+ },
346
+ "specialist-test-agent": {
347
+ category: "specialist",
348
+ description: "Test generation and verification specialist"
349
+ },
350
+ "specialist-merge-agent": {
351
+ category: "specialist",
352
+ description: "Merge request finalization specialist"
353
+ },
354
+ // Subagents (4)
355
+ "subagent:explore": {
356
+ category: "subagent",
357
+ description: "Fast codebase exploration subagent"
358
+ },
359
+ "subagent:plan": {
360
+ category: "subagent",
361
+ description: "Implementation planning subagent"
362
+ },
363
+ "subagent:bash": {
364
+ category: "subagent",
365
+ description: "Command execution specialist subagent"
366
+ },
367
+ "subagent:general-purpose": {
368
+ category: "subagent",
369
+ description: "General-purpose task subagent"
370
+ },
371
+ // Convoy members (4)
372
+ "convoy:security-reviewer": {
373
+ category: "convoy",
374
+ description: "Security-focused code reviewer in convoy"
375
+ },
376
+ "convoy:performance-reviewer": {
377
+ category: "convoy",
378
+ description: "Performance-focused code reviewer in convoy"
379
+ },
380
+ "convoy:correctness-reviewer": {
381
+ category: "convoy",
382
+ description: "Correctness-focused code reviewer in convoy"
383
+ },
384
+ "convoy:synthesis-agent": {
385
+ category: "convoy",
386
+ description: "Synthesizes findings from convoy reviewers"
387
+ },
388
+ // Pre-work agents (4)
389
+ "prd-agent": {
390
+ category: "pre-work",
391
+ description: "Generates Product Requirement Documents"
392
+ },
393
+ "decomposition-agent": {
394
+ category: "pre-work",
395
+ description: "Breaks down work into tasks"
396
+ },
397
+ "triage-agent": {
398
+ category: "pre-work",
399
+ description: "Prioritizes and triages issues"
400
+ },
401
+ "planning-agent": {
402
+ category: "pre-work",
403
+ description: "Explores and plans implementation approach"
404
+ },
405
+ // CLI contexts (2)
406
+ "cli:interactive": {
407
+ category: "cli",
408
+ description: "Interactive CLI session"
409
+ },
410
+ "cli:quick-command": {
411
+ category: "cli",
412
+ description: "Quick one-off CLI commands"
413
+ }
414
+ };
415
+ }
416
+ });
417
+
418
+ // src/lib/model-fallback.ts
419
+ function getModelProvider(modelId) {
420
+ return MODEL_PROVIDERS[modelId];
421
+ }
422
+ function getModelsByProvider(provider) {
423
+ return Object.entries(MODEL_PROVIDERS).filter(([_, p]) => p === provider).map(([modelId]) => modelId);
424
+ }
425
+ function isProviderEnabled(provider, enabledProviders) {
426
+ if (provider === "anthropic") return true;
427
+ return enabledProviders.has(provider);
428
+ }
429
+ function applyFallback(modelId, enabledProviders) {
430
+ const provider = getModelProvider(modelId);
431
+ if (isProviderEnabled(provider, enabledProviders)) {
432
+ return modelId;
433
+ }
434
+ const fallback = FALLBACK_MAP[modelId] || DEFAULT_FALLBACK;
435
+ console.warn(
436
+ `Model ${modelId} requires ${provider} API key - falling back to ${fallback}`
437
+ );
438
+ return fallback;
439
+ }
440
+ var MODEL_PROVIDERS, FALLBACK_MAP, DEFAULT_FALLBACK;
441
+ var init_model_fallback = __esm({
442
+ "src/lib/model-fallback.ts"() {
443
+ "use strict";
444
+ init_esm_shims();
445
+ MODEL_PROVIDERS = {
446
+ // Anthropic models
447
+ "claude-opus-4-6": "anthropic",
448
+ "claude-sonnet-4-5": "anthropic",
449
+ "claude-haiku-4-5": "anthropic",
450
+ // OpenAI models
451
+ "gpt-5.2-codex": "openai",
452
+ "o3-deep-research": "openai",
453
+ "gpt-4o": "openai",
454
+ "gpt-4o-mini": "openai",
455
+ // Google models
456
+ "gemini-3-pro-preview": "google",
457
+ "gemini-3-flash-preview": "google",
458
+ "gemini-2.5-pro": "google",
459
+ "gemini-2.5-flash": "google",
460
+ // Z.AI models
461
+ "glm-4.7": "zai",
462
+ "glm-4.7-flash": "zai",
463
+ // Kimi models
464
+ "kimi-k2": "kimi",
465
+ "kimi-k2.5": "kimi"
466
+ };
467
+ FALLBACK_MAP = {
468
+ // OpenAI → Anthropic
469
+ "gpt-5.2-codex": "claude-sonnet-4-5",
470
+ // Premium code model → Sonnet
471
+ "o3-deep-research": "claude-sonnet-4-5",
472
+ // Premium research model → Sonnet
473
+ "gpt-4o": "claude-sonnet-4-5",
474
+ // Flagship model → Sonnet
475
+ "gpt-4o-mini": "claude-haiku-4-5",
476
+ // Economy model → Haiku
477
+ // Google → Anthropic
478
+ "gemini-3-pro-preview": "claude-sonnet-4-5",
479
+ // Premium model → Sonnet
480
+ "gemini-3-flash-preview": "claude-haiku-4-5",
481
+ // Fast model → Haiku
482
+ // Z.AI → Anthropic
483
+ "glm-4.7": "claude-haiku-4-5",
484
+ // Standard model → Haiku
485
+ "glm-4.7-flash": "claude-haiku-4-5",
486
+ // Fast model → Haiku
487
+ // Kimi → Anthropic
488
+ "kimi-k2": "claude-sonnet-4-5",
489
+ // Good balance model → Sonnet
490
+ "kimi-k2.5": "claude-sonnet-4-5"
491
+ // Premium model → Sonnet
492
+ };
493
+ DEFAULT_FALLBACK = "claude-sonnet-4-5";
494
+ }
495
+ });
496
+
497
+ // src/lib/config-yaml.ts
498
+ import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
499
+ import { join as join3 } from "path";
500
+ import { homedir } from "os";
501
+ import yaml from "js-yaml";
502
+ function normalizeProviderConfig(providerConfig, fallbackKey) {
503
+ if (providerConfig === void 0) {
504
+ return { enabled: false };
505
+ }
506
+ if (typeof providerConfig === "boolean") {
507
+ return { enabled: providerConfig, api_key: fallbackKey };
508
+ }
509
+ return {
510
+ enabled: providerConfig.enabled,
511
+ api_key: providerConfig.api_key || fallbackKey
512
+ };
513
+ }
514
+ function resolveEnvVar(value) {
515
+ if (!value) return void 0;
516
+ return value.replace(/\$\{?([A-Z_][A-Z0-9_]*)\}?/g, (match, varName) => {
517
+ const envValue = process.env[varName];
518
+ return envValue !== void 0 ? envValue : match;
519
+ });
520
+ }
521
+ function loadYamlFile(filePath) {
522
+ if (!existsSync3(filePath)) {
523
+ return null;
524
+ }
525
+ try {
526
+ const content = readFileSync2(filePath, "utf-8");
527
+ const parsed = yaml.load(content);
528
+ return parsed || {};
529
+ } catch (error) {
530
+ console.error(`Error loading YAML config from ${filePath}:`, error);
531
+ return null;
532
+ }
533
+ }
534
+ function findProjectRoot(startDir = process.cwd()) {
535
+ let currentDir = startDir;
536
+ while (currentDir !== "/") {
537
+ if (existsSync3(join3(currentDir, ".git"))) {
538
+ return currentDir;
539
+ }
540
+ currentDir = join3(currentDir, "..");
541
+ }
542
+ return null;
543
+ }
544
+ function loadProjectConfig() {
545
+ const projectRoot = findProjectRoot();
546
+ if (!projectRoot) {
547
+ return null;
548
+ }
549
+ const projectConfigPath = join3(projectRoot, ".panopticon.yaml");
550
+ return loadYamlFile(projectConfigPath);
551
+ }
552
+ function loadGlobalConfig() {
553
+ return loadYamlFile(GLOBAL_CONFIG_PATH);
554
+ }
555
+ function mergeShadowConfig(result, config) {
556
+ if (!config?.shadow) return;
557
+ if (config.shadow.enabled !== void 0) {
558
+ result.enabled = config.shadow.enabled;
559
+ }
560
+ if (config.shadow.trackers) {
561
+ if (config.shadow.trackers.linear !== void 0) {
562
+ result.trackers.linear = config.shadow.trackers.linear;
563
+ }
564
+ if (config.shadow.trackers.github !== void 0) {
565
+ result.trackers.github = config.shadow.trackers.github;
566
+ }
567
+ if (config.shadow.trackers.gitlab !== void 0) {
568
+ result.trackers.gitlab = config.shadow.trackers.gitlab;
569
+ }
570
+ if (config.shadow.trackers.rally !== void 0) {
571
+ result.trackers.rally = config.shadow.trackers.rally;
572
+ }
573
+ }
574
+ }
575
+ function mergeConfigs(...configs) {
576
+ const result = {
577
+ ...DEFAULT_CONFIG,
578
+ enabledProviders: new Set(DEFAULT_CONFIG.enabledProviders),
579
+ shadow: {
580
+ enabled: DEFAULT_CONFIG.shadow.enabled,
581
+ trackers: { ...DEFAULT_CONFIG.shadow.trackers }
582
+ }
583
+ };
584
+ const validConfigs = configs.filter((c) => c !== null);
585
+ for (const config of validConfigs.reverse()) {
586
+ if (config.models?.providers) {
587
+ const providers = config.models.providers;
588
+ const legacyKeys = config.api_keys || {};
589
+ result.enabledProviders.add("anthropic");
590
+ const openai = normalizeProviderConfig(providers.openai, legacyKeys.openai);
591
+ if (openai.enabled) {
592
+ result.enabledProviders.add("openai");
593
+ if (openai.api_key) {
594
+ result.apiKeys.openai = resolveEnvVar(openai.api_key);
595
+ }
596
+ }
597
+ const google = normalizeProviderConfig(providers.google, legacyKeys.google);
598
+ if (google.enabled) {
599
+ result.enabledProviders.add("google");
600
+ if (google.api_key) {
601
+ result.apiKeys.google = resolveEnvVar(google.api_key);
602
+ }
603
+ }
604
+ const zai = normalizeProviderConfig(providers.zai, legacyKeys.zai);
605
+ if (zai.enabled) {
606
+ result.enabledProviders.add("zai");
607
+ if (zai.api_key) {
608
+ result.apiKeys.zai = resolveEnvVar(zai.api_key);
609
+ }
610
+ }
611
+ const kimi = normalizeProviderConfig(providers.kimi, legacyKeys.kimi);
612
+ if (kimi.enabled) {
613
+ result.enabledProviders.add("kimi");
614
+ if (kimi.api_key) {
615
+ result.apiKeys.kimi = resolveEnvVar(kimi.api_key);
616
+ }
617
+ }
618
+ }
619
+ if (config.api_keys) {
620
+ if (config.api_keys.openai) {
621
+ result.apiKeys.openai = resolveEnvVar(config.api_keys.openai);
622
+ result.enabledProviders.add("openai");
623
+ }
624
+ if (config.api_keys.google) {
625
+ result.apiKeys.google = resolveEnvVar(config.api_keys.google);
626
+ result.enabledProviders.add("google");
627
+ }
628
+ if (config.api_keys.zai) {
629
+ result.apiKeys.zai = resolveEnvVar(config.api_keys.zai);
630
+ result.enabledProviders.add("zai");
631
+ }
632
+ if (config.api_keys.kimi) {
633
+ result.apiKeys.kimi = resolveEnvVar(config.api_keys.kimi);
634
+ result.enabledProviders.add("kimi");
635
+ }
636
+ }
637
+ if (config.models?.overrides) {
638
+ result.overrides = {
639
+ ...result.overrides,
640
+ ...config.models.overrides
641
+ };
642
+ }
643
+ if (config.models?.gemini_thinking_level) {
644
+ result.geminiThinkingLevel = config.models.gemini_thinking_level;
645
+ }
646
+ mergeShadowConfig(result.shadow, config);
647
+ }
648
+ return result;
649
+ }
650
+ function loadConfig() {
651
+ const globalConfig = loadGlobalConfig();
652
+ const projectConfig = loadProjectConfig();
653
+ const config = mergeConfigs(projectConfig, globalConfig);
654
+ if (process.env.OPENAI_API_KEY && !config.apiKeys.openai) {
655
+ config.apiKeys.openai = process.env.OPENAI_API_KEY;
656
+ config.enabledProviders.add("openai");
657
+ }
658
+ if (process.env.GOOGLE_API_KEY && !config.apiKeys.google) {
659
+ config.apiKeys.google = process.env.GOOGLE_API_KEY;
660
+ config.enabledProviders.add("google");
661
+ }
662
+ if (process.env.ZAI_API_KEY && !config.apiKeys.zai) {
663
+ config.apiKeys.zai = process.env.ZAI_API_KEY;
664
+ config.enabledProviders.add("zai");
665
+ }
666
+ if (process.env.KIMI_API_KEY && !config.apiKeys.kimi) {
667
+ config.apiKeys.kimi = process.env.KIMI_API_KEY;
668
+ config.enabledProviders.add("kimi");
669
+ }
670
+ if (process.env.SHADOW_MODE !== void 0) {
671
+ const envShadowMode = ["true", "1", "yes"].includes(process.env.SHADOW_MODE.toLowerCase());
672
+ config.shadow.enabled = envShadowMode;
673
+ }
674
+ return config;
675
+ }
676
+ var DEFAULT_CONFIG, GLOBAL_CONFIG_PATH;
677
+ var init_config_yaml = __esm({
678
+ "src/lib/config-yaml.ts"() {
679
+ "use strict";
680
+ init_esm_shims();
681
+ DEFAULT_CONFIG = {
682
+ enabledProviders: /* @__PURE__ */ new Set(["anthropic"]),
683
+ // Only Anthropic by default
684
+ apiKeys: {},
685
+ overrides: {},
686
+ geminiThinkingLevel: 3,
687
+ shadow: {
688
+ enabled: false,
689
+ trackers: {
690
+ linear: false,
691
+ github: false,
692
+ gitlab: false,
693
+ rally: false
694
+ }
695
+ }
696
+ };
697
+ GLOBAL_CONFIG_PATH = join3(homedir(), ".panopticon", "config.yaml");
698
+ }
699
+ });
700
+
701
+ // src/lib/model-capabilities.ts
702
+ function getModelCapability(model) {
703
+ return MODEL_CAPABILITIES[model];
704
+ }
705
+ var MODEL_CAPABILITIES;
706
+ var init_model_capabilities = __esm({
707
+ "src/lib/model-capabilities.ts"() {
708
+ "use strict";
709
+ init_esm_shims();
710
+ MODEL_CAPABILITIES = {
711
+ // ═══════════════════════════════════════════════════════════════════════════
712
+ // ANTHROPIC MODELS
713
+ // ═══════════════════════════════════════════════════════════════════════════
714
+ "claude-opus-4-6": {
715
+ model: "claude-opus-4-6",
716
+ provider: "anthropic",
717
+ displayName: "Claude Opus 4.6",
718
+ costPer1MTokens: 45,
719
+ // $5 in / $25 out → same pricing as 4.5
720
+ contextWindow: 2e5,
721
+ // 1M available via opt-in beta, but we use 200K
722
+ skills: {
723
+ "code-generation": 96,
724
+ // 80.9% SWE-bench (first >80%), 89.4% Aider Polyglot
725
+ "code-review": 98,
726
+ debugging: 97,
727
+ planning: 99,
728
+ // User confirms: "Opus 4.6 planning for sure"
729
+ documentation: 95,
730
+ testing: 92,
731
+ security: 98,
732
+ // Best for security review
733
+ performance: 90,
734
+ synthesis: 98,
735
+ // Best for combining info across domains
736
+ speed: 40,
737
+ // Slower but 76% more token efficient
738
+ "context-length": 95
739
+ },
740
+ notes: "Successor to Opus 4.5. Same pricing, 1M context available (opt-in beta). Best for planning, security, complex reasoning."
741
+ },
742
+ "claude-sonnet-4-5": {
743
+ model: "claude-sonnet-4-5",
744
+ provider: "anthropic",
745
+ displayName: "Claude Sonnet 4.5",
746
+ costPer1MTokens: 9,
747
+ // $3 in / $15 out → avg ~$9
748
+ contextWindow: 2e5,
749
+ skills: {
750
+ "code-generation": 92,
751
+ // 77.2% SWE-bench (82% parallel), beats GPT-5 Codex (74.5%)
752
+ "code-review": 92,
753
+ debugging: 90,
754
+ planning: 88,
755
+ documentation: 90,
756
+ // 100% AIME with Python
757
+ testing: 90,
758
+ // 50% Terminal-Bench, 61.4% OSWorld
759
+ security: 85,
760
+ performance: 85,
761
+ synthesis: 88,
762
+ speed: 70,
763
+ "context-length": 95
764
+ },
765
+ notes: "Best value: 77.2% SWE-bench at 1/5th Opus cost. Beats GPT-5 Codex."
766
+ },
767
+ "claude-haiku-4-5": {
768
+ model: "claude-haiku-4-5",
769
+ provider: "anthropic",
770
+ displayName: "Claude Haiku 4.5",
771
+ costPer1MTokens: 4,
772
+ // $0.80 in / $4 out → avg ~$2.4
773
+ contextWindow: 2e5,
774
+ skills: {
775
+ "code-generation": 75,
776
+ "code-review": 72,
777
+ debugging: 70,
778
+ planning: 65,
779
+ documentation: 75,
780
+ testing: 70,
781
+ security: 60,
782
+ performance: 65,
783
+ synthesis: 68,
784
+ speed: 95,
785
+ // Fastest Anthropic
786
+ "context-length": 95
787
+ },
788
+ notes: "Fast and cheap, good for simple tasks and exploration"
789
+ },
790
+ // ═══════════════════════════════════════════════════════════════════════════
791
+ // OPENAI MODELS
792
+ // ═══════════════════════════════════════════════════════════════════════════
793
+ "gpt-5.2-codex": {
794
+ model: "gpt-5.2-codex",
795
+ provider: "openai",
796
+ displayName: "GPT-5.2 Codex",
797
+ costPer1MTokens: 75,
798
+ // Premium tier ~$75/M
799
+ contextWindow: 128e3,
800
+ skills: {
801
+ "code-generation": 95,
802
+ // 80% SWE-bench Verified, 55.6% SWE-bench Pro
803
+ "code-review": 90,
804
+ debugging: 92,
805
+ // 92.4% GPQA Diamond
806
+ planning: 88,
807
+ documentation: 85,
808
+ testing: 90,
809
+ security: 85,
810
+ performance: 88,
811
+ // 52.9% ARC-AGI-2 (best reasoning)
812
+ synthesis: 88,
813
+ // 100% AIME 2025 without tools
814
+ speed: 55,
815
+ "context-length": 75
816
+ },
817
+ notes: "Premium coding: 80% SWE-bench. Best raw reasoning (52.9% ARC-AGI-2). Expensive."
818
+ },
819
+ "o3-deep-research": {
820
+ model: "o3-deep-research",
821
+ provider: "openai",
822
+ displayName: "O3 Deep Research",
823
+ costPer1MTokens: 100,
824
+ // Expensive reasoning model
825
+ contextWindow: 2e5,
826
+ skills: {
827
+ "code-generation": 85,
828
+ "code-review": 95,
829
+ debugging: 98,
830
+ // Best for debugging
831
+ planning: 95,
832
+ documentation: 88,
833
+ testing: 85,
834
+ security: 92,
835
+ performance: 92,
836
+ synthesis: 95,
837
+ speed: 20,
838
+ // Very slow (reasoning chains)
839
+ "context-length": 95
840
+ },
841
+ notes: "Deep reasoning model, excellent for complex debugging and analysis"
842
+ },
843
+ "gpt-4o": {
844
+ model: "gpt-4o",
845
+ provider: "openai",
846
+ displayName: "GPT-4o",
847
+ costPer1MTokens: 15,
848
+ // $5 in / $15 out
849
+ contextWindow: 128e3,
850
+ skills: {
851
+ "code-generation": 88,
852
+ "code-review": 85,
853
+ debugging: 85,
854
+ planning: 82,
855
+ documentation: 88,
856
+ testing: 82,
857
+ security: 78,
858
+ performance: 80,
859
+ synthesis: 85,
860
+ speed: 75,
861
+ "context-length": 75
862
+ },
863
+ notes: "Good all-rounder, competitive with Sonnet"
864
+ },
865
+ "gpt-4o-mini": {
866
+ model: "gpt-4o-mini",
867
+ provider: "openai",
868
+ displayName: "GPT-4o Mini",
869
+ costPer1MTokens: 1,
870
+ // Very cheap
871
+ contextWindow: 128e3,
872
+ skills: {
873
+ "code-generation": 72,
874
+ "code-review": 68,
875
+ debugging: 65,
876
+ planning: 60,
877
+ documentation: 70,
878
+ testing: 65,
879
+ security: 55,
880
+ performance: 60,
881
+ synthesis: 62,
882
+ speed: 92,
883
+ "context-length": 75
884
+ },
885
+ notes: "Budget option, good for simple tasks"
886
+ },
887
+ // ═══════════════════════════════════════════════════════════════════════════
888
+ // GOOGLE MODELS
889
+ // ═══════════════════════════════════════════════════════════════════════════
890
+ "gemini-3-pro-preview": {
891
+ model: "gemini-3-pro-preview",
892
+ provider: "google",
893
+ displayName: "Gemini 3 Pro",
894
+ costPer1MTokens: 12,
895
+ // $4.2 in / $18.9 out
896
+ contextWindow: 1e6,
897
+ // 1M context!
898
+ skills: {
899
+ "code-generation": 90,
900
+ // 2439 Elo LiveCodeBench Pro (first >1500 on LMArena)
901
+ "code-review": 88,
902
+ debugging: 85,
903
+ planning: 85,
904
+ documentation: 88,
905
+ testing: 85,
906
+ // ~95% AIME 2025
907
+ security: 78,
908
+ performance: 85,
909
+ // Strong multimodal
910
+ synthesis: 90,
911
+ // Best for combining large codebases
912
+ speed: 80,
913
+ "context-length": 100
914
+ // Best context - 1M tokens
915
+ },
916
+ notes: "First to exceed 1500 Elo on LMArena. Best for large codebase analysis with 1M context."
917
+ },
918
+ "gemini-3-flash-preview": {
919
+ model: "gemini-3-flash-preview",
920
+ provider: "google",
921
+ displayName: "Gemini 3 Flash",
922
+ costPer1MTokens: 0.5,
923
+ // Very cheap
924
+ contextWindow: 1e6,
925
+ skills: {
926
+ "code-generation": 75,
927
+ "code-review": 70,
928
+ debugging: 68,
929
+ planning: 62,
930
+ documentation: 72,
931
+ testing: 68,
932
+ security: 55,
933
+ performance: 65,
934
+ synthesis: 70,
935
+ speed: 98,
936
+ // Fastest overall
937
+ "context-length": 100
938
+ },
939
+ notes: "Extremely fast and cheap, huge context, great for exploration"
940
+ },
941
+ "gemini-2.5-pro": {
942
+ model: "gemini-2.5-pro",
943
+ provider: "google",
944
+ displayName: "Gemini 2.5 Pro",
945
+ costPer1MTokens: 12,
946
+ contextWindow: 1e6,
947
+ skills: {
948
+ "code-generation": 92,
949
+ "code-review": 90,
950
+ debugging: 88,
951
+ planning: 88,
952
+ documentation: 90,
953
+ testing: 87,
954
+ security: 82,
955
+ performance: 88,
956
+ synthesis: 92,
957
+ speed: 75,
958
+ "context-length": 100
959
+ },
960
+ notes: "Advanced reasoning and code capabilities with 1M context"
961
+ },
962
+ "gemini-2.5-flash": {
963
+ model: "gemini-2.5-flash",
964
+ provider: "google",
965
+ displayName: "Gemini 2.5 Flash",
966
+ costPer1MTokens: 0.6,
967
+ contextWindow: 1e6,
968
+ skills: {
969
+ "code-generation": 78,
970
+ "code-review": 73,
971
+ debugging: 70,
972
+ planning: 65,
973
+ documentation: 75,
974
+ testing: 70,
975
+ security: 58,
976
+ performance: 68,
977
+ synthesis: 73,
978
+ speed: 95,
979
+ "context-length": 100
980
+ },
981
+ notes: "Fast and efficient with large context support"
982
+ },
983
+ // ═══════════════════════════════════════════════════════════════════════════
984
+ // Z.AI MODELS
985
+ // ═══════════════════════════════════════════════════════════════════════════
986
+ "glm-4.7": {
987
+ model: "glm-4.7",
988
+ provider: "zai",
989
+ displayName: "GLM 4.7",
990
+ costPer1MTokens: 5,
991
+ contextWindow: 2e5,
992
+ // 200K context, 128K output
993
+ skills: {
994
+ "code-generation": 88,
995
+ // 73.8% SWE-bench, 84.9 LiveCodeBench v6 (open-source SOTA)
996
+ "code-review": 85,
997
+ debugging: 85,
998
+ // Strong debugging with Interleaved Thinking
999
+ planning: 82,
1000
+ // 95.7% AIME 2025 (beats Gemini 3 & GPT-5.1)
1001
+ documentation: 80,
1002
+ testing: 82,
1003
+ // 87.4 τ²-Bench (SOTA for tool use)
1004
+ security: 72,
1005
+ performance: 78,
1006
+ synthesis: 85,
1007
+ // Preserved Thinking retains context across turns
1008
+ speed: 80,
1009
+ "context-length": 95
1010
+ // 200K context
1011
+ },
1012
+ notes: "Top open-source for agentic coding. 73.8% SWE-bench, best tool use. 400B params with Interleaved Thinking."
1013
+ },
1014
+ "glm-4.7-flash": {
1015
+ model: "glm-4.7-flash",
1016
+ provider: "zai",
1017
+ displayName: "GLM 4.7 Flash",
1018
+ costPer1MTokens: 1.5,
1019
+ contextWindow: 128e3,
1020
+ skills: {
1021
+ "code-generation": 72,
1022
+ "code-review": 68,
1023
+ debugging: 65,
1024
+ planning: 62,
1025
+ documentation: 70,
1026
+ testing: 65,
1027
+ security: 55,
1028
+ performance: 62,
1029
+ synthesis: 65,
1030
+ speed: 92,
1031
+ // Fast inference
1032
+ "context-length": 75
1033
+ },
1034
+ notes: "Fast and affordable. Good for quick iterations and exploration."
1035
+ },
1036
+ // ═══════════════════════════════════════════════════════════════════════════
1037
+ // KIMI MODELS
1038
+ // ═══════════════════════════════════════════════════════════════════════════
1039
+ "kimi-k2": {
1040
+ model: "kimi-k2",
1041
+ provider: "kimi",
1042
+ displayName: "Kimi K2",
1043
+ costPer1MTokens: 1.4,
1044
+ // $0.16 in / $2.63 out → very cheap
1045
+ contextWindow: 131e3,
1046
+ skills: {
1047
+ "code-generation": 82,
1048
+ // 65.8% SWE-bench (beats GPT-4.1 at 54.6%)
1049
+ "code-review": 80,
1050
+ debugging: 78,
1051
+ planning: 75,
1052
+ documentation: 80,
1053
+ testing: 75,
1054
+ security: 70,
1055
+ performance: 72,
1056
+ synthesis: 78,
1057
+ speed: 80,
1058
+ "context-length": 75
1059
+ },
1060
+ notes: "Strong value: 65.8% SWE-bench at very low cost. Good for routine tasks."
1061
+ },
1062
+ "kimi-k2.5": {
1063
+ model: "kimi-k2.5",
1064
+ provider: "kimi",
1065
+ displayName: "Kimi K2.5",
1066
+ costPer1MTokens: 8,
1067
+ // ~5.1x cheaper than GPT-5.2
1068
+ contextWindow: 256e3,
1069
+ skills: {
1070
+ "code-generation": 92,
1071
+ // 76.8% SWE-bench, 85 LiveCodeBench v6
1072
+ "code-review": 90,
1073
+ debugging: 90,
1074
+ // Strong analytical capabilities
1075
+ planning: 88,
1076
+ // User confirms "highly capable"
1077
+ documentation: 88,
1078
+ testing: 88,
1079
+ // 92% coding accuracy
1080
+ security: 82,
1081
+ performance: 85,
1082
+ synthesis: 92,
1083
+ // Can coordinate 100 sub-agents, 1500 tool calls
1084
+ speed: 75,
1085
+ // MoE: 1T total params, 32B active
1086
+ "context-length": 98
1087
+ // 256K context
1088
+ },
1089
+ notes: "Best open-source coding model. 5x cheaper than GPT-5.2. Excellent for frontend dev and multi-agent orchestration."
1090
+ }
1091
+ };
1092
+ }
1093
+ });
1094
+
1095
+ // src/lib/smart-model-selector.ts
1096
+ function calculateSkillScore(model, requirements) {
1097
+ const cap = getModelCapability(model);
1098
+ let totalScore = 0;
1099
+ let totalWeight = 0;
1100
+ for (const req of requirements) {
1101
+ totalScore += cap.skills[req.skill] * req.weight;
1102
+ totalWeight += req.weight;
1103
+ }
1104
+ return totalWeight > 0 ? totalScore / totalWeight : 0;
1105
+ }
1106
+ function calculateSelectionScore(model, skillScore) {
1107
+ return skillScore;
1108
+ }
1109
+ function selectModel(workType, availableModels, options = {}) {
1110
+ const { minCapability = 50, forceModel } = options;
1111
+ if (forceModel) {
1112
+ if (availableModels.includes(forceModel)) {
1113
+ return {
1114
+ model: forceModel,
1115
+ score: 100,
1116
+ reason: `Forced selection: ${forceModel}`,
1117
+ candidates: [{ model: forceModel, score: 100, available: true }]
1118
+ };
1119
+ }
1120
+ }
1121
+ const requirements = WORK_TYPE_REQUIREMENTS[workType];
1122
+ const allModels = Object.keys(MODEL_CAPABILITIES);
1123
+ const candidates = allModels.map((model) => {
1124
+ const skillScore = calculateSkillScore(model, requirements);
1125
+ const selectionScore = calculateSelectionScore(model, skillScore);
1126
+ const available = availableModels.includes(model);
1127
+ return {
1128
+ model,
1129
+ skillScore,
1130
+ score: selectionScore,
1131
+ available
1132
+ };
1133
+ });
1134
+ const eligible = candidates.filter(
1135
+ (c) => c.available && c.skillScore >= minCapability
1136
+ );
1137
+ eligible.sort((a, b) => b.score - a.score);
1138
+ if (eligible.length === 0) {
1139
+ const fallback = candidates.filter((c) => c.available).sort((a, b) => b.score - a.score)[0];
1140
+ if (!fallback) {
1141
+ return {
1142
+ model: "claude-sonnet-4-5",
1143
+ score: 0,
1144
+ reason: "No models available, falling back to default",
1145
+ candidates: candidates.map((c) => ({
1146
+ model: c.model,
1147
+ score: c.score,
1148
+ available: c.available
1149
+ }))
1150
+ };
1151
+ }
1152
+ return {
1153
+ model: fallback.model,
1154
+ score: fallback.score,
1155
+ reason: `Best available (below min threshold): ${fallback.model}`,
1156
+ candidates: candidates.map((c) => ({
1157
+ model: c.model,
1158
+ score: c.score,
1159
+ available: c.available
1160
+ }))
1161
+ };
1162
+ }
1163
+ const selected = eligible[0];
1164
+ const cap = getModelCapability(selected.model);
1165
+ const topSkills = requirements.sort((a, b) => b.weight - a.weight).slice(0, 2).map((r) => r.skill);
1166
+ const reason = `Best for ${workType}: ${cap.displayName} (${topSkills.join(", ")}: ${Math.round(selected.skillScore)}, cost: $${cap.costPer1MTokens}/1M)`;
1167
+ return {
1168
+ model: selected.model,
1169
+ score: selected.score,
1170
+ reason,
1171
+ candidates: candidates.map((c) => ({
1172
+ model: c.model,
1173
+ score: c.score,
1174
+ available: c.available
1175
+ }))
1176
+ };
1177
+ }
1178
+ var WORK_TYPE_REQUIREMENTS;
1179
+ var init_smart_model_selector = __esm({
1180
+ "src/lib/smart-model-selector.ts"() {
1181
+ "use strict";
1182
+ init_esm_shims();
1183
+ init_model_capabilities();
1184
+ WORK_TYPE_REQUIREMENTS = {
1185
+ // ═══════════════════════════════════════════════════════════════════════════
1186
+ // ISSUE AGENT PHASES
1187
+ // ═══════════════════════════════════════════════════════════════════════════
1188
+ "issue-agent:exploration": [
1189
+ { skill: "speed", weight: 0.4 },
1190
+ // Need fast exploration
1191
+ { skill: "context-length", weight: 0.3 },
1192
+ // Large codebases
1193
+ { skill: "synthesis", weight: 0.3 }
1194
+ // Understanding structure
1195
+ ],
1196
+ "issue-agent:planning": [
1197
+ { skill: "planning", weight: 0.5 },
1198
+ // Primary skill
1199
+ { skill: "code-review", weight: 0.2 },
1200
+ // Understanding existing code
1201
+ { skill: "synthesis", weight: 0.3 }
1202
+ // Combining requirements
1203
+ ],
1204
+ "issue-agent:implementation": [
1205
+ { skill: "code-generation", weight: 0.6 },
1206
+ // Primary skill
1207
+ { skill: "debugging", weight: 0.2 },
1208
+ // Avoiding bugs
1209
+ { skill: "testing", weight: 0.2 }
1210
+ // Writing testable code
1211
+ ],
1212
+ "issue-agent:testing": [
1213
+ { skill: "testing", weight: 0.5 },
1214
+ // Primary skill
1215
+ { skill: "code-generation", weight: 0.3 },
1216
+ // Writing test code
1217
+ { skill: "debugging", weight: 0.2 }
1218
+ // Finding edge cases
1219
+ ],
1220
+ "issue-agent:documentation": [
1221
+ { skill: "documentation", weight: 0.6 },
1222
+ // Primary skill
1223
+ { skill: "synthesis", weight: 0.3 },
1224
+ // Summarizing
1225
+ { skill: "speed", weight: 0.1 }
1226
+ // Fast iteration
1227
+ ],
1228
+ "issue-agent:review-response": [
1229
+ { skill: "code-review", weight: 0.4 },
1230
+ // Understanding feedback
1231
+ { skill: "code-generation", weight: 0.3 },
1232
+ // Making fixes
1233
+ { skill: "debugging", weight: 0.3 }
1234
+ // Finding issues
1235
+ ],
1236
+ // ═══════════════════════════════════════════════════════════════════════════
1237
+ // SPECIALIST AGENTS
1238
+ // ═══════════════════════════════════════════════════════════════════════════
1239
+ "specialist-review-agent": [
1240
+ { skill: "code-review", weight: 0.5 },
1241
+ // Primary skill
1242
+ { skill: "security", weight: 0.25 },
1243
+ // Security awareness
1244
+ { skill: "performance", weight: 0.25 }
1245
+ // Performance awareness
1246
+ ],
1247
+ "specialist-test-agent": [
1248
+ { skill: "testing", weight: 0.5 },
1249
+ // Primary skill
1250
+ { skill: "code-generation", weight: 0.3 },
1251
+ // Writing tests
1252
+ { skill: "debugging", weight: 0.2 }
1253
+ // Finding issues
1254
+ ],
1255
+ "specialist-merge-agent": [
1256
+ { skill: "code-review", weight: 0.4 },
1257
+ // Understanding conflicts
1258
+ { skill: "synthesis", weight: 0.3 },
1259
+ // Merging changes
1260
+ { skill: "debugging", weight: 0.3 }
1261
+ // Resolving issues
1262
+ ],
1263
+ // ═══════════════════════════════════════════════════════════════════════════
1264
+ // SUBAGENTS
1265
+ // ═══════════════════════════════════════════════════════════════════════════
1266
+ "subagent:explore": [
1267
+ { skill: "speed", weight: 0.5 },
1268
+ // Need speed
1269
+ { skill: "context-length", weight: 0.3 },
1270
+ // Large scope
1271
+ { skill: "synthesis", weight: 0.2 }
1272
+ // Quick understanding
1273
+ ],
1274
+ "subagent:plan": [
1275
+ { skill: "planning", weight: 0.5 },
1276
+ // Primary skill
1277
+ { skill: "synthesis", weight: 0.3 },
1278
+ // Combining info
1279
+ { skill: "speed", weight: 0.2 }
1280
+ // Quick iteration
1281
+ ],
1282
+ "subagent:bash": [
1283
+ { skill: "speed", weight: 0.6 },
1284
+ // Fast execution
1285
+ { skill: "code-generation", weight: 0.3 },
1286
+ // Command generation
1287
+ { skill: "debugging", weight: 0.1 }
1288
+ // Error handling
1289
+ ],
1290
+ "subagent:general-purpose": [
1291
+ { skill: "speed", weight: 0.3 },
1292
+ // Balanced
1293
+ { skill: "synthesis", weight: 0.3 },
1294
+ // General understanding
1295
+ { skill: "code-generation", weight: 0.4 }
1296
+ // General tasks
1297
+ ],
1298
+ // ═══════════════════════════════════════════════════════════════════════════
1299
+ // CONVOY MEMBERS
1300
+ // ═══════════════════════════════════════════════════════════════════════════
1301
+ "convoy:security-reviewer": [
1302
+ { skill: "security", weight: 0.7 },
1303
+ // PRIMARY - never compromise
1304
+ { skill: "code-review", weight: 0.2 },
1305
+ // Code understanding
1306
+ { skill: "debugging", weight: 0.1 }
1307
+ // Finding vulnerabilities
1308
+ ],
1309
+ "convoy:performance-reviewer": [
1310
+ { skill: "performance", weight: 0.6 },
1311
+ // Primary skill
1312
+ { skill: "code-review", weight: 0.3 },
1313
+ // Code understanding
1314
+ { skill: "debugging", weight: 0.1 }
1315
+ // Finding bottlenecks
1316
+ ],
1317
+ "convoy:correctness-reviewer": [
1318
+ { skill: "code-review", weight: 0.4 },
1319
+ // Primary skill
1320
+ { skill: "debugging", weight: 0.4 },
1321
+ // Finding bugs
1322
+ { skill: "testing", weight: 0.2 }
1323
+ // Test coverage
1324
+ ],
1325
+ "convoy:synthesis-agent": [
1326
+ { skill: "synthesis", weight: 0.6 },
1327
+ // Primary skill
1328
+ { skill: "documentation", weight: 0.2 },
1329
+ // Clear writing
1330
+ { skill: "planning", weight: 0.2 }
1331
+ // Organizing findings
1332
+ ],
1333
+ // ═══════════════════════════════════════════════════════════════════════════
1334
+ // PRE-WORK AGENTS
1335
+ // ═══════════════════════════════════════════════════════════════════════════
1336
+ "prd-agent": [
1337
+ { skill: "documentation", weight: 0.5 },
1338
+ // Primary skill
1339
+ { skill: "planning", weight: 0.3 },
1340
+ // Structure
1341
+ { skill: "synthesis", weight: 0.2 }
1342
+ // Combining requirements
1343
+ ],
1344
+ "decomposition-agent": [
1345
+ { skill: "planning", weight: 0.5 },
1346
+ // Primary skill
1347
+ { skill: "synthesis", weight: 0.3 },
1348
+ // Breaking down
1349
+ { skill: "documentation", weight: 0.2 }
1350
+ // Clear tasks
1351
+ ],
1352
+ "triage-agent": [
1353
+ { skill: "speed", weight: 0.4 },
1354
+ // Quick decisions
1355
+ { skill: "synthesis", weight: 0.3 },
1356
+ // Understanding scope
1357
+ { skill: "planning", weight: 0.3 }
1358
+ // Prioritization
1359
+ ],
1360
+ "planning-agent": [
1361
+ { skill: "planning", weight: 0.5 },
1362
+ // Primary skill
1363
+ { skill: "code-review", weight: 0.3 },
1364
+ // Understanding codebase
1365
+ { skill: "synthesis", weight: 0.2 }
1366
+ // Combining approaches
1367
+ ],
1368
+ // ═══════════════════════════════════════════════════════════════════════════
1369
+ // CLI CONTEXTS
1370
+ // ═══════════════════════════════════════════════════════════════════════════
1371
+ "cli:interactive": [
1372
+ { skill: "speed", weight: 0.4 },
1373
+ // Responsive
1374
+ { skill: "synthesis", weight: 0.3 },
1375
+ // Understanding context
1376
+ { skill: "code-generation", weight: 0.3 }
1377
+ // Quick code
1378
+ ],
1379
+ "cli:quick-command": [
1380
+ { skill: "speed", weight: 0.7 },
1381
+ // Must be fast
1382
+ { skill: "code-generation", weight: 0.2 },
1383
+ // Simple generation
1384
+ { skill: "synthesis", weight: 0.1 }
1385
+ // Quick understanding
1386
+ ]
1387
+ };
1388
+ }
1389
+ });
1390
+
1391
+ // src/lib/work-type-router.ts
1392
+ function getGlobalRouter() {
1393
+ if (!globalRouter) {
1394
+ globalRouter = new WorkTypeRouter();
1395
+ }
1396
+ return globalRouter;
1397
+ }
1398
+ function getModelId(workTypeId) {
1399
+ return getGlobalRouter().getModelId(workTypeId);
1400
+ }
1401
+ var WorkTypeRouter, globalRouter;
1402
+ var init_work_type_router = __esm({
1403
+ "src/lib/work-type-router.ts"() {
1404
+ "use strict";
1405
+ init_esm_shims();
1406
+ init_work_types();
1407
+ init_model_fallback();
1408
+ init_config_yaml();
1409
+ init_smart_model_selector();
1410
+ WorkTypeRouter = class {
1411
+ config;
1412
+ availableModels = null;
1413
+ constructor(config) {
1414
+ this.config = config || loadConfig();
1415
+ }
1416
+ /**
1417
+ * Get list of available models based on enabled providers
1418
+ */
1419
+ getAvailableModels() {
1420
+ if (this.availableModels) {
1421
+ return this.availableModels;
1422
+ }
1423
+ const available = [];
1424
+ for (const provider of this.config.enabledProviders) {
1425
+ available.push(...getModelsByProvider(provider));
1426
+ }
1427
+ this.availableModels = available;
1428
+ return available;
1429
+ }
1430
+ /**
1431
+ * Get model for a specific work type
1432
+ *
1433
+ * Resolution order:
1434
+ * 1. Per-project/global override (if configured)
1435
+ * 2. Smart selection (capability-based)
1436
+ */
1437
+ getModel(workTypeId) {
1438
+ validateWorkType(workTypeId);
1439
+ let model;
1440
+ let source;
1441
+ let originalModel;
1442
+ let selection;
1443
+ if (this.config.overrides[workTypeId]) {
1444
+ model = this.config.overrides[workTypeId];
1445
+ source = "override";
1446
+ selection = {
1447
+ score: 100,
1448
+ reason: `Explicit override: ${model}`
1449
+ };
1450
+ } else {
1451
+ const availableModels = this.getAvailableModels();
1452
+ const result = selectModel(workTypeId, availableModels);
1453
+ model = result.model;
1454
+ source = "smart";
1455
+ selection = {
1456
+ score: result.score,
1457
+ reason: result.reason
1458
+ };
1459
+ }
1460
+ originalModel = model;
1461
+ model = applyFallback(model, this.config.enabledProviders);
1462
+ return {
1463
+ model,
1464
+ workType: workTypeId,
1465
+ source,
1466
+ usedFallback: model !== originalModel,
1467
+ originalModel: model !== originalModel ? originalModel : void 0,
1468
+ selection
1469
+ };
1470
+ }
1471
+ /**
1472
+ * Get just the model ID for a work type (convenience method)
1473
+ */
1474
+ getModelId(workTypeId) {
1475
+ return this.getModel(workTypeId).model;
1476
+ }
1477
+ /**
1478
+ * Check if a work type has an override configured
1479
+ */
1480
+ hasOverride(workTypeId) {
1481
+ return workTypeId in this.config.overrides;
1482
+ }
1483
+ /**
1484
+ * Get the set of enabled providers
1485
+ */
1486
+ getEnabledProviders() {
1487
+ return this.config.enabledProviders;
1488
+ }
1489
+ /**
1490
+ * Get all configured overrides
1491
+ */
1492
+ getOverrides() {
1493
+ return { ...this.config.overrides };
1494
+ }
1495
+ /**
1496
+ * Get API keys configuration
1497
+ */
1498
+ getApiKeys() {
1499
+ return { ...this.config.apiKeys };
1500
+ }
1501
+ /**
1502
+ * Get Gemini thinking level
1503
+ */
1504
+ getGeminiThinkingLevel() {
1505
+ return this.config.geminiThinkingLevel;
1506
+ }
1507
+ /**
1508
+ * Reload configuration from disk
1509
+ */
1510
+ reloadConfig() {
1511
+ this.config = loadConfig();
1512
+ this.availableModels = null;
1513
+ }
1514
+ /**
1515
+ * Get debug information about current configuration
1516
+ */
1517
+ getDebugInfo() {
1518
+ return {
1519
+ enabledProviders: Array.from(this.config.enabledProviders),
1520
+ availableModelCount: this.getAvailableModels().length,
1521
+ overrideCount: Object.keys(this.config.overrides).length,
1522
+ hasApiKeys: {
1523
+ openai: !!this.config.apiKeys.openai,
1524
+ google: !!this.config.apiKeys.google,
1525
+ zai: !!this.config.apiKeys.zai,
1526
+ kimi: !!this.config.apiKeys.kimi
1527
+ }
1528
+ };
1529
+ }
1530
+ };
1531
+ globalRouter = null;
1532
+ }
1533
+ });
1534
+
1535
+ export {
1536
+ sessionExists,
1537
+ createSession,
1538
+ killSession,
1539
+ sendKeys,
1540
+ capturePane,
1541
+ getAgentSessions,
1542
+ init_tmux,
1543
+ initHook,
1544
+ pushToHook,
1545
+ checkHook,
1546
+ popFromHook,
1547
+ clearHook,
1548
+ sendMail,
1549
+ generateFixedPointPrompt,
1550
+ init_hooks,
1551
+ loadConfig,
1552
+ init_config_yaml,
1553
+ getModelId,
1554
+ init_work_type_router
1555
+ };
1556
+ //# sourceMappingURL=chunk-PUR532O7.js.map