@menteeai/menteeswe 0.1.23 → 0.1.25

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.
Files changed (2) hide show
  1. package/dist/cli.js +135 -64
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -408,8 +408,8 @@ function formatEvent(event) {
408
408
  const req = typeof event.data?.request === "number" ? event.data.request : 0;
409
409
  const inTok = typeof event.data?.inputTokens === "number" ? event.data.inputTokens : 0;
410
410
  const outTok = typeof event.data?.outputTokens === "number" ? event.data.outputTokens : 0;
411
- const fmtK = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
412
- return chalk.dim(` \u21C5 req #${req} \xB7 ctx ${fmtK(inTok)} tok \xB7 out ${fmtK(outTok)} tok`);
411
+ const fmtK2 = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
412
+ return chalk.dim(` \u21C5 req #${req} \xB7 ctx ${fmtK2(inTok)} tok \xB7 out ${fmtK2(outTok)} tok`);
413
413
  }
414
414
  case "info":
415
415
  return chalk.cyan.bold(`\u{1F4AD} ${event.message ?? ""}`);
@@ -1306,7 +1306,7 @@ var init_loop = __esm({
1306
1306
  var version;
1307
1307
  var init_package = __esm({
1308
1308
  "package.json"() {
1309
- version = "0.1.23";
1309
+ version = "0.1.25";
1310
1310
  }
1311
1311
  });
1312
1312
 
@@ -1641,9 +1641,29 @@ __export(App_exports, {
1641
1641
  App: () => App
1642
1642
  });
1643
1643
  import { useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState3 } from "react";
1644
- import { Box as Box6, Static, Text as Text6, useApp, useInput as useInput4, useStdout } from "ink";
1644
+ import { Box as Box6, Text as Text6, useApp, useInput as useInput4, useStdout } from "ink";
1645
1645
  import TextInput2 from "ink-text-input";
1646
1646
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1647
+ function wrappedH(text, w) {
1648
+ const width = Math.max(10, w - 2);
1649
+ let n = 0;
1650
+ for (const ln of text.split("\n")) n += Math.max(1, Math.ceil(ln.length / width));
1651
+ return n;
1652
+ }
1653
+ function lineH(l, w) {
1654
+ if (l.kind === "task") return 3 + wrappedH(l.text, w);
1655
+ if (l.kind === "answer") return 2 + wrappedH(l.text, w);
1656
+ if (l.kind === "patch" && l.edit) {
1657
+ const c = compactChanges(l.edit.old, l.edit.new);
1658
+ const removed = c.removed.slice(0, 24);
1659
+ const added = c.added.slice(0, 24);
1660
+ let h = 3;
1661
+ for (const ln of removed) h += Math.max(1, Math.ceil((ln.length + 3) / Math.max(10, w - 2)));
1662
+ for (const ln of added) h += Math.max(1, Math.ceil((ln.length + 3) / Math.max(10, w - 2)));
1663
+ return h;
1664
+ }
1665
+ return wrappedH(l.text, w);
1666
+ }
1647
1667
  function TaskBlock({ text }) {
1648
1668
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
1649
1669
  /* @__PURE__ */ jsx6(Text6, { color: "magenta", bold: true, children: "\u25B8 Task" }),
@@ -1681,25 +1701,21 @@ function App(props) {
1681
1701
  const [showEdits, setShowEdits] = useState3(true);
1682
1702
  const [taskSummary, setTaskSummary] = useState3(null);
1683
1703
  const [tokenTotals, setTokenTotals] = useState3({ totalIn: 0, totalOut: 0 });
1704
+ const [scrollOffset, setScrollOffset] = useState3(0);
1705
+ const [session, setSession] = useState3({ tasks: 0, requests: 0, toolCalls: 0, iterations: 0, files: 0 });
1684
1706
  const finalTextRef = useRef(null);
1685
1707
  const pendingTool = useRef(null);
1686
1708
  const counter = useRef(0);
1687
1709
  const stateRef = useRef({ running, approval, dialog, factoryResult, providerName, model });
1688
1710
  stateRef.current = { running, approval, dialog, factoryResult, providerName, model };
1689
1711
  const abortRef = useRef(null);
1690
- const showDetailsRef = useRef(showDetails);
1691
- showDetailsRef.current = showDetails;
1692
- const showEditsRef = useRef(showEdits);
1693
- showEditsRef.current = showEdits;
1694
1712
  const appendLog = (text, noise = false, kind) => {
1695
1713
  if (!text) return;
1696
- if (noise && !showDetailsRef.current) return;
1697
1714
  counter.current += 1;
1698
1715
  const line = { id: counter.current, text, noise, kind };
1699
1716
  setLog((prev) => [...prev, line]);
1700
1717
  };
1701
1718
  const appendPatchEdit = (edit) => {
1702
- if (!showEditsRef.current) return;
1703
1719
  counter.current += 1;
1704
1720
  setLog((prev) => [...prev, { id: counter.current, text: "", noise: false, kind: "patch", edit }]);
1705
1721
  };
@@ -1730,8 +1746,20 @@ function App(props) {
1730
1746
  const totalOut = typeof event.data?.totalOut === "number" ? event.data.totalOut : 0;
1731
1747
  setTokenTotals({ totalIn, totalOut });
1732
1748
  }
1749
+ if (event.type === "model_request") {
1750
+ setSession((s) => ({ ...s, requests: s.requests + 1 }));
1751
+ }
1752
+ if (event.type === "tool_completed") {
1753
+ setSession((s) => ({ ...s, toolCalls: s.toolCalls + 1 }));
1754
+ }
1733
1755
  if (event.type === "task_completed") {
1734
1756
  setTaskSummary(formatEvent(event));
1757
+ setSession((s) => ({
1758
+ ...s,
1759
+ tasks: s.tasks + 1,
1760
+ iterations: s.iterations + (typeof event.data?.iterations === "number" ? event.data.iterations : 0),
1761
+ files: s.files + (Array.isArray(event.data?.modifiedFiles) ? event.data.modifiedFiles.length : 0)
1762
+ }));
1735
1763
  const text = typeof event.data?.finalText === "string" ? event.data.finalText.trim() : "";
1736
1764
  if (text) {
1737
1765
  finalTextRef.current = text;
@@ -1947,6 +1975,7 @@ function App(props) {
1947
1975
  setRunning(true);
1948
1976
  setTaskSummary(null);
1949
1977
  setTokenTotals({ totalIn: 0, totalOut: 0 });
1978
+ setScrollOffset(0);
1950
1979
  const ac = new AbortController();
1951
1980
  abortRef.current = ac;
1952
1981
  try {
@@ -2016,42 +2045,91 @@ function App(props) {
2016
2045
  setShowEdits((v) => !v);
2017
2046
  return;
2018
2047
  }
2048
+ if (!stateRef.current.dialog && !stateRef.current.approval) {
2049
+ if (key.pageUp) {
2050
+ setScrollOffset((o) => o + 10);
2051
+ return;
2052
+ }
2053
+ if (key.pageDown) {
2054
+ setScrollOffset((o) => Math.max(0, o - 10));
2055
+ return;
2056
+ }
2057
+ }
2019
2058
  if (stateRef.current.dialog || stateRef.current.approval || stateRef.current.running) return;
2020
2059
  if (key.meta && (input === "m" || input === "M")) openModelDialog();
2021
2060
  else if (key.ctrl && input === "p") setDialog({ kind: "provider" });
2022
2061
  else if (key.ctrl && input === "k") setDialog({ kind: "key" });
2023
2062
  });
2024
2063
  const modelLabel = model ?? factoryResult.provider?.defaultModel ?? (factoryResult.error ? "no key" : "");
2025
- const header = /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginBottom: 1, children: [
2026
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: BANNER }),
2027
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2028
- "v",
2029
- version,
2030
- " \xB7 ",
2031
- providerName,
2032
- modelLabel ? `:${modelLabel}` : "",
2033
- " \xB7 details ",
2034
- showDetails ? "open" : "collapsed",
2035
- " \xB7 edits ",
2036
- showEdits ? "open" : "collapsed",
2037
- " \xB7 ",
2038
- props.cwd
2039
- ] }),
2040
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Alt+M model \xB7 Ctrl+P provider \xB7 Ctrl+K key \xB7 Alt+D details \xB7 Alt+E edits \xB7 /help" })
2041
- ] }, "header");
2042
2064
  const cols = stdout.columns || 80;
2043
- const marquee = thinkingText.slice(-Math.max(1, cols - 4));
2044
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
2045
- /* @__PURE__ */ jsx6(Static, { items: [{ key: "header", text: header }], children: (item) => /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: /* @__PURE__ */ jsx6(Text6, { children: item.text }) }, item.key) }),
2046
- /* @__PURE__ */ jsx6(Static, { items: log, children: (line) => line.kind === "answer" ? /* @__PURE__ */ jsx6(AnswerBlock, { text: line.text }, line.id) : line.kind === "task" ? /* @__PURE__ */ jsx6(TaskBlock, { text: line.text }, line.id) : line.kind === "patch" && line.edit ? /* @__PURE__ */ jsx6(CurrentEditBox, { edit: line.edit }, line.id) : /* @__PURE__ */ jsx6(Text6, { children: line.text }, line.id) }),
2047
- finalPending !== null ? /* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
2048
- typedText,
2049
- typing ? "\u258C" : ""
2050
- ] }) }) : null,
2051
- taskSummary ? /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { children: taskSummary }) }) : null,
2065
+ const rows = stdout.rows || 24;
2066
+ const SIDEBAR_W = 26;
2067
+ const inspectorVisible = detailsOpen && inspectorIndex !== null && toolHistory[inspectorIndex] !== void 0;
2068
+ const footerRows = (dialog ? 10 : approval ? 5 : 2) + (inspectorVisible ? 7 : 0);
2069
+ const mainInnerH = Math.max(6, rows - footerRows - 2);
2070
+ const mainInnerW = Math.max(20, cols - SIDEBAR_W - 4);
2071
+ const marquee = thinkingText.slice(-Math.max(1, mainInnerW - 4));
2072
+ const answerH = finalPending !== null ? 2 + wrappedH(typedText, mainInnerW) : 0;
2073
+ const summaryH = taskSummary ? 1 + wrappedH(taskSummary, mainInnerW) : 0;
2074
+ const visible = useMemo2(() => {
2075
+ const filtered = log.filter((l) => (showDetails || !l.noise) && (l.kind !== "patch" || showEdits));
2076
+ const sliceEnd = Math.max(0, filtered.length - scrollOffset);
2077
+ const budget = mainInnerH - answerH - summaryH - 2;
2078
+ let used = 0;
2079
+ let start = sliceEnd;
2080
+ while (start > 0) {
2081
+ const prev = filtered[start - 1];
2082
+ if (!prev) break;
2083
+ const h = lineH(prev, mainInnerW);
2084
+ if (used + h > budget) break;
2085
+ used += h;
2086
+ start--;
2087
+ }
2088
+ return filtered.slice(start, sliceEnd);
2089
+ }, [log, showDetails, showEdits, scrollOffset, mainInnerH, mainInnerW, answerH, summaryH]);
2090
+ const renderLine = (line) => line.kind === "answer" ? /* @__PURE__ */ jsx6(AnswerBlock, { text: line.text }, line.id) : line.kind === "task" ? /* @__PURE__ */ jsx6(TaskBlock, { text: line.text }, line.id) : line.kind === "patch" && line.edit ? /* @__PURE__ */ jsx6(CurrentEditBox, { edit: line.edit }, line.id) : /* @__PURE__ */ jsx6(Text6, { children: line.text }, line.id);
2091
+ const statRow = (label, value) => /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", justifyContent: "space-between", children: [
2092
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: label }),
2093
+ /* @__PURE__ */ jsx6(Text6, { children: value })
2094
+ ] }, label);
2095
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", height: rows, children: [
2096
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", flexGrow: 1, children: [
2097
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
2098
+ visible.map(renderLine),
2099
+ finalPending !== null ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
2100
+ typedText,
2101
+ typing ? "\u258C" : ""
2102
+ ] }) }) : null,
2103
+ taskSummary ? /* @__PURE__ */ jsx6(Text6, { children: taskSummary }) : null
2104
+ ] }),
2105
+ /* @__PURE__ */ jsxs6(Box6, { width: SIDEBAR_W, flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
2106
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: "magenta", children: "MenteE SWE \u{1F380}" }),
2107
+ /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2108
+ "v",
2109
+ version
2110
+ ] }),
2111
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
2112
+ statRow("provider", providerName),
2113
+ statRow("model", modelLabel.length > 18 ? modelLabel.slice(0, 17) + "\u2026" : modelLabel),
2114
+ statRow("phase", running ? PHASE_LABEL[phase] ?? "working" : "idle"),
2115
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
2116
+ statRow("tasks", String(session.tasks)),
2117
+ statRow("requests", String(session.requests)),
2118
+ statRow("\u2191 in", fmtK(tokenTotals.totalIn)),
2119
+ statRow("\u2193 out", fmtK(tokenTotals.totalOut)),
2120
+ statRow("tool calls", String(session.toolCalls)),
2121
+ statRow("iterations", String(session.iterations)),
2122
+ statRow("files", String(session.files)),
2123
+ statRow("details", showDetails ? "on" : "off"),
2124
+ statRow("edits", showEdits ? "on" : "off"),
2125
+ /* @__PURE__ */ jsx6(Text6, { children: " " }),
2126
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "menteeai.org" }),
2127
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "@menteeaiorg" })
2128
+ ] })
2129
+ ] }),
2052
2130
  detailsOpen && inspectorIndex !== null && toolHistory[inspectorIndex] ? (() => {
2053
2131
  const rec = toolHistory[inspectorIndex];
2054
- const outLines = rec.output.split("\n").slice(0, 24).join("\n");
2132
+ const outLines = rec.output.split("\n").slice(0, 20).join("\n");
2055
2133
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
2056
2134
  /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2057
2135
  " tool details (",
@@ -2118,26 +2196,20 @@ function App(props) {
2118
2196
  if (decision === "always") bus.emit("info", "Approved for the rest of this session.");
2119
2197
  }
2120
2198
  }
2121
- ) : running ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
2122
- /* @__PURE__ */ jsxs6(Box6, { children: [
2123
- /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
2124
- SPINNER_FRAMES[frame],
2125
- " "
2126
- ] }),
2127
- /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2128
- "agent ",
2129
- PHASE_LABEL[phase] ?? "working",
2130
- "\u2026",
2131
- tokenTotals.totalIn + tokenTotals.totalOut > 0 ? ` \xB7 ${((tokenTotals.totalIn + tokenTotals.totalOut) / 1e3).toFixed(1)}k tok` : "",
2132
- " (Ctrl+C to exit)"
2133
- ] })
2199
+ ) : running ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
2200
+ /* @__PURE__ */ jsxs6(Text6, { color: "yellow", children: [
2201
+ SPINNER_FRAMES[frame],
2202
+ " "
2134
2203
  ] }),
2135
- thinkingText ? /* @__PURE__ */ jsxs6(Box6, { children: [
2136
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u{1F4AD} " }),
2137
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", dimColor: true, children: marquee }),
2138
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u258C" })
2139
- ] }) : null
2140
- ] }) : /* @__PURE__ */ jsxs6(Box6, { children: [
2204
+ /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
2205
+ "agent ",
2206
+ PHASE_LABEL[phase] ?? "working",
2207
+ "\u2026",
2208
+ tokenTotals.totalIn + tokenTotals.totalOut > 0 ? ` \xB7 ${fmtK(tokenTotals.totalIn + tokenTotals.totalOut)} tok` : "",
2209
+ " \xB7 ",
2210
+ thinkingText ? `\u{1F4AD} ${marquee}` : "Ctrl+C to cancel"
2211
+ ] })
2212
+ ] }) : /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", children: [
2141
2213
  /* @__PURE__ */ jsx6(Text6, { color: "cyan", bold: true, children: "\u25B8 " }),
2142
2214
  /* @__PURE__ */ jsx6(
2143
2215
  TextInput2,
@@ -2148,10 +2220,14 @@ function App(props) {
2148
2220
  placeholder: "Describe a task, or /help"
2149
2221
  }
2150
2222
  )
2151
- ] })
2223
+ ] }),
2224
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: (scrollOffset > 0 ? `\u2191${scrollOffset} hidden \xB7 ` : "") + "Alt+M model \xB7 Ctrl+P provider \xB7 Ctrl+K key \xB7 Alt+D details \xB7 Alt+E edits \xB7 PgUp/PgDn scroll \xB7 /help".slice(
2225
+ 0,
2226
+ Math.max(10, cols - (scrollOffset > 0 ? 16 : 0))
2227
+ ) })
2152
2228
  ] });
2153
2229
  }
2154
- var SPINNER_FRAMES, PHASE_LABEL, PROVIDER_NAMES, PROVIDER_DESCRIPTIONS, BANNER;
2230
+ var SPINNER_FRAMES, PHASE_LABEL, PROVIDER_NAMES, PROVIDER_DESCRIPTIONS, fmtK;
2155
2231
  var init_App = __esm({
2156
2232
  "src/tui/App.tsx"() {
2157
2233
  "use strict";
@@ -2190,12 +2266,7 @@ var init_App = __esm({
2190
2266
  nvidia: "NVIDIA NIM \xB7 build.nvidia.com hosted models",
2191
2267
  mock: "offline testing \xB7 no network"
2192
2268
  };
2193
- BANNER = ` __ __ \u{1F380}
2194
- | \\/ |
2195
- | |
2196
- | |
2197
- MenteE SWE \u2014 https://menteeai.org
2198
- Twitter: x.com/menteeaiorg`;
2269
+ fmtK = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
2199
2270
  }
2200
2271
  });
2201
2272
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@menteeai/menteeswe",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "MenteE SWE — a model-agnostic autonomous software-engineering agent CLI. Bring your own intelligence: Kimi, GLM/Z.ai, and more.",
5
5
  "type": "module",
6
6
  "license": "MIT",