open-agents-ai 0.103.6 → 0.103.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +349 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28448,7 +28448,77 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
28448
28448
|
}
|
|
28449
28449
|
return result;
|
|
28450
28450
|
}
|
|
28451
|
-
|
|
28451
|
+
function loadUsageFile(filePath) {
|
|
28452
|
+
try {
|
|
28453
|
+
if (existsSync28(filePath)) {
|
|
28454
|
+
return JSON.parse(readFileSync20(filePath, "utf-8"));
|
|
28455
|
+
}
|
|
28456
|
+
} catch {
|
|
28457
|
+
}
|
|
28458
|
+
return { records: [] };
|
|
28459
|
+
}
|
|
28460
|
+
function saveUsageFile(filePath, data) {
|
|
28461
|
+
const dir = join38(filePath, "..");
|
|
28462
|
+
mkdirSync9(dir, { recursive: true });
|
|
28463
|
+
writeFileSync9(filePath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
28464
|
+
}
|
|
28465
|
+
function recordUsage(kind, value, opts) {
|
|
28466
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28467
|
+
const update = (filePath) => {
|
|
28468
|
+
const data = loadUsageFile(filePath);
|
|
28469
|
+
const existing = data.records.find((r) => r.kind === kind && r.value === value);
|
|
28470
|
+
if (existing) {
|
|
28471
|
+
existing.useCount++;
|
|
28472
|
+
existing.lastUsed = now;
|
|
28473
|
+
if (opts?.meta)
|
|
28474
|
+
existing.meta = { ...existing.meta, ...opts.meta };
|
|
28475
|
+
} else {
|
|
28476
|
+
data.records.push({
|
|
28477
|
+
value,
|
|
28478
|
+
kind,
|
|
28479
|
+
useCount: 1,
|
|
28480
|
+
firstUsed: now,
|
|
28481
|
+
lastUsed: now,
|
|
28482
|
+
meta: opts?.meta
|
|
28483
|
+
});
|
|
28484
|
+
}
|
|
28485
|
+
if (data.records.length > MAX_HISTORY_RECORDS) {
|
|
28486
|
+
data.records.sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
28487
|
+
data.records = data.records.slice(0, MAX_HISTORY_RECORDS);
|
|
28488
|
+
}
|
|
28489
|
+
saveUsageFile(filePath, data);
|
|
28490
|
+
};
|
|
28491
|
+
update(join38(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
|
|
28492
|
+
if (opts?.repoRoot) {
|
|
28493
|
+
update(join38(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
|
|
28494
|
+
}
|
|
28495
|
+
}
|
|
28496
|
+
function loadUsageHistory(kind, repoRoot) {
|
|
28497
|
+
const globalPath = join38(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
|
|
28498
|
+
const globalData = loadUsageFile(globalPath);
|
|
28499
|
+
const localData = repoRoot ? loadUsageFile(join38(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
|
|
28500
|
+
const map = /* @__PURE__ */ new Map();
|
|
28501
|
+
for (const r of globalData.records) {
|
|
28502
|
+
if (r.kind !== kind)
|
|
28503
|
+
continue;
|
|
28504
|
+
map.set(r.value, { ...r, localUses: 0 });
|
|
28505
|
+
}
|
|
28506
|
+
for (const r of localData.records) {
|
|
28507
|
+
if (r.kind !== kind)
|
|
28508
|
+
continue;
|
|
28509
|
+
const existing = map.get(r.value);
|
|
28510
|
+
if (existing) {
|
|
28511
|
+
existing.localUses = r.useCount;
|
|
28512
|
+
if (new Date(r.lastUsed) > new Date(existing.lastUsed)) {
|
|
28513
|
+
existing.lastUsed = r.lastUsed;
|
|
28514
|
+
}
|
|
28515
|
+
} else {
|
|
28516
|
+
map.set(r.value, { ...r, localUses: r.useCount });
|
|
28517
|
+
}
|
|
28518
|
+
}
|
|
28519
|
+
return Array.from(map.values()).sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
28520
|
+
}
|
|
28521
|
+
var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
|
|
28452
28522
|
var init_oa_directory = __esm({
|
|
28453
28523
|
"packages/cli/dist/tui/oa-directory.js"() {
|
|
28454
28524
|
"use strict";
|
|
@@ -28486,6 +28556,8 @@ var init_oa_directory = __esm({
|
|
|
28486
28556
|
".idea",
|
|
28487
28557
|
".vscode"
|
|
28488
28558
|
]);
|
|
28559
|
+
USAGE_HISTORY_FILE = "usage-history.json";
|
|
28560
|
+
MAX_HISTORY_RECORDS = 50;
|
|
28489
28561
|
}
|
|
28490
28562
|
});
|
|
28491
28563
|
|
|
@@ -30014,46 +30086,102 @@ function ansi3(code, text) {
|
|
|
30014
30086
|
function fg2562(code, text) {
|
|
30015
30087
|
return isTTY3 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
|
|
30016
30088
|
}
|
|
30089
|
+
function stripAnsi(s) {
|
|
30090
|
+
return s.replace(/\x1B\[[0-9;]*m/g, "");
|
|
30091
|
+
}
|
|
30017
30092
|
function defaultRenderRow(item, focused, isActive) {
|
|
30018
30093
|
const marker = isActive ? selectColors.green("\u25CF") : focused ? selectColors.orange("\u25CF") : selectColors.dim("\u25CB");
|
|
30019
30094
|
const label = focused ? selectColors.orange(selectColors.bold(item.label)) : isActive ? selectColors.green(item.label) : item.label;
|
|
30020
30095
|
const detail = item.detail ? ` ${selectColors.dim(item.detail)}` : "";
|
|
30021
30096
|
return ` ${marker} ${label}${detail}`;
|
|
30022
30097
|
}
|
|
30098
|
+
function matchRow(item, focused, isActive) {
|
|
30099
|
+
if (focused || isActive) {
|
|
30100
|
+
return defaultRenderRow(item, focused, isActive);
|
|
30101
|
+
}
|
|
30102
|
+
const marker = selectColors.matchLight("\u25CB");
|
|
30103
|
+
const label = selectColors.matchLight(stripAnsi(item.label));
|
|
30104
|
+
const detail = item.detail ? ` ${selectColors.dim(stripAnsi(item.detail))}` : "";
|
|
30105
|
+
return ` ${marker} ${label}${detail}`;
|
|
30106
|
+
}
|
|
30023
30107
|
function tuiSelect(opts) {
|
|
30024
30108
|
const { items, title, rl } = opts;
|
|
30025
30109
|
const renderRow = opts.renderRow ?? defaultRenderRow;
|
|
30026
30110
|
const activeKey = opts.activeKey ?? null;
|
|
30111
|
+
const skipSet = new Set(opts.skipKeys ?? []);
|
|
30027
30112
|
if (items.length === 0) {
|
|
30028
30113
|
return Promise.resolve({ confirmed: false, key: null, index: -1 });
|
|
30029
30114
|
}
|
|
30030
|
-
|
|
30031
|
-
|
|
30032
|
-
|
|
30115
|
+
const isSkippable = (idx) => skipSet.has(items[idx].key);
|
|
30116
|
+
let filter = "";
|
|
30117
|
+
let matchSet = /* @__PURE__ */ new Set();
|
|
30118
|
+
function updateFilter() {
|
|
30119
|
+
if (!filter) {
|
|
30120
|
+
matchSet = new Set(items.map((_, i) => i));
|
|
30121
|
+
} else {
|
|
30122
|
+
const lower = filter.toLowerCase();
|
|
30123
|
+
matchSet = /* @__PURE__ */ new Set();
|
|
30124
|
+
for (let i = 0; i < items.length; i++) {
|
|
30125
|
+
if (isSkippable(i))
|
|
30126
|
+
continue;
|
|
30127
|
+
const plain = stripAnsi(items[i].label).toLowerCase();
|
|
30128
|
+
const detailPlain = items[i].detail ? stripAnsi(items[i].detail).toLowerCase() : "";
|
|
30129
|
+
if (plain.includes(lower) || detailPlain.includes(lower)) {
|
|
30130
|
+
matchSet.add(i);
|
|
30131
|
+
}
|
|
30132
|
+
}
|
|
30133
|
+
}
|
|
30134
|
+
}
|
|
30135
|
+
updateFilter();
|
|
30136
|
+
const findSelectable = (from, dir) => {
|
|
30137
|
+
let idx = from;
|
|
30138
|
+
while (idx >= 0 && idx < items.length) {
|
|
30139
|
+
if (!isSkippable(idx) && matchSet.has(idx))
|
|
30140
|
+
return idx;
|
|
30141
|
+
idx += dir;
|
|
30142
|
+
}
|
|
30143
|
+
return -1;
|
|
30144
|
+
};
|
|
30145
|
+
let cursor = activeKey ? items.findIndex((i) => i.key === activeKey) : -1;
|
|
30146
|
+
if (cursor < 0 || isSkippable(cursor)) {
|
|
30147
|
+
const first = findSelectable(0, 1);
|
|
30148
|
+
cursor = first >= 0 ? first : 0;
|
|
30149
|
+
}
|
|
30033
30150
|
const termRows = process.stdout.rows ?? 24;
|
|
30034
|
-
const
|
|
30035
|
-
|
|
30151
|
+
const overhead = 6;
|
|
30152
|
+
const maxVisible = opts.maxVisible ?? Math.max(3, termRows - overhead);
|
|
30153
|
+
let scrollOffset = 0;
|
|
30036
30154
|
let lastRenderedLines = 0;
|
|
30037
30155
|
return new Promise((resolve31) => {
|
|
30038
30156
|
const stdin = process.stdin;
|
|
30039
30157
|
const hadRawMode = stdin.isRaw;
|
|
30158
|
+
const savedRlListeners = [];
|
|
30040
30159
|
if (rl) {
|
|
30041
30160
|
rl.pause();
|
|
30161
|
+
for (const event of ["keypress", "data"]) {
|
|
30162
|
+
const listeners = stdin.listeners(event);
|
|
30163
|
+
for (const fn of listeners) {
|
|
30164
|
+
savedRlListeners.push({ event, fn });
|
|
30165
|
+
stdin.removeListener(event, fn);
|
|
30166
|
+
}
|
|
30167
|
+
}
|
|
30042
30168
|
}
|
|
30043
30169
|
if (typeof stdin.setRawMode === "function") {
|
|
30044
30170
|
stdin.setRawMode(true);
|
|
30045
30171
|
}
|
|
30046
30172
|
stdin.resume();
|
|
30047
30173
|
process.stdout.write("\x1B[?25l");
|
|
30048
|
-
function clampScroll() {
|
|
30049
|
-
|
|
30050
|
-
|
|
30051
|
-
|
|
30052
|
-
|
|
30053
|
-
|
|
30054
|
-
|
|
30055
|
-
|
|
30056
|
-
|
|
30174
|
+
function clampScroll(displayList) {
|
|
30175
|
+
const cursorPos = displayList.indexOf(cursor);
|
|
30176
|
+
if (cursorPos < 0)
|
|
30177
|
+
return;
|
|
30178
|
+
if (cursorPos < scrollOffset) {
|
|
30179
|
+
scrollOffset = cursorPos;
|
|
30180
|
+
} else if (cursorPos >= scrollOffset + maxVisible) {
|
|
30181
|
+
scrollOffset = cursorPos - maxVisible + 1;
|
|
30182
|
+
}
|
|
30183
|
+
const maxOffset = Math.max(0, displayList.length - maxVisible);
|
|
30184
|
+
scrollOffset = Math.max(0, Math.min(maxOffset, scrollOffset));
|
|
30057
30185
|
}
|
|
30058
30186
|
function render() {
|
|
30059
30187
|
if (lastRenderedLines > 0) {
|
|
@@ -30063,29 +30191,66 @@ function tuiSelect(opts) {
|
|
|
30063
30191
|
}
|
|
30064
30192
|
process.stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
30065
30193
|
}
|
|
30066
|
-
clampScroll();
|
|
30067
30194
|
const lines = [];
|
|
30068
30195
|
if (title) {
|
|
30069
30196
|
lines.push(`
|
|
30070
30197
|
${selectColors.bold(title)}`);
|
|
30071
|
-
lines.push("");
|
|
30072
30198
|
}
|
|
30073
|
-
if (
|
|
30074
|
-
|
|
30199
|
+
if (filter) {
|
|
30200
|
+
const count = matchSet.size;
|
|
30201
|
+
lines.push(` ${selectColors.cyan("/")} ${selectColors.bold(filter)} ${selectColors.dim(`(${count} match${count !== 1 ? "es" : ""})`)}`);
|
|
30202
|
+
} else {
|
|
30203
|
+
lines.push(` ${selectColors.dim("Type to filter...")}`);
|
|
30075
30204
|
}
|
|
30076
|
-
|
|
30077
|
-
|
|
30078
|
-
|
|
30079
|
-
|
|
30205
|
+
lines.push("");
|
|
30206
|
+
let displayList;
|
|
30207
|
+
if (filter) {
|
|
30208
|
+
displayList = [];
|
|
30209
|
+
for (let i = 0; i < items.length; i++) {
|
|
30210
|
+
if (matchSet.has(i) || isSkippable(i)) {
|
|
30211
|
+
displayList.push(i);
|
|
30212
|
+
}
|
|
30213
|
+
}
|
|
30214
|
+
displayList = displayList.filter((idx, pos) => {
|
|
30215
|
+
if (!isSkippable(idx))
|
|
30216
|
+
return true;
|
|
30217
|
+
for (let j = pos + 1; j < displayList.length; j++) {
|
|
30218
|
+
if (!isSkippable(displayList[j]))
|
|
30219
|
+
return true;
|
|
30220
|
+
break;
|
|
30221
|
+
}
|
|
30222
|
+
return false;
|
|
30223
|
+
});
|
|
30224
|
+
} else {
|
|
30225
|
+
displayList = items.map((_, i) => i);
|
|
30226
|
+
}
|
|
30227
|
+
clampScroll(displayList);
|
|
30228
|
+
const visibleStart = scrollOffset;
|
|
30229
|
+
const visibleEnd = Math.min(displayList.length, scrollOffset + maxVisible);
|
|
30230
|
+
if (visibleStart > 0) {
|
|
30231
|
+
lines.push(` ${selectColors.dim(` \u25B2 ${visibleStart} more`)}`);
|
|
30232
|
+
}
|
|
30233
|
+
for (let vi = visibleStart; vi < visibleEnd; vi++) {
|
|
30234
|
+
const idx = displayList[vi];
|
|
30235
|
+
const item = items[idx];
|
|
30236
|
+
if (isSkippable(idx)) {
|
|
30237
|
+
lines.push(` ${item.label}`);
|
|
30238
|
+
continue;
|
|
30239
|
+
}
|
|
30240
|
+
const focused = idx === cursor;
|
|
30080
30241
|
const isActive = item.key === activeKey;
|
|
30081
|
-
|
|
30242
|
+
if (filter) {
|
|
30243
|
+
lines.push(matchRow(item, focused, isActive));
|
|
30244
|
+
} else {
|
|
30245
|
+
lines.push(renderRow(item, focused, isActive));
|
|
30246
|
+
}
|
|
30082
30247
|
}
|
|
30083
|
-
const remaining =
|
|
30248
|
+
const remaining = displayList.length - visibleEnd;
|
|
30084
30249
|
if (remaining > 0) {
|
|
30085
30250
|
lines.push(` ${selectColors.dim(` \u25BC ${remaining} more`)}`);
|
|
30086
30251
|
}
|
|
30087
30252
|
lines.push("");
|
|
30088
|
-
lines.push(` ${selectColors.dim("\u2191/\u2193 navigate Enter select Esc cancel")}`);
|
|
30253
|
+
lines.push(` ${selectColors.dim("\u2191/\u2193 navigate Enter select Esc " + (filter ? "clear filter" : "cancel") + " Type to filter")}`);
|
|
30089
30254
|
lines.push("");
|
|
30090
30255
|
const output = lines.join("\n");
|
|
30091
30256
|
process.stdout.write(output);
|
|
@@ -30093,6 +30258,7 @@ function tuiSelect(opts) {
|
|
|
30093
30258
|
}
|
|
30094
30259
|
function cleanup() {
|
|
30095
30260
|
stdin.removeListener("data", onData);
|
|
30261
|
+
process.stdout.removeListener("resize", onResize);
|
|
30096
30262
|
process.stdout.write("\x1B[?25h");
|
|
30097
30263
|
if (lastRenderedLines > 0) {
|
|
30098
30264
|
process.stdout.write(`\x1B[${lastRenderedLines}A`);
|
|
@@ -30104,6 +30270,9 @@ function tuiSelect(opts) {
|
|
|
30104
30270
|
if (typeof stdin.setRawMode === "function") {
|
|
30105
30271
|
stdin.setRawMode(hadRawMode ?? false);
|
|
30106
30272
|
}
|
|
30273
|
+
for (const { event, fn } of savedRlListeners) {
|
|
30274
|
+
stdin.on(event, fn);
|
|
30275
|
+
}
|
|
30107
30276
|
if (rl) {
|
|
30108
30277
|
rl.resume();
|
|
30109
30278
|
rl.prompt(false);
|
|
@@ -30111,29 +30280,93 @@ function tuiSelect(opts) {
|
|
|
30111
30280
|
}
|
|
30112
30281
|
function onData(chunk) {
|
|
30113
30282
|
const seq = chunk.toString("utf8");
|
|
30114
|
-
if (seq === "\x1B[A"
|
|
30115
|
-
|
|
30116
|
-
|
|
30117
|
-
|
|
30118
|
-
|
|
30119
|
-
|
|
30120
|
-
} else if (seq === "\x1B[
|
|
30121
|
-
|
|
30283
|
+
if (seq === "\x1B[A") {
|
|
30284
|
+
const next = findSelectable(cursor - 1, -1);
|
|
30285
|
+
if (next >= 0 && next !== cursor) {
|
|
30286
|
+
cursor = next;
|
|
30287
|
+
render();
|
|
30288
|
+
}
|
|
30289
|
+
} else if (seq === "\x1B[B") {
|
|
30290
|
+
const next = findSelectable(cursor + 1, 1);
|
|
30291
|
+
if (next >= 0 && next !== cursor) {
|
|
30292
|
+
cursor = next;
|
|
30293
|
+
render();
|
|
30294
|
+
}
|
|
30295
|
+
} else if (seq === "\x1B[5~") {
|
|
30296
|
+
for (let i = 0; i < maxVisible; i++) {
|
|
30297
|
+
const next = findSelectable(cursor - 1, -1);
|
|
30298
|
+
if (next < 0 || next === cursor)
|
|
30299
|
+
break;
|
|
30300
|
+
cursor = next;
|
|
30301
|
+
}
|
|
30122
30302
|
render();
|
|
30123
|
-
} else if (seq === "\x1B[
|
|
30124
|
-
|
|
30303
|
+
} else if (seq === "\x1B[6~") {
|
|
30304
|
+
for (let i = 0; i < maxVisible; i++) {
|
|
30305
|
+
const next = findSelectable(cursor + 1, 1);
|
|
30306
|
+
if (next < 0 || next === cursor)
|
|
30307
|
+
break;
|
|
30308
|
+
cursor = next;
|
|
30309
|
+
}
|
|
30125
30310
|
render();
|
|
30311
|
+
} else if (seq === "\x1B[H") {
|
|
30312
|
+
const first = findSelectable(0, 1);
|
|
30313
|
+
if (first >= 0) {
|
|
30314
|
+
cursor = first;
|
|
30315
|
+
render();
|
|
30316
|
+
}
|
|
30317
|
+
} else if (seq === "\x1B[F") {
|
|
30318
|
+
const last = findSelectable(items.length - 1, -1);
|
|
30319
|
+
if (last >= 0) {
|
|
30320
|
+
cursor = last;
|
|
30321
|
+
render();
|
|
30322
|
+
}
|
|
30126
30323
|
} else if (seq === "\r" || seq === "\n") {
|
|
30127
|
-
|
|
30128
|
-
|
|
30129
|
-
|
|
30130
|
-
|
|
30131
|
-
|
|
30324
|
+
if (!isSkippable(cursor) && matchSet.has(cursor)) {
|
|
30325
|
+
cleanup();
|
|
30326
|
+
resolve31({ confirmed: true, key: items[cursor].key, index: cursor });
|
|
30327
|
+
}
|
|
30328
|
+
} else if (seq === "\x1B" || seq === "\x1B\x1B") {
|
|
30329
|
+
if (filter) {
|
|
30330
|
+
filter = "";
|
|
30331
|
+
updateFilter();
|
|
30332
|
+
const valid = findSelectable(cursor, 1);
|
|
30333
|
+
if (valid >= 0)
|
|
30334
|
+
cursor = valid;
|
|
30335
|
+
scrollOffset = 0;
|
|
30336
|
+
render();
|
|
30337
|
+
} else {
|
|
30338
|
+
cleanup();
|
|
30339
|
+
resolve31({ confirmed: false, key: null, index: cursor });
|
|
30340
|
+
}
|
|
30132
30341
|
} else if (seq === "") {
|
|
30133
30342
|
cleanup();
|
|
30134
30343
|
resolve31({ confirmed: false, key: null, index: cursor });
|
|
30344
|
+
} else if (seq === "\x7F" || seq === "\b") {
|
|
30345
|
+
if (filter.length > 0) {
|
|
30346
|
+
filter = filter.slice(0, -1);
|
|
30347
|
+
updateFilter();
|
|
30348
|
+
if (!matchSet.has(cursor) || isSkippable(cursor)) {
|
|
30349
|
+
const next = findSelectable(0, 1);
|
|
30350
|
+
if (next >= 0)
|
|
30351
|
+
cursor = next;
|
|
30352
|
+
}
|
|
30353
|
+
scrollOffset = 0;
|
|
30354
|
+
render();
|
|
30355
|
+
}
|
|
30356
|
+
} else if (seq.length === 1 && seq.charCodeAt(0) >= 32 && seq.charCodeAt(0) < 127) {
|
|
30357
|
+
filter += seq;
|
|
30358
|
+
updateFilter();
|
|
30359
|
+
if (matchSet.size > 0) {
|
|
30360
|
+
const first = findSelectable(0, 1);
|
|
30361
|
+
if (first >= 0)
|
|
30362
|
+
cursor = first;
|
|
30363
|
+
}
|
|
30364
|
+
scrollOffset = 0;
|
|
30365
|
+
render();
|
|
30135
30366
|
}
|
|
30136
30367
|
}
|
|
30368
|
+
const onResize = () => render();
|
|
30369
|
+
process.stdout.on("resize", onResize);
|
|
30137
30370
|
stdin.on("data", onData);
|
|
30138
30371
|
render();
|
|
30139
30372
|
});
|
|
@@ -30148,7 +30381,11 @@ var init_tui_select = __esm({
|
|
|
30148
30381
|
green: (t) => ansi3("32", t),
|
|
30149
30382
|
dim: (t) => ansi3("2", t),
|
|
30150
30383
|
bold: (t) => ansi3("1", t),
|
|
30151
|
-
cyan: (t) => ansi3("36", t)
|
|
30384
|
+
cyan: (t) => ansi3("36", t),
|
|
30385
|
+
/** Lighter grey for filter matches (252 = near-white) */
|
|
30386
|
+
matchLight: (t) => fg2562(252, t),
|
|
30387
|
+
/** Dark grey for non-matching items (240 = dark grey) */
|
|
30388
|
+
matchDark: (t) => fg2562(240, t)
|
|
30152
30389
|
};
|
|
30153
30390
|
}
|
|
30154
30391
|
});
|
|
@@ -31274,16 +31511,39 @@ async function showModelPicker(ctx, local = false) {
|
|
|
31274
31511
|
renderWarning("No models found.");
|
|
31275
31512
|
return;
|
|
31276
31513
|
}
|
|
31277
|
-
const items =
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31514
|
+
const items = [];
|
|
31515
|
+
const history = loadUsageHistory("model", ctx.repoRoot);
|
|
31516
|
+
const liveModelNames = new Set(models.map((m) => m.name));
|
|
31517
|
+
if (history.length > 0) {
|
|
31518
|
+
items.push({ key: "__header_recent__", label: c2.dim("\u2500\u2500 Recent \u2500\u2500"), detail: "" });
|
|
31519
|
+
for (const h of history.slice(0, 8)) {
|
|
31520
|
+
const uses = h.localUses > 0 ? `${h.useCount} uses (${h.localUses} local)` : `${h.useCount} uses`;
|
|
31521
|
+
const available = liveModelNames.has(h.value) ? "" : c2.yellow(" [offline]");
|
|
31522
|
+
items.push({
|
|
31523
|
+
key: h.value,
|
|
31524
|
+
label: h.value,
|
|
31525
|
+
detail: `${uses}${available}`
|
|
31526
|
+
});
|
|
31527
|
+
}
|
|
31528
|
+
items.push({ key: "__header_available__", label: c2.dim("\u2500\u2500 Available \u2500\u2500"), detail: "" });
|
|
31529
|
+
}
|
|
31530
|
+
const historyKeys = new Set(history.map((h) => h.value));
|
|
31531
|
+
for (const m of models) {
|
|
31532
|
+
if (history.length > 0 && historyKeys.has(m.name))
|
|
31533
|
+
continue;
|
|
31534
|
+
items.push({
|
|
31535
|
+
key: m.name,
|
|
31536
|
+
label: m.name,
|
|
31537
|
+
detail: [m.parameterSize, m.size, m.modified].filter(Boolean).join(" ")
|
|
31538
|
+
});
|
|
31539
|
+
}
|
|
31282
31540
|
const result = await tuiSelect({
|
|
31283
31541
|
items,
|
|
31284
31542
|
activeKey: ctx.config.model,
|
|
31285
31543
|
title: "Select Model",
|
|
31286
|
-
rl: ctx.rl
|
|
31544
|
+
rl: ctx.rl,
|
|
31545
|
+
// Skip header rows
|
|
31546
|
+
skipKeys: ["__header_recent__", "__header_available__"]
|
|
31287
31547
|
});
|
|
31288
31548
|
if (!result.confirmed || !result.key) {
|
|
31289
31549
|
renderInfo("Model selection cancelled.");
|
|
@@ -31296,6 +31556,30 @@ async function showModelPicker(ctx, local = false) {
|
|
|
31296
31556
|
}
|
|
31297
31557
|
async function handleEndpoint(arg, ctx, local = false) {
|
|
31298
31558
|
if (!arg) {
|
|
31559
|
+
const history = loadUsageHistory("endpoint", ctx.repoRoot);
|
|
31560
|
+
if (history.length > 0) {
|
|
31561
|
+
const items = history.map((h) => {
|
|
31562
|
+
const provider2 = h.meta?.provider ?? detectProvider(h.value).label;
|
|
31563
|
+
const uses = h.localUses > 0 ? `${h.useCount} uses (${h.localUses} local)` : `${h.useCount} uses`;
|
|
31564
|
+
return {
|
|
31565
|
+
key: h.value,
|
|
31566
|
+
label: h.value,
|
|
31567
|
+
detail: `${provider2} ${uses}`
|
|
31568
|
+
};
|
|
31569
|
+
});
|
|
31570
|
+
const result = await tuiSelect({
|
|
31571
|
+
items,
|
|
31572
|
+
activeKey: ctx.config.backendUrl,
|
|
31573
|
+
title: "Select Endpoint",
|
|
31574
|
+
rl: ctx.rl
|
|
31575
|
+
});
|
|
31576
|
+
if (result.confirmed && result.key) {
|
|
31577
|
+
await handleEndpoint(result.key, ctx, local);
|
|
31578
|
+
return;
|
|
31579
|
+
}
|
|
31580
|
+
renderInfo("Endpoint selection cancelled.");
|
|
31581
|
+
return;
|
|
31582
|
+
}
|
|
31299
31583
|
const currentProvider = detectProvider(ctx.config.backendUrl);
|
|
31300
31584
|
process.stdout.write(`
|
|
31301
31585
|
${c2.bold("Current endpoint:")}
|
|
@@ -31399,6 +31683,15 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
31399
31683
|
}
|
|
31400
31684
|
ctx.saveSettings(endpointSettings);
|
|
31401
31685
|
}
|
|
31686
|
+
recordUsage("endpoint", normalizedUrl, {
|
|
31687
|
+
repoRoot: local ? ctx.repoRoot : void 0,
|
|
31688
|
+
local,
|
|
31689
|
+
meta: {
|
|
31690
|
+
provider: provider.label,
|
|
31691
|
+
backendType,
|
|
31692
|
+
...apiKey ? { authHint: apiKey.slice(0, 4) + "..." } : {}
|
|
31693
|
+
}
|
|
31694
|
+
});
|
|
31402
31695
|
process.stdout.write(`
|
|
31403
31696
|
${c2.green("\u2714")} Endpoint updated and saved${local ? " (project-local)" : ""}:
|
|
31404
31697
|
`);
|
|
@@ -31715,6 +32008,14 @@ async function switchModel(query, ctx, local = false) {
|
|
|
31715
32008
|
if (local) {
|
|
31716
32009
|
renderInfo("Saved as project-local override.");
|
|
31717
32010
|
}
|
|
32011
|
+
recordUsage("model", finalModel, {
|
|
32012
|
+
repoRoot: local ? ctx.repoRoot : void 0,
|
|
32013
|
+
local,
|
|
32014
|
+
meta: {
|
|
32015
|
+
endpoint: ctx.config.backendUrl,
|
|
32016
|
+
parameterSize: match.parameterSize ?? ""
|
|
32017
|
+
}
|
|
32018
|
+
});
|
|
31718
32019
|
if (ctx.setContextWindowSize) {
|
|
31719
32020
|
const ctxSize = await queryContextSize(ctx.config.backendUrl, finalModel, ctx.config.apiKey);
|
|
31720
32021
|
if (ctxSize) {
|
package/package.json
CHANGED