@lazyingart/agintiflow 0.8.10 → 0.8.11

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.8.10",
3
+ "version": "0.8.11",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a resumable Playwright website-control agent with OpenAI-compatible tool calling.",
6
6
  "license": "Apache-2.0",
@@ -60,7 +60,7 @@ function label(name, bgCode) {
60
60
  }
61
61
 
62
62
  function userPrompt() {
63
- return `\n${label("user>", ansi.userBg)} `;
63
+ return `\n${label("user>", ansi.userBg)} ${color("|", ansi.userBg)} `;
64
64
  }
65
65
 
66
66
  function commandCompleter(line = "") {
@@ -70,6 +70,21 @@ function commandCompleter(line = "") {
70
70
  return [hits.length > 0 ? hits : SLASH_COMMANDS, trimmed];
71
71
  }
72
72
 
73
+ function stripAnsi(value) {
74
+ return String(value || "").replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
75
+ }
76
+
77
+ function promptGutter() {
78
+ const visible = stripAnsi(userPrompt()).replace(/^\n/, "").length;
79
+ return " ".repeat(Math.max(visible - 2, 0)) + `${color("|", ansi.userBg)} `;
80
+ }
81
+
82
+ function commandSuggestions(line = "") {
83
+ const trimmed = String(line || "");
84
+ if (!trimmed.startsWith("/") || /\s/.test(trimmed)) return [];
85
+ return SLASH_COMMANDS.filter((command) => command.startsWith(trimmed)).slice(0, 8);
86
+ }
87
+
73
88
  function stripMarkdown(text) {
74
89
  const lines = String(text || "").split(/\r?\n/);
75
90
  let inFence = false;
@@ -79,16 +94,26 @@ function stripMarkdown(text) {
79
94
  let line = rawLine;
80
95
  if (/^\s*```/.test(line)) {
81
96
  inFence = !inFence;
82
- if (inFence) rendered.push(color("code", ansi.dim));
97
+ if (inFence) {
98
+ const language = line.replace(/^\s*```/, "").trim();
99
+ rendered.push(color(language ? `code ${language}` : "code", ansi.dim));
100
+ }
83
101
  continue;
84
102
  }
85
103
 
86
104
  if (!inFence) {
87
105
  if (/^\s*[-*_]{3,}\s*$/.test(line)) {
88
- rendered.push("");
106
+ rendered.push(color("-".repeat(42), ansi.dim));
107
+ continue;
108
+ }
109
+ const heading = line.match(/^\s{0,3}(#{1,6})\s+(.+)$/);
110
+ if (heading) {
111
+ rendered.push(color(heading[2].replace(/\s+#*$/, ""), ansi.bold, ansi.cyan));
112
+ continue;
113
+ }
114
+ if (/^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line)) {
89
115
  continue;
90
116
  }
91
- line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
92
117
  line = line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)");
93
118
  line = line.replace(/\*\*([^*]+)\*\*/g, (_, value) => color(value, ansi.bold));
94
119
  line = line.replace(/__([^_]+)__/g, (_, value) => color(value, ansi.bold));
@@ -96,7 +121,9 @@ function stripMarkdown(text) {
96
121
  line = line.replace(/(^|[^\w])_([^_\n]+)_/g, "$1$2");
97
122
  line = line.replace(/`([^`]+)`/g, (_, value) => color(value, ansi.yellow));
98
123
  line = line.replace(/^(\s*)[-*+]\s+/, "$1- ");
99
- line = line.replace(/^\s*>\s?/, " ");
124
+ line = line.replace(/^\s*>\s?(.+)$/, (_, value) => color(`| ${value}`, ansi.dim));
125
+ } else {
126
+ line = color(` ${line}`, ansi.yellow);
100
127
  }
101
128
 
102
129
  rendered.push(line);
@@ -105,10 +132,15 @@ function stripMarkdown(text) {
105
132
  return rendered.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
106
133
  }
107
134
 
108
- function printWrapped(prefix, text) {
135
+ function rolePrefix(name, bgCode) {
136
+ return `${label(name, bgCode)} ${color("|", bgCode)} `;
137
+ }
138
+
139
+ function printWrapped(prefix, text, { stripCode = "" } = {}) {
109
140
  const rendered = stripMarkdown(text);
110
141
  const lines = rendered.split("\n");
111
- const gutter = " ".repeat(useColor ? 9 : prefix.length);
142
+ const visible = stripAnsi(prefix).length;
143
+ const gutter = `${" ".repeat(Math.max(visible - 2, 0))}${stripCode ? color("|", stripCode) : "|"} `;
112
144
  console.log(`${prefix}${lines[0] || ""}`);
113
145
  for (const line of lines.slice(1)) {
114
146
  console.log(`${gutter}${line}`);
@@ -116,7 +148,7 @@ function printWrapped(prefix, text) {
116
148
  }
117
149
 
118
150
  function printAgentMessage(text) {
119
- printWrapped(`${label("aginti>", ansi.agentBg)} `, text);
151
+ printWrapped(rolePrefix("aginti>", ansi.agentBg), text, { stripCode: ansi.agentBg });
120
152
  }
121
153
 
122
154
  function printSystemLine(text) {
@@ -197,6 +229,113 @@ function printHelp() {
197
229
  );
198
230
  }
199
231
 
232
+ function renderPromptBuffer(buffer, previousLineCount = 0) {
233
+ for (let index = 0; index < previousLineCount; index += 1) {
234
+ output.write(`\r${ansi.clearLine}`);
235
+ if (index < previousLineCount - 1) output.write("\x1b[1A");
236
+ }
237
+
238
+ const lines = String(buffer || "").split("\n");
239
+ const suggestions = commandSuggestions(lines[0] || "");
240
+ const rendered = [];
241
+ rendered.push(`${userPrompt().replace(/^\n/, "")}${lines[0] || ""}`);
242
+ for (const line of lines.slice(1)) {
243
+ rendered.push(`${promptGutter()}${line}`);
244
+ }
245
+ if (suggestions.length > 0) {
246
+ rendered.push(`${promptGutter()}${color(`suggest: ${suggestions.join(" ")}`, ansi.dim)}`);
247
+ }
248
+ output.write(rendered.join("\n"));
249
+ return rendered.length;
250
+ }
251
+
252
+ function createAbortError(message = "Aborted with Ctrl+C") {
253
+ const error = new Error(message);
254
+ error.code = "ABORT_ERR";
255
+ error.name = "AbortError";
256
+ return error;
257
+ }
258
+
259
+ function readTtyPrompt() {
260
+ return new Promise((resolve, reject) => {
261
+ emitKeypressEvents(input);
262
+ const wasRaw = Boolean(input.isRaw);
263
+ let buffer = "";
264
+ let renderedLines = 0;
265
+
266
+ const cleanup = () => {
267
+ input.off("keypress", handler);
268
+ if (typeof input.setRawMode === "function") input.setRawMode(wasRaw);
269
+ input.pause();
270
+ output.write(ansi.cursorShow);
271
+ };
272
+
273
+ const redraw = () => {
274
+ renderedLines = renderPromptBuffer(buffer, renderedLines);
275
+ };
276
+
277
+ const submit = () => {
278
+ cleanup();
279
+ output.write("\n");
280
+ resolve(buffer);
281
+ };
282
+
283
+ const handler = (str = "", key = {}) => {
284
+ if (key.ctrl && key.name === "c") {
285
+ cleanup();
286
+ output.write("\n");
287
+ reject(createAbortError());
288
+ return;
289
+ }
290
+ if ((key.ctrl && key.name === "j") || (key.sequence === "\n" && key.name !== "return" && key.name !== "enter")) {
291
+ buffer += "\n";
292
+ redraw();
293
+ return;
294
+ }
295
+ if (key.name === "return" || key.name === "enter" || key.sequence === "\r" || str === "\r") {
296
+ submit();
297
+ return;
298
+ }
299
+ if (key.name === "backspace") {
300
+ buffer = buffer.slice(0, -1);
301
+ redraw();
302
+ return;
303
+ }
304
+ if (key.name === "tab") {
305
+ const suggestions = commandSuggestions(buffer.split("\n")[0] || "");
306
+ if (suggestions.length === 1) {
307
+ buffer = suggestions[0];
308
+ }
309
+ redraw();
310
+ return;
311
+ }
312
+ if (key.name === "escape") {
313
+ buffer = "";
314
+ redraw();
315
+ return;
316
+ }
317
+ if (key.ctrl || key.meta) return;
318
+ if (str && !key.sequence?.startsWith("\x1b")) {
319
+ buffer += str;
320
+ redraw();
321
+ }
322
+ };
323
+
324
+ input.resume();
325
+ input.setRawMode(true);
326
+ output.write(ansi.cursorHide);
327
+ input.on("keypress", handler);
328
+ redraw();
329
+ });
330
+ }
331
+
332
+ async function readPromptAnswer(rl) {
333
+ if (input.isTTY && output.isTTY && typeof input.setRawMode === "function") {
334
+ return readTtyPrompt();
335
+ }
336
+ return rl.question(userPrompt());
337
+ }
338
+
200
339
  function printStatus(state) {
201
340
  printSystemLine(`project=${process.cwd()}`);
202
341
  printSystemLine(`cwd=${state.commandCwd || process.cwd()}`);
@@ -237,6 +376,7 @@ function attachRunInterrupts(controller) {
237
376
 
238
377
  emitKeypressEvents(input);
239
378
  const wasRaw = Boolean(input.isRaw);
379
+ input.resume();
240
380
  input.setRawMode(true);
241
381
  const handler = (_str, key = {}) => {
242
382
  const isEscape = key.name === "escape";
@@ -564,12 +704,15 @@ async function runPrompt(prompt, state, packageDir) {
564
704
 
565
705
  export async function startInteractiveCli(args = {}, { packageDir, packageVersion } = {}) {
566
706
  const state = createState(args);
567
- const rl = readline.createInterface({
568
- input,
569
- output,
570
- terminal: Boolean(input.isTTY && output.isTTY),
571
- completer: commandCompleter,
572
- });
707
+ const rl =
708
+ input.isTTY && output.isTTY
709
+ ? null
710
+ : readline.createInterface({
711
+ input,
712
+ output,
713
+ terminal: false,
714
+ completer: commandCompleter,
715
+ });
573
716
 
574
717
  await renderLaunchHeader(packageVersion);
575
718
  printSystemLine(`Project: ${process.cwd()}`);
@@ -581,7 +724,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
581
724
  while (true) {
582
725
  let answer = "";
583
726
  try {
584
- answer = await rl.question(userPrompt());
727
+ answer = await readPromptAnswer(rl);
585
728
  } catch (error) {
586
729
  if (error?.code === "ERR_USE_AFTER_CLOSE") break;
587
730
  if (isAbortError(error)) {
@@ -609,6 +752,6 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
609
752
  }
610
753
  }
611
754
  } finally {
612
- rl.close();
755
+ rl?.close();
613
756
  }
614
757
  }