buildwithnexus 0.8.7 → 0.8.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.
package/dist/bin.js CHANGED
@@ -1605,10 +1605,25 @@ init_secrets();
1605
1605
  init_docker();
1606
1606
 
1607
1607
  // src/core/version.ts
1608
- var resolvedVersion = true ? "0.8.7" : pkg.version;
1608
+ var resolvedVersion = true ? "0.8.8" : pkg.version;
1609
1609
 
1610
1610
  // src/cli/interactive.ts
1611
1611
  var appVersion = resolvedVersion;
1612
+ var SSE_STALL_WARNING_MS = 8e3;
1613
+ async function reportBackendError(label, response) {
1614
+ let bodySnippet = "";
1615
+ try {
1616
+ const text = await response.text();
1617
+ bodySnippet = text.slice(0, 300);
1618
+ } catch {
1619
+ bodySnippet = "(could not read response body)";
1620
+ }
1621
+ console.error(chalk3.red(`${label}: HTTP ${response.status} ${response.statusText}`));
1622
+ if (bodySnippet) {
1623
+ console.error(chalk3.gray(` body: ${bodySnippet}`));
1624
+ }
1625
+ console.error(chalk3.gray(" Tip: stream backend logs with `buildwithnexus logs -f`"));
1626
+ }
1612
1627
  async function interactiveMode() {
1613
1628
  const backendUrl = process.env.BACKEND_URL || "http://localhost:4200";
1614
1629
  const urlCheck = validateBackendUrl(backendUrl);
@@ -1782,7 +1797,7 @@ async function planModeLoop(task, backendUrl, currentMode, ask) {
1782
1797
  signal: AbortSignal.timeout(12e4)
1783
1798
  });
1784
1799
  if (!response.ok) {
1785
- console.error(chalk3.red("Backend error \u2014 cannot fetch plan."));
1800
+ await reportBackendError("Backend error fetching plan", response);
1786
1801
  return "cancel";
1787
1802
  }
1788
1803
  const planText = await response.text();
@@ -1806,27 +1821,36 @@ async function planModeLoop(task, backendUrl, currentMode, ask) {
1806
1821
  tui.displayConnected(run_id);
1807
1822
  const streamResponse = await fetch(`${backendUrl}/api/stream/${run_id}`, { signal: AbortSignal.timeout(12e4) });
1808
1823
  if (!streamResponse.ok) {
1809
- console.error(chalk3.red(`Stream endpoint returned ${streamResponse.status}`));
1824
+ await reportBackendError("Stream endpoint error", streamResponse);
1810
1825
  return "cancel";
1811
1826
  }
1812
1827
  const reader = streamResponse.body?.getReader();
1813
1828
  if (!reader) throw new Error("No response body");
1814
1829
  let planReceived = false;
1815
- for await (const parsed of parseSSEStream(reader)) {
1816
- if (parsed.type === "plan") {
1817
- steps = parsed.data["steps"] || [];
1818
- planReceived = true;
1819
- reader.cancel();
1820
- break;
1821
- } else if (parsed.type === "error") {
1822
- const errorMsg = parsed.data["error"] || parsed.data["content"] || "Unknown error";
1823
- tui.displayError(errorMsg);
1824
- reader.cancel();
1825
- return "cancel";
1830
+ const stallTimer = setTimeout(() => {
1831
+ console.log(chalk3.gray(`(no events from backend after ${SSE_STALL_WARNING_MS / 1e3}s \u2014 backend may be stalled; check \`buildwithnexus logs -f\`)`));
1832
+ }, SSE_STALL_WARNING_MS);
1833
+ try {
1834
+ for await (const parsed of parseSSEStream(reader)) {
1835
+ if (parsed.type === "plan") {
1836
+ steps = parsed.data["steps"] || [];
1837
+ planReceived = true;
1838
+ reader.cancel();
1839
+ break;
1840
+ } else if (parsed.type === "error") {
1841
+ const errorMsg = parsed.data["error"] || parsed.data["content"] || "Unknown error";
1842
+ tui.displayError(errorMsg);
1843
+ reader.cancel();
1844
+ return "cancel";
1845
+ }
1826
1846
  }
1847
+ } finally {
1848
+ clearTimeout(stallTimer);
1827
1849
  }
1828
1850
  if (!planReceived || steps.length === 0) {
1829
1851
  console.log(chalk3.yellow("No plan received from backend."));
1852
+ console.log(chalk3.gray(" This usually means the backend exited without emitting a plan event."));
1853
+ console.log(chalk3.gray(" Check `buildwithnexus logs -f` for the underlying error."));
1830
1854
  steps = ["(no steps returned \u2014 execute anyway?)"];
1831
1855
  }
1832
1856
  } catch (err) {
@@ -1841,7 +1865,7 @@ async function planModeLoop(task, backendUrl, currentMode, ask) {
1841
1865
  if (answer === "" || answer === "y") {
1842
1866
  return "BUILD";
1843
1867
  }
1844
- if (answer === "n" || answer === "\x1B") {
1868
+ if (answer === "n" || answer === "") {
1845
1869
  console.log(chalk3.yellow("\nExecution cancelled.\n"));
1846
1870
  return "cancel";
1847
1871
  }
@@ -1893,7 +1917,7 @@ async function buildModeLoop(task, backendUrl, currentMode, ask) {
1893
1917
  signal: AbortSignal.timeout(12e4)
1894
1918
  });
1895
1919
  if (!response.ok) {
1896
- console.error(chalk3.red("Backend error"));
1920
+ await reportBackendError("Backend error starting run", response);
1897
1921
  return "done";
1898
1922
  }
1899
1923
  const buildText = await response.text();
@@ -1919,30 +1943,45 @@ async function buildModeLoop(task, backendUrl, currentMode, ask) {
1919
1943
  tui.displayStreamStart();
1920
1944
  const streamResponse = await fetch(`${backendUrl}/api/stream/${run_id}`, { signal: AbortSignal.timeout(12e4) });
1921
1945
  if (!streamResponse.ok) {
1922
- console.error(chalk3.red(`Stream endpoint returned ${streamResponse.status}`));
1946
+ await reportBackendError("Stream endpoint error", streamResponse);
1923
1947
  return "done";
1924
1948
  }
1925
1949
  const reader = streamResponse.body?.getReader();
1926
1950
  if (!reader) throw new Error("No response body");
1927
- for await (const parsed of parseSSEStream(reader)) {
1928
- const type = parsed.type;
1929
- if (type === "execution_complete") {
1930
- const summary = parsed.data["summary"] || "";
1931
- const count = parsed.data["todos_completed"] || 0;
1932
- tui.displayResults(summary, count);
1933
- tui.displayComplete(tui.getElapsedTime());
1934
- break;
1935
- } else if (type === "done") {
1936
- tui.displayEvent(type, { content: "Task completed successfully" });
1937
- tui.displayComplete(tui.getElapsedTime());
1938
- break;
1939
- } else if (type === "error") {
1940
- const errorMsg = parsed.data["error"] || parsed.data["content"] || "Unknown error";
1941
- tui.displayError(errorMsg);
1942
- break;
1943
- } else if (type !== "plan") {
1944
- tui.displayEvent(type, parsed.data);
1951
+ let sawTerminal = false;
1952
+ const stallTimer = setTimeout(() => {
1953
+ console.log(chalk3.gray(`(no events from backend after ${SSE_STALL_WARNING_MS / 1e3}s \u2014 backend may be stalled; check \`buildwithnexus logs -f\`)`));
1954
+ }, SSE_STALL_WARNING_MS);
1955
+ try {
1956
+ for await (const parsed of parseSSEStream(reader)) {
1957
+ const type = parsed.type;
1958
+ if (type === "execution_complete") {
1959
+ const summary = parsed.data["summary"] || "";
1960
+ const count = parsed.data["todos_completed"] || 0;
1961
+ tui.displayResults(summary, count);
1962
+ tui.displayComplete(tui.getElapsedTime());
1963
+ sawTerminal = true;
1964
+ break;
1965
+ } else if (type === "done") {
1966
+ tui.displayEvent(type, { content: "Task completed successfully" });
1967
+ tui.displayComplete(tui.getElapsedTime());
1968
+ sawTerminal = true;
1969
+ break;
1970
+ } else if (type === "error") {
1971
+ const errorMsg = parsed.data["error"] || parsed.data["content"] || "Unknown error";
1972
+ tui.displayError(errorMsg);
1973
+ sawTerminal = true;
1974
+ break;
1975
+ } else if (type !== "plan") {
1976
+ tui.displayEvent(type, parsed.data);
1977
+ }
1945
1978
  }
1979
+ } finally {
1980
+ clearTimeout(stallTimer);
1981
+ }
1982
+ if (!sawTerminal) {
1983
+ console.log(chalk3.yellow("Stream ended without a terminal event (no execution_complete / done / error)."));
1984
+ console.log(chalk3.gray(" The backend likely crashed mid-run. Check `buildwithnexus logs -f`."));
1946
1985
  }
1947
1986
  } catch (err) {
1948
1987
  const msg = err instanceof Error ? err.message : String(err);
@@ -1972,7 +2011,9 @@ async function brainstormModeLoop(task, backendUrl, currentMode, ask) {
1972
2011
  )),
1973
2012
  signal: AbortSignal.timeout(12e4)
1974
2013
  });
1975
- if (response.ok) {
2014
+ if (!response.ok) {
2015
+ await reportBackendError("Backend error in brainstorm", response);
2016
+ } else {
1976
2017
  const brainstormText = await response.text();
1977
2018
  let brainstormParsed;
1978
2019
  try {
@@ -1993,7 +2034,7 @@ async function brainstormModeLoop(task, backendUrl, currentMode, ask) {
1993
2034
  const run_id = brainstormRunId;
1994
2035
  const streamResponse = await fetch(`${backendUrl}/api/stream/${run_id}`, { signal: AbortSignal.timeout(12e4) });
1995
2036
  if (!streamResponse.ok) {
1996
- console.error(chalk3.red(`Stream endpoint returned ${streamResponse.status}`));
2037
+ await reportBackendError("Stream endpoint error", streamResponse);
1997
2038
  continue;
1998
2039
  }
1999
2040
  const reader = streamResponse.body?.getReader();
@@ -2003,50 +2044,55 @@ async function brainstormModeLoop(task, backendUrl, currentMode, ask) {
2003
2044
  }
2004
2045
  let responseText = "";
2005
2046
  let firstEvent = true;
2006
- for await (const parsed of parseSSEStream(reader)) {
2007
- const type = parsed.type;
2008
- const data = parsed.data;
2009
- if (firstEvent && type !== "done" && type !== "error") {
2010
- console.log(chalk3.bold.blue("\u{1F4AD} Thinking...\n"));
2011
- firstEvent = false;
2012
- }
2013
- if (type === "done" || type === "execution_complete" || type === "final_result") {
2014
- const summary = data["summary"] || data["result"] || "";
2015
- if (summary) responseText = summary;
2016
- break;
2017
- } else if (type === "error") {
2018
- const errorMsg = data["error"] || data["content"] || "Unknown error";
2019
- responseText += errorMsg + "\n";
2020
- break;
2021
- } else if (type === "thought" || type === "observation") {
2022
- const content = data["content"] || "";
2023
- if (content) {
2024
- console.log(chalk3.gray("\u2192 " + content));
2025
- responseText += content + "\n";
2047
+ const stallTimer = setTimeout(() => {
2048
+ console.log(chalk3.gray(`(no events from backend after ${SSE_STALL_WARNING_MS / 1e3}s \u2014 backend may be stalled; check \`buildwithnexus logs -f\`)`));
2049
+ }, SSE_STALL_WARNING_MS);
2050
+ try {
2051
+ for await (const parsed of parseSSEStream(reader)) {
2052
+ const type = parsed.type;
2053
+ const data = parsed.data;
2054
+ if (firstEvent && type !== "done" && type !== "error") {
2055
+ console.log(chalk3.bold.blue("\u{1F4AD} Thinking...\n"));
2056
+ firstEvent = false;
2026
2057
  }
2027
- } else if (type === "agent_response" || type === "agent_result") {
2028
- const content = data["content"] || data["result"] || "";
2029
- if (content) responseText += content + "\n";
2030
- } else if (type === "action") {
2031
- const content = data["content"] || "";
2032
- if (content) {
2033
- console.log(chalk3.cyan("\u2699\uFE0F " + content));
2034
- responseText += content + "\n";
2058
+ if (type === "done" || type === "execution_complete" || type === "final_result") {
2059
+ const summary = data["summary"] || data["result"] || "";
2060
+ if (summary) responseText = summary;
2061
+ break;
2062
+ } else if (type === "error") {
2063
+ const errorMsg = data["error"] || data["content"] || "Unknown error";
2064
+ responseText += errorMsg + "\n";
2065
+ break;
2066
+ } else if (type === "thought" || type === "observation") {
2067
+ const content = data["content"] || "";
2068
+ if (content) {
2069
+ console.log(chalk3.gray("\u2192 " + content));
2070
+ responseText += content + "\n";
2071
+ }
2072
+ } else if (type === "agent_response" || type === "agent_result") {
2073
+ const content = data["content"] || data["result"] || "";
2074
+ if (content) responseText += content + "\n";
2075
+ } else if (type === "action") {
2076
+ const content = data["content"] || "";
2077
+ if (content) {
2078
+ console.log(chalk3.cyan("\u2699\uFE0F " + content));
2079
+ responseText += content + "\n";
2080
+ }
2081
+ } else if (type === "agent_working" || type === "started") {
2082
+ } else if (type !== "plan") {
2083
+ const content = data["content"] || data["response"] || "";
2084
+ if (content) responseText += content + "\n";
2035
2085
  }
2036
- } else if (type === "agent_working" || type === "started") {
2037
- } else if (type !== "plan") {
2038
- const content = data["content"] || data["response"] || "";
2039
- if (content) responseText += content + "\n";
2040
2086
  }
2087
+ } finally {
2088
+ clearTimeout(stallTimer);
2041
2089
  }
2042
2090
  console.log("");
2043
2091
  if (responseText.trim()) {
2044
2092
  tui.displayBrainstormResponse(responseText.trim());
2045
2093
  } else {
2046
- console.log(chalk3.gray("(No response received from agent)"));
2094
+ console.log(chalk3.gray("(No response received from agent \u2014 check `buildwithnexus logs -f`)"));
2047
2095
  }
2048
- } else {
2049
- console.log(chalk3.red("Could not reach backend for brainstorm response."));
2050
2096
  }
2051
2097
  } catch (err) {
2052
2098
  const msg = err instanceof Error ? err.message : String(err);
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buildwithnexus",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "Interactive AI agent orchestrator with intent-based planning, execution, and brainstorming modes",
5
5
  "type": "module",
6
6
  "bin": {