@menteeai/menteeswe 0.1.4 → 0.1.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.
Files changed (2) hide show
  1. package/dist/cli.js +137 -94
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -96,6 +96,97 @@ var init_base = __esm({
96
96
  }
97
97
  });
98
98
 
99
+ // src/tools/exec.ts
100
+ import { spawn } from "child_process";
101
+ function killTree(child) {
102
+ if (child.pid === void 0) return;
103
+ if (process.platform === "win32") {
104
+ spawn(`taskkill /pid ${String(child.pid)} /T /F`, { stdio: "ignore", shell: true });
105
+ } else {
106
+ child.kill("SIGKILL");
107
+ }
108
+ }
109
+ function killActiveChild() {
110
+ if (activeChild) killTree(activeChild);
111
+ }
112
+ async function runShellCommand(command, cwd, timeoutMs = 12e4, maxChars = 1e5) {
113
+ return new Promise((resolve) => {
114
+ const started = Date.now();
115
+ const child = spawn(command, {
116
+ shell: true,
117
+ cwd,
118
+ env: { ...process.env, MENTEE: "1" },
119
+ windowsHide: true
120
+ });
121
+ activeChild = child;
122
+ let stdout = "";
123
+ let stderr = "";
124
+ let killed = false;
125
+ const timer = setTimeout(() => {
126
+ killed = true;
127
+ killTree(child);
128
+ }, timeoutMs);
129
+ child.stdout?.on("data", (chunk) => {
130
+ if (stdout.length < maxChars * 2) stdout += chunk.toString("utf8");
131
+ });
132
+ child.stderr?.on("data", (chunk) => {
133
+ if (stderr.length < maxChars * 2) stderr += chunk.toString("utf8");
134
+ });
135
+ child.on("error", (error) => {
136
+ clearTimeout(timer);
137
+ if (activeChild === child) activeChild = null;
138
+ resolve({
139
+ exitCode: -1,
140
+ stdout,
141
+ stderr: `${stderr}
142
+ ${error.message}`.trim(),
143
+ durationMs: Date.now() - started
144
+ });
145
+ });
146
+ child.on("close", (code) => {
147
+ clearTimeout(timer);
148
+ if (activeChild === child) activeChild = null;
149
+ resolve({
150
+ exitCode: killed ? "timeout" : code ?? -1,
151
+ stdout,
152
+ stderr,
153
+ durationMs: Date.now() - started
154
+ });
155
+ });
156
+ });
157
+ }
158
+ function formatOutcome(outcome, maxChars = 1e5) {
159
+ const cut = (text, limit) => {
160
+ if (text.length <= limit) return { text, truncated: false };
161
+ const head = Math.floor(limit * 0.7);
162
+ return {
163
+ text: `${text.slice(0, head)}
164
+ ...[truncated, ${text.length - head} chars removed]...`,
165
+ truncated: true
166
+ };
167
+ };
168
+ const out = cut(outcome.stdout.trim(), maxChars);
169
+ const err = cut(outcome.stderr.trim(), Math.floor(maxChars / 2));
170
+ const sections = [`exit_code: ${outcome.exitCode}`, `duration_ms: ${outcome.durationMs}`];
171
+ if (out.text) sections.push(`stdout:
172
+ ${out.text}`);
173
+ if (err.text) sections.push(`stderr:
174
+ ${err.text}`);
175
+ if (!out.text && !err.text) sections.push("(no output)");
176
+ return {
177
+ output: sections.join("\n"),
178
+ success: outcome.exitCode === 0,
179
+ truncated: out.truncated || err.truncated
180
+ };
181
+ }
182
+ var activeChild;
183
+ var init_exec = __esm({
184
+ "src/tools/exec.ts"() {
185
+ "use strict";
186
+ activeChild = null;
187
+ }
188
+ });
189
+
99
190
  // src/events.ts
100
191
  var EventBus;
101
192
  var init_events = __esm({
@@ -159,7 +250,7 @@ function formatEvent(event) {
159
250
  case "model_request":
160
251
  return chalk.gray("\u25CF thinking...");
161
252
  case "info":
162
- return chalk.cyan(` ${event.message ?? ""}`);
253
+ return chalk.cyan.bold(`\u{1F4AD} ${event.message ?? ""}`);
163
254
  case "tool_started": {
164
255
  const tool = typeof event.data?.tool === "string" ? event.data.tool : "";
165
256
  const color = CATEGORY_COLOR[TOOL_CATEGORY[tool] ?? "other"];
@@ -202,8 +293,10 @@ function formatEvent(event) {
202
293
  const sep = chalk.dim("\u2500".repeat(48));
203
294
  const statsLine = chalk.cyan(` ${stats.join(" \xB7 ")}`);
204
295
  const statusLine = success ? chalk.green.bold("\u2714 Task completed") : chalk.red.bold("\u2716 Task failed");
205
- const block = [statusLine, sep, statsLine, sep];
206
- return block.join("\n");
296
+ const filesLine = modifiedFiles.length > 0 ? chalk.cyan.dim(` \u{1F4DD} ${modifiedFiles.length} file(s): ${modifiedFiles.join(", ")}`) : "";
297
+ const tipLine = success ? chalk.dim(" Next: type a new task, or /help for commands") : chalk.yellow.dim(" The task did not finish \u2014 check the steps above and retry");
298
+ const block = [sep, statusLine, statsLine, filesLine, tipLine, sep, ""];
299
+ return block.filter((line) => line !== "").join("\n");
207
300
  }
208
301
  default:
209
302
  return null;
@@ -593,7 +686,8 @@ async function runAgent(options) {
593
686
  bus,
594
687
  approval,
595
688
  maxIterations = 40,
596
- systemExtra
689
+ systemExtra,
690
+ signal
597
691
  } = options;
598
692
  const state = createAgentState(task, maxIterations);
599
693
  const prior = formatConversationContext(cwd);
@@ -618,6 +712,10 @@ ${systemExtra}` : "");
618
712
  let finalText = "";
619
713
  let sawFinish = false;
620
714
  while (state.iteration < maxIterations) {
715
+ if (signal?.aborted) {
716
+ finalText = "Task cancelled.";
717
+ break;
718
+ }
621
719
  state.iteration += 1;
622
720
  state.usage.modelRequests += 1;
623
721
  bus.emit("model_request", `iteration ${state.iteration}/${maxIterations}`);
@@ -774,6 +872,10 @@ ${systemExtra}` : "");
774
872
  content: result.output
775
873
  });
776
874
  }
875
+ if (signal?.aborted) {
876
+ finalText = "Task cancelled.";
877
+ break;
878
+ }
777
879
  if (estimateContextChars(messages, system) > MAX_CONTEXT_CHARS) {
778
880
  bus.emit("warning", "Context is large; trimming oldest tool outputs.");
779
881
  trimOldToolResults(messages);
@@ -784,7 +886,7 @@ ${systemExtra}` : "");
784
886
  bus.emit("warning", finalText);
785
887
  }
786
888
  const success = sawFinish && state.errors.length === 0;
787
- if (finalText) appendTurn(cwd, task, finalText);
889
+ if (finalText && !signal?.aborted) appendTurn(cwd, task, finalText);
788
890
  bus.emit("task_completed", finalText.slice(0, 400), {
789
891
  success,
790
892
  finalText,
@@ -977,7 +1079,7 @@ var init_KeyDialog = __esm({
977
1079
  var version;
978
1080
  var init_package = __esm({
979
1081
  "package.json"() {
980
- version = "0.1.4";
1082
+ version = "0.1.7";
981
1083
  }
982
1084
  });
983
1085
 
@@ -1019,6 +1121,7 @@ function App(props) {
1019
1121
  const counter = useRef(0);
1020
1122
  const stateRef = useRef({ running, approval, dialog, factoryResult, providerName, model });
1021
1123
  stateRef.current = { running, approval, dialog, factoryResult, providerName, model };
1124
+ const abortRef = useRef(null);
1022
1125
  const appendLog = (text) => {
1023
1126
  if (!text) return;
1024
1127
  counter.current += 1;
@@ -1069,6 +1172,12 @@ function App(props) {
1069
1172
  const timer = setInterval(() => setFrame((f) => (f + 1) % SPINNER_FRAMES.length), 80);
1070
1173
  return () => clearInterval(timer);
1071
1174
  }, [running]);
1175
+ useEffect2(() => {
1176
+ const turns = loadConversation(props.cwd);
1177
+ if (turns.length > 0) {
1178
+ appendLog(`Resumed previous session \u2014 ${turns.length} prior turn(s) loaded as context.`);
1179
+ }
1180
+ }, []);
1072
1181
  useEffect2(() => {
1073
1182
  if (!typing || finalPending == null) return;
1074
1183
  if (typedText.length >= finalPending.length) {
@@ -1223,6 +1332,8 @@ function App(props) {
1223
1332
  setInspectorIndex(null);
1224
1333
  setDetailsOpen(false);
1225
1334
  setRunning(true);
1335
+ const ac = new AbortController();
1336
+ abortRef.current = ac;
1226
1337
  try {
1227
1338
  await runAgent({
1228
1339
  task,
@@ -1233,7 +1344,8 @@ function App(props) {
1233
1344
  bus,
1234
1345
  approval: props.yes ? async () => "allow" : bridge.handler,
1235
1346
  maxIterations: props.maxIterations,
1236
- systemExtra: props.systemExtra
1347
+ systemExtra: props.systemExtra,
1348
+ signal: ac.signal
1237
1349
  });
1238
1350
  } catch (error) {
1239
1351
  bus.emit("error", error.message);
@@ -1270,16 +1382,22 @@ function App(props) {
1270
1382
  }
1271
1383
  };
1272
1384
  useInput4((input, key) => {
1385
+ if (key.ctrl && input === "c") {
1386
+ if (stateRef.current.running) {
1387
+ killActiveChild();
1388
+ abortRef.current?.abort();
1389
+ return;
1390
+ }
1391
+ exit();
1392
+ setTimeout(() => process.exit(0), 50);
1393
+ return;
1394
+ }
1273
1395
  if (stateRef.current.dialog || stateRef.current.approval || stateRef.current.running) return;
1274
1396
  if (key.meta && (input === "m" || input === "M")) openModelDialog();
1275
1397
  else if (key.ctrl && input === "p") setDialog({ kind: "provider" });
1276
1398
  else if (key.ctrl && input === "k") setDialog({ kind: "key" });
1277
1399
  else if (input === "d" || input === "D") cycleInspector();
1278
1400
  else if (input === "t" || input === "T") setShowTools((v) => !v);
1279
- else if (key.ctrl && input === "c") {
1280
- exit();
1281
- setTimeout(() => process.exit(0), 50);
1282
- }
1283
1401
  });
1284
1402
  const modelLabel = model ?? factoryResult.provider?.defaultModel ?? (factoryResult.error ? "no key" : "");
1285
1403
  const header = /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginBottom: 1, children: [
@@ -1410,6 +1528,8 @@ var init_App = __esm({
1410
1528
  init_render();
1411
1529
  init_approval();
1412
1530
  init_loop();
1531
+ init_conversation();
1532
+ init_exec();
1413
1533
  init_config();
1414
1534
  init_Approval();
1415
1535
  init_SelectDialog();
@@ -1424,11 +1544,10 @@ var init_App = __esm({
1424
1544
  "zai-coding": "Z.ai GLM Coding Plan subscription \xB7 api.z.ai/api/coding",
1425
1545
  mock: "offline testing \xB7 no network"
1426
1546
  };
1427
- BANNER = `|\\ /|
1428
- | \\/ |
1429
- | |
1430
- | |
1431
- \\__/
1547
+ BANNER = ` __ __ \u{1F380}
1548
+ | \\/ |
1549
+ | |
1550
+ | |
1432
1551
  MenteE SWE \u2014 https://menteeai.org
1433
1552
  Twitter: x.com/menteeaiorg`;
1434
1553
  }
@@ -2375,85 +2494,8 @@ function classifyCommand(command) {
2375
2494
  return overall;
2376
2495
  }
2377
2496
 
2378
- // src/tools/exec.ts
2379
- import { spawn } from "child_process";
2380
- function killTree(child) {
2381
- if (child.pid === void 0) return;
2382
- if (process.platform === "win32") {
2383
- spawn(`taskkill /pid ${String(child.pid)} /T /F`, { stdio: "ignore", shell: true });
2384
- } else {
2385
- child.kill("SIGKILL");
2386
- }
2387
- }
2388
- async function runShellCommand(command, cwd, timeoutMs = 12e4, maxChars = 1e5) {
2389
- return new Promise((resolve) => {
2390
- const started = Date.now();
2391
- const child = spawn(command, {
2392
- shell: true,
2393
- cwd,
2394
- env: { ...process.env, MENTEE: "1" },
2395
- windowsHide: true
2396
- });
2397
- let stdout = "";
2398
- let stderr = "";
2399
- let killed = false;
2400
- const timer = setTimeout(() => {
2401
- killed = true;
2402
- killTree(child);
2403
- }, timeoutMs);
2404
- child.stdout?.on("data", (chunk) => {
2405
- if (stdout.length < maxChars * 2) stdout += chunk.toString("utf8");
2406
- });
2407
- child.stderr?.on("data", (chunk) => {
2408
- if (stderr.length < maxChars * 2) stderr += chunk.toString("utf8");
2409
- });
2410
- child.on("error", (error) => {
2411
- clearTimeout(timer);
2412
- resolve({
2413
- exitCode: -1,
2414
- stdout,
2415
- stderr: `${stderr}
2416
- ${error.message}`.trim(),
2417
- durationMs: Date.now() - started
2418
- });
2419
- });
2420
- child.on("close", (code) => {
2421
- clearTimeout(timer);
2422
- resolve({
2423
- exitCode: killed ? "timeout" : code ?? -1,
2424
- stdout,
2425
- stderr,
2426
- durationMs: Date.now() - started
2427
- });
2428
- });
2429
- });
2430
- }
2431
- function formatOutcome(outcome, maxChars = 1e5) {
2432
- const cut = (text, limit) => {
2433
- if (text.length <= limit) return { text, truncated: false };
2434
- const head = Math.floor(limit * 0.7);
2435
- return {
2436
- text: `${text.slice(0, head)}
2437
- ...[truncated, ${text.length - head} chars removed]...`,
2438
- truncated: true
2439
- };
2440
- };
2441
- const out = cut(outcome.stdout.trim(), maxChars);
2442
- const err = cut(outcome.stderr.trim(), Math.floor(maxChars / 2));
2443
- const sections = [`exit_code: ${outcome.exitCode}`, `duration_ms: ${outcome.durationMs}`];
2444
- if (out.text) sections.push(`stdout:
2445
- ${out.text}`);
2446
- if (err.text) sections.push(`stderr:
2447
- ${err.text}`);
2448
- if (!out.text && !err.text) sections.push("(no output)");
2449
- return {
2450
- output: sections.join("\n"),
2451
- success: outcome.exitCode === 0,
2452
- truncated: out.truncated || err.truncated
2453
- };
2454
- }
2455
-
2456
2497
  // src/tools/terminal.ts
2498
+ init_exec();
2457
2499
  var DEFAULT_TIMEOUT_MS = 12e4;
2458
2500
  var MAX_OUTPUT_CHARS = 1e5;
2459
2501
  var executeCommand = {
@@ -2489,6 +2531,7 @@ var executeCommand = {
2489
2531
 
2490
2532
  // src/tools/testing.ts
2491
2533
  init_base();
2534
+ init_exec();
2492
2535
  import fs4 from "fs";
2493
2536
  import path4 from "path";
2494
2537
  var DEFAULT_TIMEOUT_MS2 = 18e4;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@menteeai/menteeswe",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
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",