@lazyingart/agintiflow 0.20.173 → 0.20.174

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.173",
3
+ "version": "0.20.174",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
package/public/app.js CHANGED
@@ -1796,6 +1796,83 @@ function renderPlanEvent(entry) {
1796
1796
  `;
1797
1797
  }
1798
1798
 
1799
+ function embeddedWorkspaceChangesFromText(value = "") {
1800
+ const lines = String(value || "").split(/\r?\n/);
1801
+ const changes = [];
1802
+ let currentTool = "";
1803
+
1804
+ for (let index = 0; index < lines.length; index += 1) {
1805
+ const toolMatch = lines[index].match(/^\s*Tool:\s*(.+?)\s*$/i);
1806
+ if (toolMatch) {
1807
+ currentTool = toolMatch[1].trim();
1808
+ continue;
1809
+ }
1810
+
1811
+ const pathMatch = lines[index].match(/^\s*Path:\s*(.+?)\s*$/i);
1812
+ if (!pathMatch) continue;
1813
+
1814
+ let cursor = index + 1;
1815
+ while (cursor < lines.length && !/^\s*Diff:\s*$/i.test(lines[cursor]) && !/^\s*(?:Tool|Path):\s*/i.test(lines[cursor])) {
1816
+ cursor += 1;
1817
+ }
1818
+ if (!/^\s*Diff:\s*$/i.test(lines[cursor] || "")) continue;
1819
+
1820
+ const diffLines = [];
1821
+ cursor += 1;
1822
+ while (cursor < lines.length) {
1823
+ if (diffLines.length && /^\s*(?:Tool|Path):\s*/i.test(lines[cursor])) break;
1824
+ if (
1825
+ diffLines.length &&
1826
+ /^\s*(?:Output:|No command output|Blocked by guardrail\.|Mock run complete\.)/i.test(lines[cursor]) &&
1827
+ !/^[-+@ ]/.test(lines[cursor])
1828
+ ) {
1829
+ break;
1830
+ }
1831
+ diffLines.push(lines[cursor]);
1832
+ cursor += 1;
1833
+ }
1834
+ while (diffLines.length && !diffLines[diffLines.length - 1].trim()) diffLines.pop();
1835
+ if (diffLines.length) {
1836
+ changes.push({
1837
+ toolName: currentTool || "write_file",
1838
+ path: pathMatch[1].trim(),
1839
+ diff: diffLines.join("\n"),
1840
+ });
1841
+ index = Math.max(index, cursor - 1);
1842
+ }
1843
+ }
1844
+
1845
+ return changes;
1846
+ }
1847
+
1848
+ function embeddedWorkspaceSummary(value = "") {
1849
+ const summary = [];
1850
+ let skippingDiff = false;
1851
+ for (const line of String(value || "").split(/\r?\n/)) {
1852
+ if (/^\s*Diff:\s*$/i.test(line)) {
1853
+ skippingDiff = true;
1854
+ continue;
1855
+ }
1856
+ if (skippingDiff && /^\s*(?:Tool|Path):\s*/i.test(line)) skippingDiff = false;
1857
+ if (skippingDiff) continue;
1858
+ if (/^\s*Path:\s*/i.test(line)) continue;
1859
+ summary.push(line);
1860
+ }
1861
+ return summary.join("\n").replace(/\n{3,}/g, "\n\n").trim();
1862
+ }
1863
+
1864
+ function renderEmbeddedWorkspaceResult(value = "", entry = {}) {
1865
+ const changes = embeddedWorkspaceChangesFromText(value);
1866
+ if (changes.length === 0) return "";
1867
+ const summary = embeddedWorkspaceSummary(value);
1868
+ return `
1869
+ ${summary ? `<div class="event-result-summary markdown-body">${renderMarkdown(summary)}</div>` : ""}
1870
+ <div class="embedded-change-list">
1871
+ ${changes.map((change) => renderWorkspaceChangeEvent({ data: change, at: entry.at, content: change.path })).join("")}
1872
+ </div>
1873
+ `;
1874
+ }
1875
+
1799
1876
  function renderWorkspaceChangeEvent(entry) {
1800
1877
  const data = entry.data || {};
1801
1878
  const toolName = data.toolName || data.action || "file.changed";
@@ -1833,14 +1910,18 @@ function renderToolEvent(entry) {
1833
1910
  const skipped = message === "tool.skipped";
1834
1911
  const toolName = data.toolName || "tool";
1835
1912
  const args = data.args || {};
1913
+ const resultText = String(data.result || args.result || "");
1914
+ const embeddedResult = resultText ? renderEmbeddedWorkspaceResult(resultText, entry) : "";
1836
1915
  const argPreview =
1837
- toolName === "run_command" && args.command
1916
+ toolName === "finish"
1917
+ ? ""
1918
+ : toolName === "run_command" && args.command
1838
1919
  ? args.command
1839
1920
  : args.path || args.url || args.query || args.q || (Object.keys(args).length ? JSON.stringify(args) : "");
1840
1921
  const stdout = data.stdout ? outputPreviewText(data.stdout) : null;
1841
1922
  const stderr = data.stderr ? outputPreviewText(data.stderr) : null;
1842
1923
  return `
1843
- <article class="event-card ${failed ? "event-failed" : skipped ? "event-muted" : "event-tool"}">
1924
+ <article class="event-card ${failed ? "event-failed" : skipped ? "event-muted" : toolName === "finish" ? "event-finish" : "event-tool"}">
1844
1925
  <div class="event-card-meta">
1845
1926
  <span>${escapeHtml(failed ? "tool failed" : skipped ? "tool skipped" : message === "tool.started" ? "tool" : "tool done")}</span>
1846
1927
  <span>${entry.at ? escapeHtml(new Date(entry.at).toLocaleString()) : ""}</span>
@@ -1848,6 +1929,7 @@ function renderToolEvent(entry) {
1848
1929
  <strong class="event-path">${escapeHtml(toolName)}</strong>
1849
1930
  ${argPreview ? `<code class="event-inline-code">${escapeHtml(argPreview)}</code>` : ""}
1850
1931
  ${data.error || data.reason ? `<div class="event-fold-note">${escapeHtml(data.error || data.reason)}</div>` : ""}
1932
+ ${embeddedResult || (toolName === "finish" && resultText ? `<div class="markdown-body">${renderMarkdown(resultText)}</div>` : "")}
1851
1933
  ${stdout ? `<div class="log-stream-title">stdout</div><pre class="event-output">${escapeHtml(stdout.text)}</pre>` : ""}
1852
1934
  ${stdout?.hidden > 0 ? `<div class="event-fold-note">... ${stdout.hidden} more stdout line(s) folded</div>` : ""}
1853
1935
  ${stderr ? `<div class="log-stream-title">stderr</div><pre class="event-output">${escapeHtml(stderr.text)}</pre>` : ""}
@@ -1862,13 +1944,14 @@ function renderStatusEvent(entry) {
1862
1944
  const label = entry.eventLabel || message.replace(/^[^.]+\./, "");
1863
1945
  const content = data.result || data.error || data.reason || entry.content || "";
1864
1946
  const failed = message === "session.failed";
1947
+ const embeddedResult = content ? renderEmbeddedWorkspaceResult(content, entry) : "";
1865
1948
  return `
1866
- <article class="event-card ${failed ? "event-failed" : "event-muted"}">
1949
+ <article class="event-card ${failed ? "event-failed" : message === "session.finished" && embeddedResult ? "event-finish" : "event-muted"}">
1867
1950
  <div class="event-card-meta">
1868
1951
  <span>${escapeHtml(label)}</span>
1869
1952
  <span>${entry.at ? escapeHtml(new Date(entry.at).toLocaleString()) : ""}</span>
1870
1953
  </div>
1871
- ${content ? `<div class="chat-content">${escapeHtml(content)}</div>` : ""}
1954
+ ${embeddedResult || (content ? `<div class="chat-content">${escapeHtml(content)}</div>` : "")}
1872
1955
  </article>
1873
1956
  `;
1874
1957
  }
@@ -1909,9 +1992,14 @@ function renderStructuredEvent(entry) {
1909
1992
 
1910
1993
  function renderLogs(run) {
1911
1994
  logsEl.dataset.mode = "active";
1995
+ const structuredRunResult = run.result ? renderEmbeddedWorkspaceResult(run.result, { at: run.endedAt || run.updatedAt || "" }) : "";
1912
1996
  const parts = [
1913
1997
  `<div class="log-line">${escapeHtml(`status=${run.status} session=${run.sessionId} provider=${run.provider} model=${run.model}`)}</div>`,
1914
- run.result ? `<div class="log-line">${escapeHtml(`result=${run.result}`)}</div>` : "",
1998
+ structuredRunResult
1999
+ ? `<article class="event-card event-finish"><div class="event-card-meta"><span>result</span></div>${structuredRunResult}</article>`
2000
+ : run.result
2001
+ ? `<div class="log-line">${escapeHtml(`result=${run.result}`)}</div>`
2002
+ : "",
1915
2003
  run.error ? `<div class="log-line error">${escapeHtml(`error=${run.error}`)}</div>` : "",
1916
2004
  ];
1917
2005
 
@@ -2174,6 +2262,28 @@ function renderChat(chatEntries) {
2174
2262
  </article>
2175
2263
  `;
2176
2264
  }
2265
+ if (entry.role === "tool") {
2266
+ try {
2267
+ const parsed = JSON.parse(entry.content || "{}");
2268
+ const toolName = parsed.toolName || "tool";
2269
+ return renderToolEvent({
2270
+ role: "event",
2271
+ eventType: parsed.ok === false ? "tool.failed" : "tool.completed",
2272
+ message: parsed.ok === false ? "tool.failed" : "tool.completed",
2273
+ eventLabel: parsed.ok === false ? "tool failed" : "tool done",
2274
+ data: parsed,
2275
+ content: parsed.result || toolName,
2276
+ at: entry.at,
2277
+ });
2278
+ } catch {
2279
+ return `
2280
+ <article class="event-card event-tool">
2281
+ <div class="event-card-meta">tool${entry.at ? ` · ${new Date(entry.at).toLocaleString()}` : ""}</div>
2282
+ <pre class="event-output">${escapeHtml(entry.content || "")}</pre>
2283
+ </article>
2284
+ `;
2285
+ }
2286
+ }
2177
2287
  const role = entry.role === "assistant" ? "assistant" : "user";
2178
2288
  const label = role === "assistant" ? t("assistantLabel") : t("youLabel");
2179
2289
  const content =
package/public/styles.css CHANGED
@@ -1264,6 +1264,19 @@ button.danger {
1264
1264
  border-color: rgba(59, 130, 246, 0.28);
1265
1265
  }
1266
1266
 
1267
+ .event-finish {
1268
+ border-color: rgba(16, 185, 129, 0.36);
1269
+ background:
1270
+ radial-gradient(circle at 0% 0%, rgba(16, 185, 129, 0.14), transparent 30%),
1271
+ rgba(236, 253, 245, 0.46);
1272
+ }
1273
+
1274
+ #logs .event-finish {
1275
+ background:
1276
+ radial-gradient(circle at 0% 0%, rgba(16, 185, 129, 0.16), transparent 30%),
1277
+ rgba(6, 78, 59, 0.28);
1278
+ }
1279
+
1267
1280
  .event-failed {
1268
1281
  border-color: rgba(248, 113, 113, 0.45);
1269
1282
  background: rgba(127, 29, 29, 0.12);
@@ -1337,6 +1350,27 @@ button.danger {
1337
1350
  font-size: 0.8rem;
1338
1351
  }
1339
1352
 
1353
+ .event-result-summary {
1354
+ margin: 4px 0 12px;
1355
+ padding: 10px 12px;
1356
+ border-radius: 12px;
1357
+ background: rgba(15, 118, 110, 0.08);
1358
+ }
1359
+
1360
+ #logs .event-result-summary {
1361
+ background: rgba(255, 255, 255, 0.08);
1362
+ }
1363
+
1364
+ .embedded-change-list {
1365
+ display: grid;
1366
+ gap: 8px;
1367
+ }
1368
+
1369
+ .embedded-change-list > .event-card {
1370
+ margin: 0;
1371
+ box-shadow: none;
1372
+ }
1373
+
1340
1374
  #logs .event-fold-note {
1341
1375
  color: #94a3b8;
1342
1376
  }
@@ -896,6 +896,9 @@ try {
896
896
  if (!latest.stdout.includes(" write ") || !latest.stdout.includes("+Created by AgInTiFlow mock mode.")) {
897
897
  throw new Error("bare aginti resume did not replay formatted file-change diff context");
898
898
  }
899
+ if (!/\bfinish\b/.test(latest.stdout) || latest.stdout.includes('{"result":"Mock run complete')) {
900
+ throw new Error("bare aginti resume did not render finish-result diffs in formatted mode");
901
+ }
899
902
  if (latest.stdout.includes("resume note=showing chat transcript only")) {
900
903
  throw new Error("bare aginti resume regressed to chat-only history");
901
904
  }
@@ -209,6 +209,21 @@ try {
209
209
  const chatTail = (await page.locator("#chat-thread").innerText().catch(() => "")).slice(-1200);
210
210
  throw new Error(`web UI did not render formatted file-change diff event; state=${state}\nlogs tail:\n${logsTail}\nchat tail:\n${chatTail}`);
211
211
  }
212
+ try {
213
+ await page.waitForFunction(
214
+ () =>
215
+ [...document.querySelectorAll(".event-finish .change-diff")].some((node) =>
216
+ (node.textContent || "").includes("+Created by AgInTiFlow mock mode.")
217
+ ),
218
+ null,
219
+ { timeout: 30000 }
220
+ );
221
+ } catch (error) {
222
+ const state = await page.locator("#run-state").evaluate((node) => node.dataset.status || "").catch(() => "unknown");
223
+ const logsTail = (await page.locator("#logs").innerText().catch(() => "")).slice(-1200);
224
+ const chatTail = (await page.locator("#chat-thread").innerText().catch(() => "")).slice(-1200);
225
+ throw new Error(`web UI did not render formatted finish-result diff event; state=${state}\nlogs tail:\n${logsTail}\nchat tail:\n${chatTail}`);
226
+ }
212
227
 
213
228
  await page.click("#open-settings");
214
229
  await page.waitForSelector("#settings-modal[open]");
@@ -246,6 +261,7 @@ try {
246
261
  "new-session-resets-scope",
247
262
  "formatted-plan-event-card",
248
263
  "formatted-file-diff-event-card",
264
+ "formatted-finish-result-diff-card",
249
265
  "settings-provider-dropdowns",
250
266
  "settings-wrapper-dropdowns",
251
267
  ],
@@ -778,6 +778,71 @@ export function formatWorkspaceChange(change = {}) {
778
778
  };
779
779
  }
780
780
 
781
+ function embeddedWorkspaceChangesFromText(value = "") {
782
+ const lines = String(value || "").split(/\r?\n/);
783
+ const changes = [];
784
+ let currentTool = "";
785
+
786
+ for (let index = 0; index < lines.length; index += 1) {
787
+ const toolMatch = lines[index].match(/^\s*Tool:\s*(.+?)\s*$/i);
788
+ if (toolMatch) {
789
+ currentTool = toolMatch[1].trim();
790
+ continue;
791
+ }
792
+
793
+ const pathMatch = lines[index].match(/^\s*Path:\s*(.+?)\s*$/i);
794
+ if (!pathMatch) continue;
795
+
796
+ let cursor = index + 1;
797
+ while (cursor < lines.length && !/^\s*Diff:\s*$/i.test(lines[cursor]) && !/^\s*(?:Tool|Path):\s*/i.test(lines[cursor])) {
798
+ cursor += 1;
799
+ }
800
+ if (!/^\s*Diff:\s*$/i.test(lines[cursor] || "")) continue;
801
+
802
+ const diffLines = [];
803
+ cursor += 1;
804
+ while (cursor < lines.length) {
805
+ if (diffLines.length && /^\s*(?:Tool|Path):\s*/i.test(lines[cursor])) break;
806
+ if (
807
+ diffLines.length &&
808
+ /^\s*(?:Output:|No command output|Blocked by guardrail\.|Mock run complete\.)/i.test(lines[cursor]) &&
809
+ !/^[-+@ ]/.test(lines[cursor])
810
+ ) {
811
+ break;
812
+ }
813
+ diffLines.push(lines[cursor]);
814
+ cursor += 1;
815
+ }
816
+ while (diffLines.length && !diffLines[diffLines.length - 1].trim()) diffLines.pop();
817
+ if (diffLines.length) {
818
+ changes.push({
819
+ toolName: currentTool || "write_file",
820
+ path: pathMatch[1].trim(),
821
+ diff: diffLines.join("\n"),
822
+ });
823
+ index = Math.max(index, cursor - 1);
824
+ }
825
+ }
826
+
827
+ return changes;
828
+ }
829
+
830
+ function embeddedWorkspaceSummary(value = "") {
831
+ const summary = [];
832
+ let skippingDiff = false;
833
+ for (const line of String(value || "").split(/\r?\n/)) {
834
+ if (/^\s*Diff:\s*$/i.test(line)) {
835
+ skippingDiff = true;
836
+ continue;
837
+ }
838
+ if (skippingDiff && /^\s*(?:Tool|Path):\s*/i.test(line)) skippingDiff = false;
839
+ if (skippingDiff) continue;
840
+ if (/^\s*Path:\s*/i.test(line)) continue;
841
+ summary.push(line);
842
+ }
843
+ return summary.join("\n").replace(/\n{3,}/g, "\n\n").trim();
844
+ }
845
+
781
846
  function printWorkspaceChange(change = {}) {
782
847
  if (!change?.diff) return;
783
848
  const formatted = formatWorkspaceChange(change);
@@ -787,6 +852,15 @@ function printWorkspaceChange(change = {}) {
787
852
  for (const line of formatted.lines) outputLine(`${gutter}${line}`);
788
853
  }
789
854
 
855
+ function printEmbeddedWorkspaceResult(result = "", { labelName = "finish", time = "" } = {}) {
856
+ const changes = embeddedWorkspaceChangesFromText(result);
857
+ if (changes.length === 0) return false;
858
+ const summary = embeddedWorkspaceSummary(result);
859
+ if (summary) printHistoryBlock(labelName, summary, { time, bg: ansi.systemBg });
860
+ for (const change of changes) printWorkspaceChange(change);
861
+ return true;
862
+ }
863
+
790
864
  function printPreviewBlock(role, text, { time = "", bg = ansi.systemBg, maxLines = 5 } = {}) {
791
865
  const header = [label(role, bg).trimEnd(), time ? color(time, ansi.dim) : ""].filter(Boolean).join(" ");
792
866
  outputLine(header);
@@ -2201,6 +2275,24 @@ async function latestSession() {
2201
2275
  }
2202
2276
 
2203
2277
  function printHistoryEntry(entry) {
2278
+ if (entry.role === "tool") {
2279
+ const time = entry.at ? new Date(entry.at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "";
2280
+ try {
2281
+ const parsed = JSON.parse(entry.content || "{}");
2282
+ if (parsed.toolName === "finish" && printEmbeddedWorkspaceResult(parsed.result || parsed.args?.result || "", { labelName: "finish", time })) {
2283
+ return;
2284
+ }
2285
+ if (parsed.diff) {
2286
+ printWorkspaceChange(parsed);
2287
+ return;
2288
+ }
2289
+ outputLine(`${label(parsed.ok === false ? "fail" : "done", parsed.ok === false ? ansi.red : ansi.systemBg)} ${toolStatusDetails(parsed)}`);
2290
+ return;
2291
+ } catch {
2292
+ printHistoryBlock("tool", entry.content, { time, bg: ansi.systemBg });
2293
+ return;
2294
+ }
2295
+ }
2204
2296
  const role = entry.role === "assistant" ? "aginti>" : entry.role === "user" ? "user>" : String(entry.role || "note");
2205
2297
  const bg = role === "aginti>" ? ansi.agentBg : role === "user>" ? ansi.userBg : ansi.systemBg;
2206
2298
  const time = entry.at ? new Date(entry.at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : "";
@@ -2279,6 +2371,9 @@ function printResumeEvent(event = {}) {
2279
2371
  printWorkspaceChange(data);
2280
2372
  return true;
2281
2373
  }
2374
+ if (data.toolName === "finish" && printEmbeddedWorkspaceResult(data.result || data.args?.result || "", { labelName: "finish" })) {
2375
+ return true;
2376
+ }
2282
2377
  if (data.toolName === "run_command") {
2283
2378
  printCommandOutputLog({
2284
2379
  command: data.args?.command || data.command || "",
@@ -2318,6 +2413,7 @@ function printResumeEvent(event = {}) {
2318
2413
  return true;
2319
2414
  }
2320
2415
  if (type === "session.finished") {
2416
+ if (printEmbeddedWorkspaceResult(data.result || "", { labelName: "finish" })) return true;
2321
2417
  outputLine(`${label("state", ansi.systemBg)} status=finished${data.result ? ` result=${compactLine(data.result, 86)}` : ""}`);
2322
2418
  return true;
2323
2419
  }
@@ -4178,7 +4274,11 @@ async function runPrompt(prompt, state, packageDir, { approvalDepth = 0 } = {})
4178
4274
  } else if (type === "tool.started") {
4179
4275
  printStatusEvent(state, "tool", toolStatusDetails(data));
4180
4276
  } else if (type === "tool.completed" || type === "tool.failed") {
4181
- printStatusEvent(state, type === "tool.failed" || data.ok === false ? "tool_failed" : "tool_done", toolStatusDetails(data));
4277
+ if (data.toolName === "finish" && printEmbeddedWorkspaceResult(data.result || data.args?.result || "", { labelName: "finish" })) {
4278
+ // The finish tool can recap a workspace diff; render it like the original write/patch event.
4279
+ } else {
4280
+ printStatusEvent(state, type === "tool.failed" || data.ok === false ? "tool_failed" : "tool_done", toolStatusDetails(data));
4281
+ }
4182
4282
  } else if (type === "file.changed") {
4183
4283
  printWorkspaceChange(data);
4184
4284
  } else if (type === "tool.blocked") {