@lazyingart/agintiflow 0.12.6 → 0.12.7
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 +1 -1
- package/package.json +1 -1
- package/scripts/smoke-cli-chat.js +21 -4
- package/src/interactive-cli.js +55 -5
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ aginti
|
|
|
67
67
|
aginti chat
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Inside chat, type normal requests such as `write a small Python CLI app with tests`. The default is Docker workspace mode with approved package installs, so coding, plotting, and LaTeX tasks can set up project-local tools without touching the host. Use `/help` for commands, `/login` or `/auth` to paste a provider key, `/instructions` to inspect `AGINTI.md`, `/latex on` for PDF work, `/docker off` only when you intentionally want host mode, `/sessions` to list project runs, and `/resume latest` or `/resume <session-id>` to continue work. Type `/` then Tab for command completion. `Ctrl+J` inserts a new line in the colored input panel, Enter sends, arrow keys move through wrapped multiline input, and `Ctrl+A`/`Ctrl+E` jump to the current line start/end. During an active run, Enter sends the draft as an ASAP pipe message (`→`) and Tab queues it for after the run (`↳`); ASAP messages are consumed first, Alt+Up edits the last piped message, and Shift+Left edits the last after-finish queued message. The input panel always shows the current `cwd` footer. Assistant responses start on a fresh line after the `aginti>` header with a colored response gutter and render common Markdown, including headings, inline code, bold text, lists, quotes, code fences, and
|
|
70
|
+
Inside chat, type normal requests such as `write a small Python CLI app with tests`. The default is Docker workspace mode with approved package installs, so coding, plotting, and LaTeX tasks can set up project-local tools without touching the host. Use `/help` for commands, `/login` or `/auth` to paste a provider key, `/instructions` to inspect `AGINTI.md`, `/latex on` for PDF work, `/docker off` only when you intentionally want host mode, `/sessions` to list project runs, and `/resume latest` or `/resume <session-id>` to continue work. Type `/` then Tab for command completion. `Ctrl+J` inserts a new line in the colored input panel, Enter sends, arrow keys move through wrapped multiline input, and `Ctrl+A`/`Ctrl+E` jump to the current line start/end. During an active run, Enter sends the draft as an ASAP pipe message (`→`) and Tab queues it for after the run (`↳`); ASAP messages are consumed first, Alt+Up edits the last piped message, and Shift+Left edits the last after-finish queued message. The input panel always shows the current `cwd` footer and a single live status row, so long goals and tool updates are compacted instead of flooding the transcript. Assistant responses start on a fresh line after the `aginti>` header with a colored response gutter and render common Markdown, including headings, inline code, bold text, lists, quotes, code fences, tables, and red/green patch diff lines. Resuming a session prints a compact recent-chat preview before the prompt. Esc or Ctrl+C stops the active run cleanly and prints the resume command.
|
|
71
71
|
|
|
72
72
|
`aginti init` creates `AGINTI.md` at the project root. This is the editable project-instruction file for both CLI and web runs, similar to `AGENTS.md` or project memory in other agents. Keep durable preferences, commands, and constraints there, but never secrets. You can edit it manually or ask in chat, for example: `update AGINTI.md to remember that this project uses pytest and npm run check`.
|
|
73
73
|
|
package/package.json
CHANGED
|
@@ -69,6 +69,22 @@ try {
|
|
|
69
69
|
if (!renderedMarkdown.includes("Check") || !renderedMarkdown.includes("Present")) {
|
|
70
70
|
throw new Error("terminal markdown renderer dropped table content");
|
|
71
71
|
}
|
|
72
|
+
if ((renderedMarkdown.match(/Present/g) || []).length !== 1) {
|
|
73
|
+
throw new Error("terminal markdown renderer duplicated table rows");
|
|
74
|
+
}
|
|
75
|
+
const renderedDiff = stripMarkdown(
|
|
76
|
+
[
|
|
77
|
+
"Diff:",
|
|
78
|
+
"--- a/example.txt",
|
|
79
|
+
"+++ b/example.txt",
|
|
80
|
+
"@@ line 1 @@",
|
|
81
|
+
"-old",
|
|
82
|
+
"+new",
|
|
83
|
+
].join("\n")
|
|
84
|
+
);
|
|
85
|
+
if (!renderedDiff.includes("-old") || !renderedDiff.includes("+new")) {
|
|
86
|
+
throw new Error("terminal markdown renderer dropped patch diff lines");
|
|
87
|
+
}
|
|
72
88
|
|
|
73
89
|
const promptLayout = buildPromptLayout(`${"x".repeat(180)}\nsecond line`, 95, 80, 24);
|
|
74
90
|
const visibleLengths = promptLayout.renderedRows.map((line) =>
|
|
@@ -86,13 +102,14 @@ try {
|
|
|
86
102
|
}
|
|
87
103
|
const queuedPromptLayout = buildPromptLayout("follow up", 9, 90, 24, {
|
|
88
104
|
commandCwd: "/tmp/aginti-project",
|
|
105
|
+
statusLine: "running · tool: apply_patch with a very long request that should be compacted in the panel",
|
|
89
106
|
pendingAsap: [{ content: "apply this to the running task" }],
|
|
90
107
|
pendingQueued: [{ content: "run this after the current task" }],
|
|
91
108
|
});
|
|
92
109
|
const queuedText = queuedPromptLayout.renderedRows
|
|
93
110
|
.map((line) => line.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, ""))
|
|
94
111
|
.join("\n");
|
|
95
|
-
if (!queuedText.includes("→ apply this") || !queuedText.includes("↳ run this") || !queuedText.includes("cwd /tmp/aginti-project")) {
|
|
112
|
+
if (!queuedText.includes("run running · tool: apply_patch") || !queuedText.includes("→ apply this") || !queuedText.includes("↳ run this") || !queuedText.includes("cwd /tmp/aginti-project")) {
|
|
96
113
|
throw new Error("terminal prompt layout did not render live input queue and cwd footer");
|
|
97
114
|
}
|
|
98
115
|
|
|
@@ -119,8 +136,8 @@ try {
|
|
|
119
136
|
if (!result.stdout.includes("Interactive agent chat")) {
|
|
120
137
|
throw new Error("interactive chat did not print its banner");
|
|
121
138
|
}
|
|
122
|
-
if (!result.stdout.includes("status=
|
|
123
|
-
throw new Error("interactive chat did not print
|
|
139
|
+
if (!result.stdout.includes("status=idle session=")) {
|
|
140
|
+
throw new Error("interactive chat did not print final run status");
|
|
124
141
|
}
|
|
125
142
|
if (!/aginti>\s*\r?\n\s*\|\s+Mock run complete\./.test(result.stdout)) {
|
|
126
143
|
throw new Error("assistant response did not render with a fresh-line response gutter");
|
|
@@ -139,7 +156,7 @@ try {
|
|
|
139
156
|
{
|
|
140
157
|
ok: true,
|
|
141
158
|
projectRoot: tempRoot,
|
|
142
|
-
checks: ["markdown-render", "prompt-layout", "live-input-layout", "agent-response-gutter", "aginti-md", "instructions-command", "instructions-chat-edit", "interactive-chat", "mock-file-write", "run-status", "resume-latest", "resume-history-preview"],
|
|
159
|
+
checks: ["markdown-render", "markdown-table-no-duplicate", "patch-diff-render", "prompt-layout", "live-input-status-layout", "agent-response-gutter", "aginti-md", "instructions-command", "instructions-chat-edit", "interactive-chat", "mock-file-write", "run-status", "resume-latest", "resume-history-preview"],
|
|
143
160
|
},
|
|
144
161
|
null,
|
|
145
162
|
2
|
package/src/interactive-cli.js
CHANGED
|
@@ -28,6 +28,7 @@ const ansi = {
|
|
|
28
28
|
userBg: "\x1b[48;5;24m\x1b[38;5;231m",
|
|
29
29
|
agentBg: "\x1b[48;5;29m\x1b[38;5;231m",
|
|
30
30
|
responseBg: "\x1b[48;5;25m\x1b[38;5;231m",
|
|
31
|
+
statusBg: "\x1b[48;5;23m\x1b[38;5;231m",
|
|
31
32
|
systemBg: "\x1b[48;5;236m\x1b[38;5;245m",
|
|
32
33
|
};
|
|
33
34
|
const brandPalette = ["\x1b[38;5;45m", "\x1b[38;5;81m", "\x1b[38;5;86m", "\x1b[38;5;118m", "\x1b[38;5;226m"];
|
|
@@ -152,6 +153,7 @@ function compactLine(value = "", limit = 96) {
|
|
|
152
153
|
export function stripMarkdown(text) {
|
|
153
154
|
const lines = String(text || "").split(/\r?\n/);
|
|
154
155
|
let inFence = false;
|
|
156
|
+
let diffContext = 0;
|
|
155
157
|
const rendered = [];
|
|
156
158
|
|
|
157
159
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -166,6 +168,15 @@ export function stripMarkdown(text) {
|
|
|
166
168
|
continue;
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
if (/^\s*Diff:\s*$/i.test(line)) diffContext = 80;
|
|
172
|
+
const patchLine = renderPatchLine(line, { active: diffContext > 0 || inFence });
|
|
173
|
+
if (patchLine) {
|
|
174
|
+
rendered.push(patchLine);
|
|
175
|
+
diffContext = 80;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (diffContext > 0) diffContext -= 1;
|
|
179
|
+
|
|
169
180
|
if (!inFence) {
|
|
170
181
|
if (/^\s*[-*_]{3,}\s*$/.test(line)) {
|
|
171
182
|
rendered.push(color("-".repeat(42), ansi.dim));
|
|
@@ -203,6 +214,17 @@ export function stripMarkdown(text) {
|
|
|
203
214
|
return rendered.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
204
215
|
}
|
|
205
216
|
|
|
217
|
+
function renderPatchLine(line = "", { active = false } = {}) {
|
|
218
|
+
const value = String(line || "");
|
|
219
|
+
if (/^diff --git\s+/.test(value)) return color(value, ansi.bold, ansi.cyan);
|
|
220
|
+
if (/^@@\s+/.test(value)) return color(value, ansi.cyan);
|
|
221
|
+
if (/^---\s+a\//.test(value)) return color(value, ansi.red);
|
|
222
|
+
if (/^\+\+\+\s+b\//.test(value)) return color(value, ansi.green);
|
|
223
|
+
if (active && /^\+(?!\+\+)/.test(value)) return color(value, ansi.green);
|
|
224
|
+
if (active && /^-(?!--)/.test(value)) return color(value, ansi.red);
|
|
225
|
+
return "";
|
|
226
|
+
}
|
|
227
|
+
|
|
206
228
|
function splitMarkdownTableRow(line = "") {
|
|
207
229
|
const trimmed = String(line || "").trim();
|
|
208
230
|
if (!trimmed.includes("|")) return null;
|
|
@@ -519,6 +541,11 @@ export function buildPromptLayout(buffer = "", cursor = 0, width = terminalWidth
|
|
|
519
541
|
const renderedRows = [];
|
|
520
542
|
let renderedCursorRow = cursorRow - visible.start;
|
|
521
543
|
|
|
544
|
+
if (options.statusLine) {
|
|
545
|
+
renderedRows.push(panelLine(` run ${compactLine(options.statusLine, lineWidth - 8)}`, ansi.statusBg, lineWidth));
|
|
546
|
+
renderedCursorRow += 1;
|
|
547
|
+
}
|
|
548
|
+
|
|
522
549
|
const pendingAsap = Array.isArray(options.pendingAsap) ? options.pendingAsap : [];
|
|
523
550
|
const pendingQueued = Array.isArray(options.pendingQueued) ? options.pendingQueued : [];
|
|
524
551
|
for (const item of pendingAsap.slice(-4)) {
|
|
@@ -887,6 +914,7 @@ class LiveRunInput {
|
|
|
887
914
|
this.preferredColumn = null;
|
|
888
915
|
this.pendingAsap = [];
|
|
889
916
|
this.pendingQueued = [];
|
|
917
|
+
this.statusLine = "";
|
|
890
918
|
this.wasRaw = Boolean(input.isRaw);
|
|
891
919
|
this.started = false;
|
|
892
920
|
this.handler = this.handleKey.bind(this);
|
|
@@ -952,6 +980,7 @@ class LiveRunInput {
|
|
|
952
980
|
}
|
|
953
981
|
this.rendered = renderPromptBuffer(this.buffer, this.cursor, this.rendered, {
|
|
954
982
|
commandCwd: this.commandCwd,
|
|
983
|
+
statusLine: this.statusLine,
|
|
955
984
|
pendingAsap: this.pendingAsap,
|
|
956
985
|
pendingQueued: this.pendingQueued,
|
|
957
986
|
});
|
|
@@ -972,9 +1001,17 @@ class LiveRunInput {
|
|
|
972
1001
|
this.redraw();
|
|
973
1002
|
}
|
|
974
1003
|
|
|
1004
|
+
setStatus(value = "") {
|
|
1005
|
+
const nextStatus = compactLine(value, Math.max(terminalWidth() - 16, 36));
|
|
1006
|
+
if (this.statusLine === nextStatus) return;
|
|
1007
|
+
this.statusLine = nextStatus;
|
|
1008
|
+
this.redraw();
|
|
1009
|
+
}
|
|
1010
|
+
|
|
975
1011
|
moveVertical(direction) {
|
|
976
1012
|
const layout = buildPromptLayout(this.buffer, this.cursor, terminalWidth(), terminalHeight(), {
|
|
977
1013
|
commandCwd: this.commandCwd,
|
|
1014
|
+
statusLine: this.statusLine,
|
|
978
1015
|
pendingAsap: this.pendingAsap,
|
|
979
1016
|
pendingQueued: this.pendingQueued,
|
|
980
1017
|
});
|
|
@@ -1215,8 +1252,14 @@ async function printResumeHistory(state, { limit = 8 } = {}) {
|
|
|
1215
1252
|
}
|
|
1216
1253
|
|
|
1217
1254
|
function printStatusEvent(state, label, details = "") {
|
|
1218
|
-
|
|
1219
|
-
|
|
1255
|
+
const safeDetails = compactLine(details, 72);
|
|
1256
|
+
state.lastEvent = safeDetails ? `${label}: ${safeDetails}` : label;
|
|
1257
|
+
const statusText = `${state.status || "running"} · ${state.lastEvent}`;
|
|
1258
|
+
if (activeRunInput) {
|
|
1259
|
+
activeRunInput.setStatus(statusText);
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
printSystemLine(`status=${statusText}`);
|
|
1220
1263
|
}
|
|
1221
1264
|
|
|
1222
1265
|
function attachRunInterrupts(controller) {
|
|
@@ -1595,15 +1638,19 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
1595
1638
|
|
|
1596
1639
|
state.sessionId = config.resume || config.sessionId || state.sessionId;
|
|
1597
1640
|
state.status = "running";
|
|
1598
|
-
state.activeGoal = prompt
|
|
1641
|
+
state.activeGoal = compactLine(prompt, 84);
|
|
1599
1642
|
state.lastEvent = "";
|
|
1600
|
-
printSystemLine(`session=${state.sessionId}`);
|
|
1601
|
-
printSystemLine(`status=running workingOn=${state.activeGoal}`);
|
|
1602
1643
|
|
|
1603
1644
|
const store = new SessionStore(config.sessionsDir, state.sessionId);
|
|
1604
1645
|
const liveInput = new LiveRunInput({ state, store, controller });
|
|
1605
1646
|
const liveStarted = liveInput.start();
|
|
1606
1647
|
const detachInterrupts = liveStarted ? () => {} : attachRunInterrupts(controller);
|
|
1648
|
+
if (liveStarted) {
|
|
1649
|
+
liveInput.setStatus(`running · ${state.activeGoal}`);
|
|
1650
|
+
} else {
|
|
1651
|
+
printSystemLine(`session=${state.sessionId}`);
|
|
1652
|
+
printSystemLine(`status=running workingOn=${state.activeGoal}`);
|
|
1653
|
+
}
|
|
1607
1654
|
let result;
|
|
1608
1655
|
let queuedAfterFinish = [];
|
|
1609
1656
|
try {
|
|
@@ -1619,6 +1666,9 @@ async function runPrompt(prompt, state, packageDir) {
|
|
|
1619
1666
|
printHeading(text);
|
|
1620
1667
|
} else if (options.error) {
|
|
1621
1668
|
outputLine(`${label("error", ansi.systemBg)} ${stripMarkdown(text)}`);
|
|
1669
|
+
} else if (options.kind === "meta" && liveStarted) {
|
|
1670
|
+
const trimmed = String(text || "").trim();
|
|
1671
|
+
if (trimmed) liveInput.setStatus(trimmed);
|
|
1622
1672
|
} else {
|
|
1623
1673
|
printSystemLine(text);
|
|
1624
1674
|
}
|