open-agents-ai 0.103.7 → 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.
Files changed (2) hide show
  1. package/dist/index.js +178 -46
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -30086,12 +30086,24 @@ function ansi3(code, text) {
30086
30086
  function fg2562(code, text) {
30087
30087
  return isTTY3 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
30088
30088
  }
30089
+ function stripAnsi(s) {
30090
+ return s.replace(/\x1B\[[0-9;]*m/g, "");
30091
+ }
30089
30092
  function defaultRenderRow(item, focused, isActive) {
30090
30093
  const marker = isActive ? selectColors.green("\u25CF") : focused ? selectColors.orange("\u25CF") : selectColors.dim("\u25CB");
30091
30094
  const label = focused ? selectColors.orange(selectColors.bold(item.label)) : isActive ? selectColors.green(item.label) : item.label;
30092
30095
  const detail = item.detail ? ` ${selectColors.dim(item.detail)}` : "";
30093
30096
  return ` ${marker} ${label}${detail}`;
30094
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
+ }
30095
30107
  function tuiSelect(opts) {
30096
30108
  const { items, title, rl } = opts;
30097
30109
  const renderRow = opts.renderRow ?? defaultRenderRow;
@@ -30101,20 +30113,44 @@ function tuiSelect(opts) {
30101
30113
  return Promise.resolve({ confirmed: false, key: null, index: -1 });
30102
30114
  }
30103
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();
30104
30136
  const findSelectable = (from, dir) => {
30105
30137
  let idx = from;
30106
- while (idx >= 0 && idx < items.length && isSkippable(idx)) {
30138
+ while (idx >= 0 && idx < items.length) {
30139
+ if (!isSkippable(idx) && matchSet.has(idx))
30140
+ return idx;
30107
30141
  idx += dir;
30108
30142
  }
30109
- return idx >= 0 && idx < items.length ? idx : from;
30143
+ return -1;
30110
30144
  };
30111
- let cursor = activeKey ? items.findIndex((i) => i.key === activeKey) : 0;
30112
- if (cursor < 0)
30113
- cursor = 0;
30114
- cursor = findSelectable(cursor, 1);
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
+ }
30115
30150
  const termRows = process.stdout.rows ?? 24;
30116
- const maxVisible = opts.maxVisible ?? Math.max(5, termRows - 6);
30117
- let scrollOffset = Math.max(0, cursor - Math.floor(maxVisible / 2));
30151
+ const overhead = 6;
30152
+ const maxVisible = opts.maxVisible ?? Math.max(3, termRows - overhead);
30153
+ let scrollOffset = 0;
30118
30154
  let lastRenderedLines = 0;
30119
30155
  return new Promise((resolve31) => {
30120
30156
  const stdin = process.stdin;
@@ -30135,15 +30171,17 @@ function tuiSelect(opts) {
30135
30171
  }
30136
30172
  stdin.resume();
30137
30173
  process.stdout.write("\x1B[?25l");
30138
- function clampScroll() {
30139
- if (cursor < scrollOffset) {
30140
- scrollOffset = cursor;
30141
- } else if (cursor >= scrollOffset + maxVisible) {
30142
- scrollOffset = cursor - maxVisible + 1;
30143
- }
30144
- scrollOffset = Math.max(0, Math.min(items.length - maxVisible, scrollOffset));
30145
- if (scrollOffset < 0)
30146
- scrollOffset = 0;
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));
30147
30185
  }
30148
30186
  function render() {
30149
30187
  if (lastRenderedLines > 0) {
@@ -30153,33 +30191,66 @@ function tuiSelect(opts) {
30153
30191
  }
30154
30192
  process.stdout.write(`\x1B[${lastRenderedLines}A`);
30155
30193
  }
30156
- clampScroll();
30157
30194
  const lines = [];
30158
30195
  if (title) {
30159
30196
  lines.push(`
30160
30197
  ${selectColors.bold(title)}`);
30161
- lines.push("");
30162
30198
  }
30163
- if (scrollOffset > 0) {
30164
- lines.push(` ${selectColors.dim(` \u25B2 ${scrollOffset} more`)}`);
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...")}`);
30165
30204
  }
30166
- const visibleEnd = Math.min(items.length, scrollOffset + maxVisible);
30167
- for (let i = scrollOffset; i < visibleEnd; i++) {
30168
- const item = items[i];
30169
- if (isSkippable(i)) {
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)) {
30170
30237
  lines.push(` ${item.label}`);
30171
30238
  continue;
30172
30239
  }
30173
- const focused = i === cursor;
30240
+ const focused = idx === cursor;
30174
30241
  const isActive = item.key === activeKey;
30175
- lines.push(renderRow(item, focused, isActive));
30242
+ if (filter) {
30243
+ lines.push(matchRow(item, focused, isActive));
30244
+ } else {
30245
+ lines.push(renderRow(item, focused, isActive));
30246
+ }
30176
30247
  }
30177
- const remaining = items.length - visibleEnd;
30248
+ const remaining = displayList.length - visibleEnd;
30178
30249
  if (remaining > 0) {
30179
30250
  lines.push(` ${selectColors.dim(` \u25BC ${remaining} more`)}`);
30180
30251
  }
30181
30252
  lines.push("");
30182
- 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")}`);
30183
30254
  lines.push("");
30184
30255
  const output = lines.join("\n");
30185
30256
  process.stdout.write(output);
@@ -30187,6 +30258,7 @@ function tuiSelect(opts) {
30187
30258
  }
30188
30259
  function cleanup() {
30189
30260
  stdin.removeListener("data", onData);
30261
+ process.stdout.removeListener("resize", onResize);
30190
30262
  process.stdout.write("\x1B[?25h");
30191
30263
  if (lastRenderedLines > 0) {
30192
30264
  process.stdout.write(`\x1B[${lastRenderedLines}A`);
@@ -30208,37 +30280,93 @@ function tuiSelect(opts) {
30208
30280
  }
30209
30281
  function onData(chunk) {
30210
30282
  const seq = chunk.toString("utf8");
30211
- if (seq === "\x1B[A" || seq === "k") {
30212
- const next = cursor - 1;
30213
- if (next >= 0) {
30214
- cursor = findSelectable(next, -1);
30283
+ if (seq === "\x1B[A") {
30284
+ const next = findSelectable(cursor - 1, -1);
30285
+ if (next >= 0 && next !== cursor) {
30286
+ cursor = next;
30215
30287
  render();
30216
30288
  }
30217
- } else if (seq === "\x1B[B" || seq === "j") {
30218
- const next = cursor + 1;
30219
- if (next < items.length) {
30220
- cursor = findSelectable(next, 1);
30289
+ } else if (seq === "\x1B[B") {
30290
+ const next = findSelectable(cursor + 1, 1);
30291
+ if (next >= 0 && next !== cursor) {
30292
+ cursor = next;
30221
30293
  render();
30222
30294
  }
30223
- } else if (seq === "\x1B[H" || seq === "g") {
30224
- cursor = findSelectable(0, 1);
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
+ }
30225
30302
  render();
30226
- } else if (seq === "\x1B[F" || seq === "G") {
30227
- cursor = findSelectable(items.length - 1, -1);
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
+ }
30228
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
+ }
30229
30323
  } else if (seq === "\r" || seq === "\n") {
30230
- if (!isSkippable(cursor)) {
30324
+ if (!isSkippable(cursor) && matchSet.has(cursor)) {
30231
30325
  cleanup();
30232
30326
  resolve31({ confirmed: true, key: items[cursor].key, index: cursor });
30233
30327
  }
30234
- } else if (seq === "\x1B" || seq === "\x1B\x1B" || seq === "q") {
30235
- cleanup();
30236
- resolve31({ confirmed: false, key: null, index: cursor });
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
+ }
30237
30341
  } else if (seq === "") {
30238
30342
  cleanup();
30239
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();
30240
30366
  }
30241
30367
  }
30368
+ const onResize = () => render();
30369
+ process.stdout.on("resize", onResize);
30242
30370
  stdin.on("data", onData);
30243
30371
  render();
30244
30372
  });
@@ -30253,7 +30381,11 @@ var init_tui_select = __esm({
30253
30381
  green: (t) => ansi3("32", t),
30254
30382
  dim: (t) => ansi3("2", t),
30255
30383
  bold: (t) => ansi3("1", t),
30256
- 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)
30257
30389
  };
30258
30390
  }
30259
30391
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.7",
3
+ "version": "0.103.8",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",