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.
- package/README.md +84 -2695
- package/dist/{agents-B5NRTVHK.js → agents-54LDKMHR.js} +8 -3
- package/dist/chunk-44EOY2ZL.js +58 -0
- package/dist/chunk-44EOY2ZL.js.map +1 -0
- package/dist/chunk-BWGFN44T.js +224 -0
- package/dist/chunk-BWGFN44T.js.map +1 -0
- package/dist/chunk-F7NQZD6H.js +49 -0
- package/dist/chunk-F7NQZD6H.js.map +1 -0
- package/dist/chunk-HCTJFIJJ.js +159 -0
- package/dist/chunk-HCTJFIJJ.js.map +1 -0
- package/dist/chunk-JM6V62LT.js +650 -0
- package/dist/chunk-JM6V62LT.js.map +1 -0
- package/dist/chunk-K45YD6A3.js +254 -0
- package/dist/chunk-K45YD6A3.js.map +1 -0
- package/dist/chunk-KGPRXDMX.js +137 -0
- package/dist/chunk-KGPRXDMX.js.map +1 -0
- package/dist/chunk-KQAEUOML.js +278 -0
- package/dist/chunk-KQAEUOML.js.map +1 -0
- package/dist/chunk-NYVQC3D7.js +90 -0
- package/dist/chunk-NYVQC3D7.js.map +1 -0
- package/dist/chunk-PUR532O7.js +1556 -0
- package/dist/chunk-PUR532O7.js.map +1 -0
- package/dist/chunk-VTDDVLCK.js +1977 -0
- package/dist/chunk-VTDDVLCK.js.map +1 -0
- package/dist/chunk-Z24TY3XN.js +916 -0
- package/dist/chunk-Z24TY3XN.js.map +1 -0
- package/dist/chunk-ZHC57RCV.js +44 -0
- package/dist/chunk-ZHC57RCV.js.map +1 -0
- package/dist/{chunk-ITI4IC5A.js → chunk-ZZ3477GY.js} +69 -100
- package/dist/chunk-ZZ3477GY.js.map +1 -0
- package/dist/cli/index.js +4664 -2912
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/public/assets/index-CRqsEkmn.css +32 -0
- package/dist/dashboard/public/assets/index-DPSUbu4A.js +645 -0
- package/dist/dashboard/public/index.html +15 -3
- package/dist/dashboard/server.js +45663 -17860
- package/dist/dns-L3L2BB27.js +30 -0
- package/dist/dns-L3L2BB27.js.map +1 -0
- package/dist/index.d.ts +63 -3
- package/dist/index.js +42 -18
- package/dist/index.js.map +1 -1
- package/dist/projects-ESIB34QQ.js +43 -0
- package/dist/projects-ESIB34QQ.js.map +1 -0
- package/dist/remote-agents-Z3R2A5BN.js +25 -0
- package/dist/remote-agents-Z3R2A5BN.js.map +1 -0
- package/dist/remote-workspace-HI4VML6H.js +179 -0
- package/dist/remote-workspace-HI4VML6H.js.map +1 -0
- package/dist/specialist-context-SNCJ7O7G.js +256 -0
- package/dist/specialist-context-SNCJ7O7G.js.map +1 -0
- package/dist/specialist-logs-A7ODEK2T.js +43 -0
- package/dist/specialist-logs-A7ODEK2T.js.map +1 -0
- package/dist/specialists-C7XLNSXQ.js +121 -0
- package/dist/specialists-C7XLNSXQ.js.map +1 -0
- package/dist/traefik-WI3KSRGG.js +12 -0
- package/dist/traefik-WI3KSRGG.js.map +1 -0
- package/package.json +1 -1
- package/templates/traefik/docker-compose.yml +1 -1
- package/templates/traefik/dynamic/panopticon.yml.template +41 -0
- package/templates/traefik/traefik.yml +8 -0
- package/dist/chunk-7HHDVXBM.js +0 -349
- package/dist/chunk-7HHDVXBM.js.map +0 -1
- package/dist/chunk-H45CLB7E.js +0 -2044
- package/dist/chunk-H45CLB7E.js.map +0 -1
- package/dist/chunk-ITI4IC5A.js.map +0 -1
- package/dist/dashboard/public/assets/index-BDd8hGYb.css +0 -32
- package/dist/dashboard/public/assets/index-sFwLPko-.js +0 -556
- package/templates/traefik/dynamic/panopticon.yml +0 -51
- /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
|