@lazyingart/agintiflow 0.20.86 → 0.20.87

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.86",
3
+ "version": "0.20.87",
4
4
  "type": "module",
5
5
  "description": "Low-cost, project-aware Web and CLI agents with DeepSeek/Venice/OpenAI routing, visible tool calls, durable sessions, scouts, AAPS, SCS, and guarded local execution.",
6
6
  "license": "Apache-2.0",
@@ -76,6 +76,7 @@ function runCli(args, inputText) {
76
76
  ...process.env,
77
77
  AGINTIFLOW_RUNTIME_DIR: "",
78
78
  AGINTIFLOW_HOME: agintiflowHome,
79
+ AGINTIFLOW_PREVIEW_TTL_MS: "1000",
79
80
  AGINTI_LANGUAGE: "en",
80
81
  },
81
82
  });
@@ -10,7 +10,7 @@ import {
10
10
  selectModelRoute,
11
11
  } from "../src/model-routing.js";
12
12
  import { normalizeTextToolCallResponse, parseTextToolCalls, usesTextToolProtocol } from "../src/model-client.js";
13
- import { modelRoleChoices } from "../src/interactive-cli.js";
13
+ import { modelRoleChoices, selectorVisibleWindow } from "../src/interactive-cli.js";
14
14
  import { buildScsEvidencePack, buildSupervisorInstruction } from "../src/scs-controller.js";
15
15
 
16
16
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
@@ -151,6 +151,11 @@ assert(!routeChoices.includes("venice/e2ee-venice-uncensored-24b-p"), "shared mo
151
151
  assert(modelRoleChoices("route").some((item) => item.provider === "openai" && item.model === "gpt-5.5" && item.reasoningOptions.includes("xhigh")), "OpenAI selector missing reasoning levels");
152
152
  assert(modelRoleChoices("auxiliary").some((item) => item.provider === "grsai"), "auxiliary selector missing GRS AI");
153
153
  assert(modelRoleChoices("auxiliary").some((item) => item.provider === "venice" && item.model === "wan-2-7-pro-edit"), "auxiliary selector missing Venice Wan edit");
154
+ const longAuxiliaryWindow = selectorVisibleWindow(32, 17, 24);
155
+ assert(longAuxiliaryWindow.end - longAuxiliaryWindow.start <= 8, "selector should cap visible rows for long option lists");
156
+ assert(longAuxiliaryWindow.topHidden > 0 && longAuxiliaryWindow.bottomHidden > 0, "selector should expose scroll indicators around middle selections");
157
+ const topAuxiliaryWindow = selectorVisibleWindow(32, 0, 24);
158
+ assert(topAuxiliaryWindow.start === 0 && topAuxiliaryWindow.bottomHidden > 0, "selector should keep first option visible at top of long lists");
154
159
  const parsedTextToolCalls = parseTextToolCalls('[TOOL_CALLS]list_files[ARGS]call_123[ARGS]{"path":".","maxDepth":1}');
155
160
  assert(parsedTextToolCalls.length === 1, "Venice text tool-call parser did not detect encoded tool call");
156
161
  assert(parsedTextToolCalls[0].function.name === "list_files", "Venice text tool-call parser returned wrong tool name");
@@ -253,6 +258,7 @@ console.log(
253
258
  "route-overrides",
254
259
  "provider-groups",
255
260
  "auxiliary-catalog",
261
+ "selector-windowing",
256
262
  "shared-model-selectors",
257
263
  "venice-text-tool-parser",
258
264
  "requested-tools-parser",
@@ -151,7 +151,7 @@ async function isPortAvailable(port) {
151
151
  async function findAvailablePort(preferredPort = 8765) {
152
152
  const preferred = Number(preferredPort);
153
153
  const start = Number.isFinite(preferred) && preferred > 0 ? preferred : 8765;
154
- for (let port = start; port < start + 80; port += 1) {
154
+ for (let port = start; port < start + 1000 && port < 65535; port += 1) {
155
155
  if (await isPortAvailable(port)) return port;
156
156
  }
157
157
  throw new Error(`No available preview port found near ${start}.`);
@@ -2220,21 +2220,49 @@ function clearSelectorSequence(lineCount) {
2220
2220
  return Array.from({ length: Math.max(lineCount, 0) }, () => "\x1b[1A\r\x1b[2K").join("");
2221
2221
  }
2222
2222
 
2223
+ export function selectorVisibleWindow(optionCount = 0, selectedIndex = 0, height = terminalHeight()) {
2224
+ const count = Math.max(Number(optionCount) || 0, 0);
2225
+ const maxRows = Math.max(4, Math.min(8, Math.floor(Math.max(Number(height) || 24, 10) * 0.36)));
2226
+ if (count <= maxRows) {
2227
+ return { start: 0, end: count, topHidden: 0, bottomHidden: 0 };
2228
+ }
2229
+ const selected = clamp(selectedIndex, 0, count - 1);
2230
+ const half = Math.floor(maxRows / 2);
2231
+ const start = clamp(selected - half, 0, count - maxRows);
2232
+ const end = Math.min(start + maxRows, count);
2233
+ return {
2234
+ start,
2235
+ end,
2236
+ topHidden: start,
2237
+ bottomHidden: count - end,
2238
+ };
2239
+ }
2240
+
2223
2241
  function renderSelector({ title, subtitle, options, selectedIndex, lineCount = 0 }) {
2224
2242
  const width = Math.min(Math.max(terminalWidth() - 2, 60), 110);
2225
2243
  const bodyWidth = width - 4;
2226
2244
  const safeTitle = compactLine(title, bodyWidth);
2227
2245
  const safeSubtitle = compactLine(subtitle, bodyWidth);
2246
+ const visible = selectorVisibleWindow(options.length, selectedIndex, terminalHeight());
2247
+ const optionRows = [];
2248
+ if (visible.topHidden > 0) {
2249
+ optionRows.push(`│ ${padVisible(color(` ... ${visible.topHidden} earlier option${visible.topHidden === 1 ? "" : "s"}`, ansi.dim), bodyWidth)} │`);
2250
+ }
2251
+ for (let index = visible.start; index < visible.end; index += 1) {
2252
+ const option = options[index];
2253
+ const marker = index === selectedIndex ? ">" : " ";
2254
+ const rendered = `${marker} ${compactLine(modelChoiceLine(option), bodyWidth - 2)}`;
2255
+ optionRows.push(`│ ${padVisible(index === selectedIndex ? color(rendered, ansi.userBg, ansi.bold) : rendered, bodyWidth)} │`);
2256
+ }
2257
+ if (visible.bottomHidden > 0) {
2258
+ optionRows.push(`│ ${padVisible(color(` ... ${visible.bottomHidden} later option${visible.bottomHidden === 1 ? "" : "s"}`, ansi.dim), bodyWidth)} │`);
2259
+ }
2228
2260
  const rows = [
2229
2261
  `╭${"─".repeat(width - 2)}╮`,
2230
2262
  `│ ${padVisible(safeTitle, bodyWidth)} │`,
2231
2263
  `│ ${padVisible(safeSubtitle, bodyWidth)} │`,
2232
2264
  `├${"─".repeat(width - 2)}┤`,
2233
- ...options.map((option, index) => {
2234
- const marker = index === selectedIndex ? ">" : " ";
2235
- const rendered = `${marker} ${compactLine(modelChoiceLine(option), bodyWidth - 2)}`;
2236
- return `│ ${padVisible(index === selectedIndex ? color(rendered, ansi.userBg, ansi.bold) : rendered, bodyWidth)} │`;
2237
- }),
2265
+ ...optionRows,
2238
2266
  `╰${"─".repeat(width - 2)}╯`,
2239
2267
  ];
2240
2268
  output.write(`${lineCount > 0 ? clearSelectorSequence(lineCount) : ""}${rows.join("\n")}\n`);
@@ -5,6 +5,8 @@ import path from "node:path";
5
5
  const root = path.resolve(process.argv[2] || process.cwd());
6
6
  const port = Number(process.argv[3] || 0);
7
7
  const host = "127.0.0.1";
8
+ const idleTtlMs = Math.max(Number(process.env.AGINTIFLOW_PREVIEW_TTL_MS) || 6 * 60 * 60 * 1000, 1000);
9
+ let lastRequestAt = Date.now();
8
10
 
9
11
  const MIME_TYPES = new Map([
10
12
  [".html", "text/html; charset=utf-8"],
@@ -62,6 +64,7 @@ function isBlockedPath(relativePath) {
62
64
  }
63
65
 
64
66
  const server = http.createServer(async (req, res) => {
67
+ lastRequestAt = Date.now();
65
68
  if (!["GET", "HEAD"].includes(req.method || "")) {
66
69
  send(res, 405, "Method Not Allowed");
67
70
  return;
@@ -110,3 +113,14 @@ server.listen(port, host, () => {
110
113
  const actualPort = typeof address === "object" && address ? address.port : port;
111
114
  console.log(`AgInTiFlow static preview http://${host}:${actualPort}/ root=${root}`);
112
115
  });
116
+
117
+ const ttlTimer = setInterval(async () => {
118
+ const rootExists = await fs
119
+ .stat(root)
120
+ .then((stat) => stat.isDirectory())
121
+ .catch(() => false);
122
+ if (rootExists && Date.now() - lastRequestAt < idleTtlMs) return;
123
+ server.close(() => process.exit(0));
124
+ setTimeout(() => process.exit(0), 1000).unref();
125
+ }, Math.min(Math.max(Math.floor(idleTtlMs / 2), 1000), 60_000));
126
+ ttlTimer.unref();