@corbat-tech/coco 1.5.0 → 1.6.0

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/cli/index.js CHANGED
@@ -19,6 +19,7 @@ import { fileURLToPath, URL as URL$1 } from 'url';
19
19
  import JSON5 from 'json5';
20
20
  import Anthropic from '@anthropic-ai/sdk';
21
21
  import OpenAI from 'openai';
22
+ import { jsonrepair } from 'jsonrepair';
22
23
  import * as http from 'http';
23
24
  import { execFile, exec, execSync, execFileSync, spawn } from 'child_process';
24
25
  import { promisify } from 'util';
@@ -981,6 +982,71 @@ var init_allow_path_prompt = __esm({
981
982
  init_allowed_paths();
982
983
  }
983
984
  });
985
+
986
+ // src/tools/utils/heartbeat.ts
987
+ var heartbeat_exports = {};
988
+ __export(heartbeat_exports, {
989
+ CommandHeartbeat: () => CommandHeartbeat
990
+ });
991
+ var CommandHeartbeat;
992
+ var init_heartbeat = __esm({
993
+ "src/tools/utils/heartbeat.ts"() {
994
+ CommandHeartbeat = class {
995
+ startTime = 0;
996
+ lastActivityTime = 0;
997
+ updateInterval = null;
998
+ warnThreshold = 30;
999
+ // seconds
1000
+ updateIntervalSeconds = 10;
1001
+ // seconds
1002
+ callbacks;
1003
+ constructor(callbacks = {}) {
1004
+ this.callbacks = callbacks;
1005
+ }
1006
+ /**
1007
+ * Start monitoring - begins periodic updates and silence warnings
1008
+ */
1009
+ start() {
1010
+ this.startTime = Date.now();
1011
+ this.lastActivityTime = Date.now();
1012
+ this.updateInterval = setInterval(() => {
1013
+ const stats = this.getStats();
1014
+ this.callbacks.onUpdate?.(stats);
1015
+ if (stats.silentSeconds >= this.warnThreshold) {
1016
+ this.callbacks.onWarn?.(`\u26A0\uFE0F Command silent for ${stats.silentSeconds}s`);
1017
+ }
1018
+ }, this.updateIntervalSeconds * 1e3);
1019
+ }
1020
+ /**
1021
+ * Register activity - call this when command produces output
1022
+ * Resets the silence timer
1023
+ */
1024
+ activity() {
1025
+ this.lastActivityTime = Date.now();
1026
+ }
1027
+ /**
1028
+ * Stop monitoring - clears periodic interval
1029
+ * Should be called in finally{} block to ensure cleanup
1030
+ */
1031
+ stop() {
1032
+ if (this.updateInterval) {
1033
+ clearInterval(this.updateInterval);
1034
+ this.updateInterval = null;
1035
+ }
1036
+ }
1037
+ /**
1038
+ * Get current heartbeat statistics
1039
+ */
1040
+ getStats() {
1041
+ const now = Date.now();
1042
+ return {
1043
+ elapsedSeconds: Math.floor((now - this.startTime) / 1e3),
1044
+ silentSeconds: Math.floor((now - this.lastActivityTime) / 1e3)
1045
+ };
1046
+ }
1047
+ };
1048
+ }
1049
+ });
984
1050
  function isEnvVarSafe(name) {
985
1051
  if (SAFE_ENV_VARS.has(name)) {
986
1052
  return true;
@@ -1117,23 +1183,50 @@ Examples:
1117
1183
  }
1118
1184
  const startTime = performance.now();
1119
1185
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS;
1186
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
1187
+ const heartbeat = new CommandHeartbeat2({
1188
+ onUpdate: (stats) => {
1189
+ if (stats.elapsedSeconds > 10) {
1190
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
1191
+ }
1192
+ },
1193
+ onWarn: (message) => {
1194
+ process.stderr.write(`
1195
+ ${message}
1196
+ `);
1197
+ }
1198
+ });
1120
1199
  try {
1200
+ heartbeat.start();
1121
1201
  const options = {
1122
1202
  cwd: cwd ?? process.cwd(),
1123
1203
  timeout: timeoutMs,
1124
1204
  env: { ...process.env, ...env2 },
1125
1205
  shell: true,
1126
1206
  reject: false,
1207
+ buffer: false,
1208
+ // Enable streaming
1127
1209
  maxBuffer: MAX_OUTPUT_SIZE
1128
1210
  };
1129
- const result = await execa(command, options);
1211
+ const subprocess = execa(command, options);
1212
+ let stdoutBuffer = "";
1213
+ let stderrBuffer = "";
1214
+ subprocess.stdout?.on("data", (chunk) => {
1215
+ const text11 = chunk.toString();
1216
+ stdoutBuffer += text11;
1217
+ process.stdout.write(text11);
1218
+ heartbeat.activity();
1219
+ });
1220
+ subprocess.stderr?.on("data", (chunk) => {
1221
+ const text11 = chunk.toString();
1222
+ stderrBuffer += text11;
1223
+ process.stderr.write(text11);
1224
+ heartbeat.activity();
1225
+ });
1226
+ const result = await subprocess;
1130
1227
  return {
1131
- stdout: truncateOutput(
1132
- typeof result.stdout === "string" ? result.stdout : String(result.stdout ?? "")
1133
- ),
1134
- stderr: truncateOutput(
1135
- typeof result.stderr === "string" ? result.stderr : String(result.stderr ?? "")
1136
- ),
1228
+ stdout: truncateOutput(stdoutBuffer),
1229
+ stderr: truncateOutput(stderrBuffer),
1137
1230
  exitCode: result.exitCode ?? 0,
1138
1231
  duration: performance.now() - startTime
1139
1232
  };
@@ -1148,6 +1241,9 @@ Examples:
1148
1241
  `Command execution failed: ${error instanceof Error ? error.message : String(error)}`,
1149
1242
  { tool: "bash_exec", cause: error instanceof Error ? error : void 0 }
1150
1243
  );
1244
+ } finally {
1245
+ heartbeat.stop();
1246
+ process.stderr.write("\r \r");
1151
1247
  }
1152
1248
  }
1153
1249
  });
@@ -6191,8 +6287,10 @@ var OpenAIProvider = class {
6191
6287
  const timeoutInterval = setInterval(checkTimeout, 5e3);
6192
6288
  try {
6193
6289
  for await (const chunk of stream) {
6194
- lastActivityTime = Date.now();
6195
6290
  const delta = chunk.choices[0]?.delta;
6291
+ if (delta?.content || delta?.tool_calls) {
6292
+ lastActivityTime = Date.now();
6293
+ }
6196
6294
  if (delta?.content) {
6197
6295
  yield { type: "text", text: delta.content };
6198
6296
  }
@@ -6238,10 +6336,20 @@ var OpenAIProvider = class {
6238
6336
  let input = {};
6239
6337
  try {
6240
6338
  input = builder.arguments ? JSON.parse(builder.arguments) : {};
6241
- } catch {
6339
+ } catch (error) {
6242
6340
  console.warn(
6243
- `[OpenAI] Failed to parse tool call arguments: ${builder.arguments?.slice(0, 100)}`
6341
+ `[OpenAI] Failed to parse tool call arguments for ${builder.name}: ${builder.arguments?.slice(0, 100)}`
6244
6342
  );
6343
+ try {
6344
+ if (builder.arguments) {
6345
+ const repaired = jsonrepair(builder.arguments);
6346
+ input = JSON.parse(repaired);
6347
+ console.log(`[OpenAI] \u2713 Successfully repaired JSON for ${builder.name}`);
6348
+ }
6349
+ } catch (repairError) {
6350
+ console.error(`[OpenAI] Cannot repair JSON for ${builder.name}, using empty object`);
6351
+ console.error(`[OpenAI] Original error:`, error);
6352
+ }
6245
6353
  }
6246
6354
  yield {
6247
6355
  type: "tool_use_end",
@@ -10601,14 +10709,42 @@ function generateToolCatalog(registry) {
10601
10709
  }
10602
10710
  var COCO_SYSTEM_PROMPT = `You are Corbat-Coco, an autonomous coding assistant with an extensive toolkit.
10603
10711
 
10604
- ## Your Approach: Tool-Aware Problem Solving
10712
+ ## YOUR PRIMARY DIRECTIVE: EXECUTE, DON'T TALK ABOUT EXECUTING
10713
+
10714
+ \u{1F6A8} **CRITICAL - READ THIS FIRST** \u{1F6A8}
10715
+ YOU ARE AN EXECUTION AGENT, NOT A CONVERSATIONAL ASSISTANT.
10716
+
10717
+ **WRONG BEHAVIOR (Never do this):**
10718
+ \u274C "I'll create a file called hello.js with a function..."
10719
+ \u274C "I created hello.js with the following code..."
10720
+ \u274C "Here's what the file would look like..."
10721
+ \u274C Showing code blocks without calling write_file tool
10722
+
10723
+ **CORRECT BEHAVIOR (Always do this):**
10724
+ \u2705 Immediately call write_file tool with the code
10725
+ \u2705 Then say "Created hello.js with greeting function"
10726
+ \u2705 TOOLS FIRST, then brief confirmation
10727
+
10728
+ **Core Principle: USE TOOLS, DON'T DESCRIBE**
10729
+ \u26A0\uFE0F CRITICAL: You MUST use your tools to perform actions. NEVER just describe what you would do or claim you did something without actually calling a tool.
10605
10730
 
10606
- When the user asks you to do something, follow this process:
10607
- 1. **Analyze the request**: Understand what the user needs
10608
- 2. **Scan your tools**: Review which of your available tools can help accomplish the task
10609
- 3. **Plan your approach**: Decide which tools to use and in what order
10610
- 4. **Execute**: Use the appropriate tools, combining multiple when needed
10611
- 5. **Verify**: Check your work (read files after editing, run tests after changes)
10731
+ **Tool Calling is MANDATORY:**
10732
+ - User says "create a file" \u2192 CALL write_file tool FIRST (don't show code, don't explain, just CALL THE TOOL)
10733
+ - User says "search the web" \u2192 CALL web_search tool FIRST (don't describe what you would search for)
10734
+ - User says "run tests" \u2192 CALL bash_exec tool FIRST (don't say you ran them, actually run them)
10735
+ - EVERY action requires a TOOL CALL. Text responses are ONLY for brief confirmations AFTER tools execute.
10736
+
10737
+ **Execution Process:**
10738
+ 1. **Analyze**: Understand what the user wants (in your head, don't output this)
10739
+ 2. **Execute**: IMMEDIATELY CALL THE APPROPRIATE TOOLS (this is mandatory, not optional)
10740
+ 3. **Respond**: Brief confirmation of what was done (AFTER tools executed)
10741
+
10742
+ **Critical Rules:**
10743
+ - User says "create X with Y" \u2192 Immediately call write_file/edit_file tool, no discussion
10744
+ - If a task needs data you don't have, fetch it with web_search/web_fetch FIRST, THEN complete the task with other tools
10745
+ - Never ask "should I do this?" or "do you want me to...?" - JUST DO IT (with tools)
10746
+ - If you don't call tools, you didn't do the task - showing code is NOT the same as creating files
10747
+ - NEVER show code blocks as examples - ALWAYS write them to files with tools
10612
10748
 
10613
10749
  **IMPORTANT**: You have many tools beyond basic file/bash/git. Before answering "I can't do that", check if any of your tools can help. For example:
10614
10750
  - Need information from the internet? Use **web_search** and **web_fetch**
@@ -10626,13 +10762,19 @@ When the user asks you to do something, follow this process:
10626
10762
  {TOOL_CATALOG}
10627
10763
 
10628
10764
  ## Guidelines
10629
- - Be helpful and direct
10630
- - If a task requires multiple steps, execute them one by one
10631
- - Always verify your work by reading files after editing or running tests after changes
10632
- - You can use multiple tools together for complex tasks
10633
- - When uncertain which tool to use, check the full list above
10765
+ - **Be action-oriented**: Execute tasks immediately without asking for confirmation
10766
+ - **Multi-step tasks**: Chain tools together to complete the full request
10767
+ - **Always verify**: Read files after editing, run tests after changes
10768
+ - **Don't present options**: If the user says "create X", create it with reasonable defaults
10769
+ - **Don't ask "should I..."**: The user already told you what to do by making the request
10770
+ - **Combine tools**: Use web_search + write_file, bash + read_file, etc. to complete tasks fully
10634
10771
  - **Never** add "Co-Authored-By", "Generated by", or any AI attribution to commits, code comments, documentation, or PR descriptions. All output must read as if written by the developer.
10635
10772
 
10773
+ **Example Flows:**
10774
+ - "Create an HTML with weather data" \u2192 web_search for weather \u2192 write_file with HTML \u2192 DONE
10775
+ - "Add tests for function X" \u2192 read_file to see X \u2192 write_file with tests \u2192 bash to run tests \u2192 DONE
10776
+ - "Fix the bug in Y" \u2192 read_file to understand \u2192 edit_file to fix \u2192 bash to test \u2192 DONE
10777
+
10636
10778
  ## File Access
10637
10779
  File operations are restricted to the project directory by default.
10638
10780
  When you need to access a path outside the project, use the **authorize_path** tool first \u2014 it will ask the user for permission interactively. Once authorized, proceed with the file operation.
@@ -24325,7 +24467,21 @@ Examples:
24325
24467
  const projectDir = cwd ?? process.cwd();
24326
24468
  const startTime = performance.now();
24327
24469
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
24470
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
24471
+ const heartbeat = new CommandHeartbeat2({
24472
+ onUpdate: (stats) => {
24473
+ if (stats.elapsedSeconds > 10) {
24474
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
24475
+ }
24476
+ },
24477
+ onWarn: (message) => {
24478
+ process.stderr.write(`
24479
+ ${message}
24480
+ `);
24481
+ }
24482
+ });
24328
24483
  try {
24484
+ heartbeat.start();
24329
24485
  const pm = packageManager ?? await detectPackageManager(projectDir);
24330
24486
  const cmdArgs = ["run", script];
24331
24487
  if (args && args.length > 0) {
@@ -24336,13 +24492,30 @@ Examples:
24336
24492
  timeout: timeoutMs,
24337
24493
  env: { ...process.env, ...env2 },
24338
24494
  reject: false,
24495
+ buffer: false,
24496
+ // Enable streaming
24339
24497
  maxBuffer: MAX_OUTPUT_SIZE2
24340
24498
  };
24341
- const result = await execa(pm, cmdArgs, options);
24499
+ const subprocess = execa(pm, cmdArgs, options);
24500
+ let stdoutBuffer = "";
24501
+ let stderrBuffer = "";
24502
+ subprocess.stdout?.on("data", (chunk) => {
24503
+ const text11 = chunk.toString();
24504
+ stdoutBuffer += text11;
24505
+ process.stdout.write(text11);
24506
+ heartbeat.activity();
24507
+ });
24508
+ subprocess.stderr?.on("data", (chunk) => {
24509
+ const text11 = chunk.toString();
24510
+ stderrBuffer += text11;
24511
+ process.stderr.write(text11);
24512
+ heartbeat.activity();
24513
+ });
24514
+ const result = await subprocess;
24342
24515
  return {
24343
24516
  success: result.exitCode === 0,
24344
- stdout: truncateOutput2(String(result.stdout ?? "")),
24345
- stderr: truncateOutput2(String(result.stderr ?? "")),
24517
+ stdout: truncateOutput2(stdoutBuffer),
24518
+ stderr: truncateOutput2(stderrBuffer),
24346
24519
  exitCode: result.exitCode ?? 0,
24347
24520
  duration: performance.now() - startTime,
24348
24521
  packageManager: pm
@@ -24358,6 +24531,9 @@ Examples:
24358
24531
  `Failed to run script '${script}': ${error instanceof Error ? error.message : String(error)}`,
24359
24532
  { tool: "run_script", cause: error instanceof Error ? error : void 0 }
24360
24533
  );
24534
+ } finally {
24535
+ heartbeat.stop();
24536
+ process.stderr.write("\r \r");
24361
24537
  }
24362
24538
  }
24363
24539
  });
@@ -24383,7 +24559,21 @@ Examples:
24383
24559
  const projectDir = cwd ?? process.cwd();
24384
24560
  const startTime = performance.now();
24385
24561
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
24562
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
24563
+ const heartbeat = new CommandHeartbeat2({
24564
+ onUpdate: (stats) => {
24565
+ if (stats.elapsedSeconds > 10) {
24566
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
24567
+ }
24568
+ },
24569
+ onWarn: (message) => {
24570
+ process.stderr.write(`
24571
+ ${message}
24572
+ `);
24573
+ }
24574
+ });
24386
24575
  try {
24576
+ heartbeat.start();
24387
24577
  const pm = packageManager ?? await detectPackageManager(projectDir);
24388
24578
  let cmdArgs;
24389
24579
  if (packages && packages.length > 0) {
@@ -24423,13 +24613,30 @@ Examples:
24423
24613
  cwd: projectDir,
24424
24614
  timeout: timeoutMs,
24425
24615
  reject: false,
24616
+ buffer: false,
24617
+ // Enable streaming
24426
24618
  maxBuffer: MAX_OUTPUT_SIZE2
24427
24619
  };
24428
- const result = await execa(pm, cmdArgs, options);
24620
+ const subprocess = execa(pm, cmdArgs, options);
24621
+ let stdoutBuffer = "";
24622
+ let stderrBuffer = "";
24623
+ subprocess.stdout?.on("data", (chunk) => {
24624
+ const text11 = chunk.toString();
24625
+ stdoutBuffer += text11;
24626
+ process.stdout.write(text11);
24627
+ heartbeat.activity();
24628
+ });
24629
+ subprocess.stderr?.on("data", (chunk) => {
24630
+ const text11 = chunk.toString();
24631
+ stderrBuffer += text11;
24632
+ process.stderr.write(text11);
24633
+ heartbeat.activity();
24634
+ });
24635
+ const result = await subprocess;
24429
24636
  return {
24430
24637
  success: result.exitCode === 0,
24431
- stdout: truncateOutput2(String(result.stdout ?? "")),
24432
- stderr: truncateOutput2(String(result.stderr ?? "")),
24638
+ stdout: truncateOutput2(stdoutBuffer),
24639
+ stderr: truncateOutput2(stderrBuffer),
24433
24640
  exitCode: result.exitCode ?? 0,
24434
24641
  duration: performance.now() - startTime,
24435
24642
  packageManager: pm
@@ -24445,6 +24652,9 @@ Examples:
24445
24652
  `Failed to install dependencies: ${error instanceof Error ? error.message : String(error)}`,
24446
24653
  { tool: "install_deps", cause: error instanceof Error ? error : void 0 }
24447
24654
  );
24655
+ } finally {
24656
+ heartbeat.stop();
24657
+ process.stderr.write("\r \r");
24448
24658
  }
24449
24659
  }
24450
24660
  });
@@ -24469,12 +24679,26 @@ Examples:
24469
24679
  const projectDir = cwd ?? process.cwd();
24470
24680
  const startTime = performance.now();
24471
24681
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
24682
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
24683
+ const heartbeat = new CommandHeartbeat2({
24684
+ onUpdate: (stats) => {
24685
+ if (stats.elapsedSeconds > 10) {
24686
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
24687
+ }
24688
+ },
24689
+ onWarn: (message) => {
24690
+ process.stderr.write(`
24691
+ ${message}
24692
+ `);
24693
+ }
24694
+ });
24472
24695
  try {
24473
24696
  try {
24474
24697
  await fs23__default.access(path20__default.join(projectDir, "Makefile"));
24475
24698
  } catch {
24476
24699
  throw new ToolError("No Makefile found in directory", { tool: "make" });
24477
24700
  }
24701
+ heartbeat.start();
24478
24702
  const cmdArgs = [];
24479
24703
  if (target) {
24480
24704
  cmdArgs.push(...target.split(/\s+/));
@@ -24487,13 +24711,30 @@ Examples:
24487
24711
  timeout: timeoutMs,
24488
24712
  env: { ...process.env, ...env2 },
24489
24713
  reject: false,
24714
+ buffer: false,
24715
+ // Enable streaming
24490
24716
  maxBuffer: MAX_OUTPUT_SIZE2
24491
24717
  };
24492
- const result = await execa("make", cmdArgs, options);
24718
+ const subprocess = execa("make", cmdArgs, options);
24719
+ let stdoutBuffer = "";
24720
+ let stderrBuffer = "";
24721
+ subprocess.stdout?.on("data", (chunk) => {
24722
+ const text11 = chunk.toString();
24723
+ stdoutBuffer += text11;
24724
+ process.stdout.write(text11);
24725
+ heartbeat.activity();
24726
+ });
24727
+ subprocess.stderr?.on("data", (chunk) => {
24728
+ const text11 = chunk.toString();
24729
+ stderrBuffer += text11;
24730
+ process.stderr.write(text11);
24731
+ heartbeat.activity();
24732
+ });
24733
+ const result = await subprocess;
24493
24734
  return {
24494
24735
  success: result.exitCode === 0,
24495
- stdout: truncateOutput2(String(result.stdout ?? "")),
24496
- stderr: truncateOutput2(String(result.stderr ?? "")),
24736
+ stdout: truncateOutput2(stdoutBuffer),
24737
+ stderr: truncateOutput2(stderrBuffer),
24497
24738
  exitCode: result.exitCode ?? 0,
24498
24739
  duration: performance.now() - startTime
24499
24740
  };
@@ -24509,6 +24750,9 @@ Examples:
24509
24750
  `Make failed: ${error instanceof Error ? error.message : String(error)}`,
24510
24751
  { tool: "make", cause: error instanceof Error ? error : void 0 }
24511
24752
  );
24753
+ } finally {
24754
+ heartbeat.stop();
24755
+ process.stderr.write("\r \r");
24512
24756
  }
24513
24757
  }
24514
24758
  });
@@ -24534,7 +24778,21 @@ Examples:
24534
24778
  const projectDir = cwd ?? process.cwd();
24535
24779
  const startTime = performance.now();
24536
24780
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
24781
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
24782
+ const heartbeat = new CommandHeartbeat2({
24783
+ onUpdate: (stats) => {
24784
+ if (stats.elapsedSeconds > 10) {
24785
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
24786
+ }
24787
+ },
24788
+ onWarn: (message) => {
24789
+ process.stderr.write(`
24790
+ ${message}
24791
+ `);
24792
+ }
24793
+ });
24537
24794
  try {
24795
+ heartbeat.start();
24538
24796
  const cmdArgs = [];
24539
24797
  if (project) {
24540
24798
  cmdArgs.push("--project", project);
@@ -24552,13 +24810,30 @@ Examples:
24552
24810
  cwd: projectDir,
24553
24811
  timeout: timeoutMs,
24554
24812
  reject: false,
24813
+ buffer: false,
24814
+ // Enable streaming
24555
24815
  maxBuffer: MAX_OUTPUT_SIZE2
24556
24816
  };
24557
- const result = await execa("npx", ["tsc", ...cmdArgs], options);
24817
+ const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
24818
+ let stdoutBuffer = "";
24819
+ let stderrBuffer = "";
24820
+ subprocess.stdout?.on("data", (chunk) => {
24821
+ const text11 = chunk.toString();
24822
+ stdoutBuffer += text11;
24823
+ process.stdout.write(text11);
24824
+ heartbeat.activity();
24825
+ });
24826
+ subprocess.stderr?.on("data", (chunk) => {
24827
+ const text11 = chunk.toString();
24828
+ stderrBuffer += text11;
24829
+ process.stderr.write(text11);
24830
+ heartbeat.activity();
24831
+ });
24832
+ const result = await subprocess;
24558
24833
  return {
24559
24834
  success: result.exitCode === 0,
24560
- stdout: truncateOutput2(String(result.stdout ?? "")),
24561
- stderr: truncateOutput2(String(result.stderr ?? "")),
24835
+ stdout: truncateOutput2(stdoutBuffer),
24836
+ stderr: truncateOutput2(stderrBuffer),
24562
24837
  exitCode: result.exitCode ?? 0,
24563
24838
  duration: performance.now() - startTime
24564
24839
  };
@@ -24573,6 +24848,9 @@ Examples:
24573
24848
  `TypeScript compile failed: ${error instanceof Error ? error.message : String(error)}`,
24574
24849
  { tool: "tsc", cause: error instanceof Error ? error : void 0 }
24575
24850
  );
24851
+ } finally {
24852
+ heartbeat.stop();
24853
+ process.stderr.write("\r \r");
24576
24854
  }
24577
24855
  }
24578
24856
  });
@@ -30442,7 +30720,11 @@ async function startRepl(options = {}) {
30442
30720
  clearSpinner();
30443
30721
  renderToolStart(result2.name, result2.input);
30444
30722
  renderToolEnd(result2);
30445
- setSpinner("Processing...");
30723
+ if (isCocoMode()) {
30724
+ setSpinner("Processing results & checking quality...");
30725
+ } else {
30726
+ setSpinner("Processing...");
30727
+ }
30446
30728
  },
30447
30729
  onToolSkipped: (tc, reason) => {
30448
30730
  clearSpinner();
@@ -30455,10 +30737,18 @@ async function startRepl(options = {}) {
30455
30737
  if (!thinkingStartTime) return;
30456
30738
  const elapsed = Math.floor((Date.now() - thinkingStartTime) / 1e3);
30457
30739
  if (elapsed < 4) return;
30458
- if (elapsed < 8) setSpinner("Analyzing request...");
30459
- else if (elapsed < 12) setSpinner("Planning approach...");
30460
- else if (elapsed < 16) setSpinner("Preparing tools...");
30461
- else setSpinner(`Still working... (${elapsed}s)`);
30740
+ if (isCocoMode()) {
30741
+ if (elapsed < 8) setSpinner("Analyzing request...");
30742
+ else if (elapsed < 15) setSpinner("Running quality checks...");
30743
+ else if (elapsed < 25) setSpinner("Iterating for quality...");
30744
+ else if (elapsed < 40) setSpinner("Verifying implementation...");
30745
+ else setSpinner(`Quality iteration in progress... (${elapsed}s)`);
30746
+ } else {
30747
+ if (elapsed < 8) setSpinner("Analyzing request...");
30748
+ else if (elapsed < 12) setSpinner("Planning approach...");
30749
+ else if (elapsed < 16) setSpinner("Preparing tools...");
30750
+ else setSpinner(`Still working... (${elapsed}s)`);
30751
+ }
30462
30752
  }, 2e3);
30463
30753
  },
30464
30754
  onThinkingEnd: () => {