@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/index.js CHANGED
@@ -18,6 +18,7 @@ import { z } from 'zod';
18
18
  import { Logger } from 'tslog';
19
19
  import Anthropic from '@anthropic-ai/sdk';
20
20
  import OpenAI from 'openai';
21
+ import { jsonrepair } from 'jsonrepair';
21
22
  import 'http';
22
23
  import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';
23
24
  import JSON5 from 'json5';
@@ -255,6 +256,71 @@ var init_allowed_paths = __esm({
255
256
  }
256
257
  });
257
258
 
259
+ // src/tools/utils/heartbeat.ts
260
+ var heartbeat_exports = {};
261
+ __export(heartbeat_exports, {
262
+ CommandHeartbeat: () => CommandHeartbeat
263
+ });
264
+ var CommandHeartbeat;
265
+ var init_heartbeat = __esm({
266
+ "src/tools/utils/heartbeat.ts"() {
267
+ CommandHeartbeat = class {
268
+ startTime = 0;
269
+ lastActivityTime = 0;
270
+ updateInterval = null;
271
+ warnThreshold = 30;
272
+ // seconds
273
+ updateIntervalSeconds = 10;
274
+ // seconds
275
+ callbacks;
276
+ constructor(callbacks = {}) {
277
+ this.callbacks = callbacks;
278
+ }
279
+ /**
280
+ * Start monitoring - begins periodic updates and silence warnings
281
+ */
282
+ start() {
283
+ this.startTime = Date.now();
284
+ this.lastActivityTime = Date.now();
285
+ this.updateInterval = setInterval(() => {
286
+ const stats = this.getStats();
287
+ this.callbacks.onUpdate?.(stats);
288
+ if (stats.silentSeconds >= this.warnThreshold) {
289
+ this.callbacks.onWarn?.(`\u26A0\uFE0F Command silent for ${stats.silentSeconds}s`);
290
+ }
291
+ }, this.updateIntervalSeconds * 1e3);
292
+ }
293
+ /**
294
+ * Register activity - call this when command produces output
295
+ * Resets the silence timer
296
+ */
297
+ activity() {
298
+ this.lastActivityTime = Date.now();
299
+ }
300
+ /**
301
+ * Stop monitoring - clears periodic interval
302
+ * Should be called in finally{} block to ensure cleanup
303
+ */
304
+ stop() {
305
+ if (this.updateInterval) {
306
+ clearInterval(this.updateInterval);
307
+ this.updateInterval = null;
308
+ }
309
+ }
310
+ /**
311
+ * Get current heartbeat statistics
312
+ */
313
+ getStats() {
314
+ const now = Date.now();
315
+ return {
316
+ elapsedSeconds: Math.floor((now - this.startTime) / 1e3),
317
+ silentSeconds: Math.floor((now - this.lastActivityTime) / 1e3)
318
+ };
319
+ }
320
+ };
321
+ }
322
+ });
323
+
258
324
  // src/cli/repl/allow-path-prompt.ts
259
325
  var allow_path_prompt_exports = {};
260
326
  __export(allow_path_prompt_exports, {
@@ -10616,8 +10682,10 @@ var OpenAIProvider = class {
10616
10682
  const timeoutInterval = setInterval(checkTimeout, 5e3);
10617
10683
  try {
10618
10684
  for await (const chunk of stream) {
10619
- lastActivityTime = Date.now();
10620
10685
  const delta = chunk.choices[0]?.delta;
10686
+ if (delta?.content || delta?.tool_calls) {
10687
+ lastActivityTime = Date.now();
10688
+ }
10621
10689
  if (delta?.content) {
10622
10690
  yield { type: "text", text: delta.content };
10623
10691
  }
@@ -10663,10 +10731,20 @@ var OpenAIProvider = class {
10663
10731
  let input = {};
10664
10732
  try {
10665
10733
  input = builder.arguments ? JSON.parse(builder.arguments) : {};
10666
- } catch {
10734
+ } catch (error) {
10667
10735
  console.warn(
10668
- `[OpenAI] Failed to parse tool call arguments: ${builder.arguments?.slice(0, 100)}`
10736
+ `[OpenAI] Failed to parse tool call arguments for ${builder.name}: ${builder.arguments?.slice(0, 100)}`
10669
10737
  );
10738
+ try {
10739
+ if (builder.arguments) {
10740
+ const repaired = jsonrepair(builder.arguments);
10741
+ input = JSON.parse(repaired);
10742
+ console.log(`[OpenAI] \u2713 Successfully repaired JSON for ${builder.name}`);
10743
+ }
10744
+ } catch (repairError) {
10745
+ console.error(`[OpenAI] Cannot repair JSON for ${builder.name}, using empty object`);
10746
+ console.error(`[OpenAI] Original error:`, error);
10747
+ }
10670
10748
  }
10671
10749
  yield {
10672
10750
  type: "tool_use_end",
@@ -13394,23 +13472,50 @@ Examples:
13394
13472
  }
13395
13473
  const startTime = performance.now();
13396
13474
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS;
13475
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
13476
+ const heartbeat = new CommandHeartbeat2({
13477
+ onUpdate: (stats) => {
13478
+ if (stats.elapsedSeconds > 10) {
13479
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
13480
+ }
13481
+ },
13482
+ onWarn: (message) => {
13483
+ process.stderr.write(`
13484
+ ${message}
13485
+ `);
13486
+ }
13487
+ });
13397
13488
  try {
13489
+ heartbeat.start();
13398
13490
  const options = {
13399
13491
  cwd: cwd ?? process.cwd(),
13400
13492
  timeout: timeoutMs,
13401
13493
  env: { ...process.env, ...env2 },
13402
13494
  shell: true,
13403
13495
  reject: false,
13496
+ buffer: false,
13497
+ // Enable streaming
13404
13498
  maxBuffer: MAX_OUTPUT_SIZE
13405
13499
  };
13406
- const result = await execa(command, options);
13500
+ const subprocess = execa(command, options);
13501
+ let stdoutBuffer = "";
13502
+ let stderrBuffer = "";
13503
+ subprocess.stdout?.on("data", (chunk) => {
13504
+ const text = chunk.toString();
13505
+ stdoutBuffer += text;
13506
+ process.stdout.write(text);
13507
+ heartbeat.activity();
13508
+ });
13509
+ subprocess.stderr?.on("data", (chunk) => {
13510
+ const text = chunk.toString();
13511
+ stderrBuffer += text;
13512
+ process.stderr.write(text);
13513
+ heartbeat.activity();
13514
+ });
13515
+ const result = await subprocess;
13407
13516
  return {
13408
- stdout: truncateOutput(
13409
- typeof result.stdout === "string" ? result.stdout : String(result.stdout ?? "")
13410
- ),
13411
- stderr: truncateOutput(
13412
- typeof result.stderr === "string" ? result.stderr : String(result.stderr ?? "")
13413
- ),
13517
+ stdout: truncateOutput(stdoutBuffer),
13518
+ stderr: truncateOutput(stderrBuffer),
13414
13519
  exitCode: result.exitCode ?? 0,
13415
13520
  duration: performance.now() - startTime
13416
13521
  };
@@ -13425,6 +13530,9 @@ Examples:
13425
13530
  `Command execution failed: ${error instanceof Error ? error.message : String(error)}`,
13426
13531
  { tool: "bash_exec", cause: error instanceof Error ? error : void 0 }
13427
13532
  );
13533
+ } finally {
13534
+ heartbeat.stop();
13535
+ process.stderr.write("\r \r");
13428
13536
  }
13429
13537
  }
13430
13538
  });
@@ -15051,7 +15159,21 @@ Examples:
15051
15159
  const projectDir = cwd ?? process.cwd();
15052
15160
  const startTime = performance.now();
15053
15161
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
15162
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
15163
+ const heartbeat = new CommandHeartbeat2({
15164
+ onUpdate: (stats) => {
15165
+ if (stats.elapsedSeconds > 10) {
15166
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
15167
+ }
15168
+ },
15169
+ onWarn: (message) => {
15170
+ process.stderr.write(`
15171
+ ${message}
15172
+ `);
15173
+ }
15174
+ });
15054
15175
  try {
15176
+ heartbeat.start();
15055
15177
  const pm = packageManager ?? await detectPackageManager(projectDir);
15056
15178
  const cmdArgs = ["run", script];
15057
15179
  if (args && args.length > 0) {
@@ -15062,13 +15184,30 @@ Examples:
15062
15184
  timeout: timeoutMs,
15063
15185
  env: { ...process.env, ...env2 },
15064
15186
  reject: false,
15187
+ buffer: false,
15188
+ // Enable streaming
15065
15189
  maxBuffer: MAX_OUTPUT_SIZE2
15066
15190
  };
15067
- const result = await execa(pm, cmdArgs, options);
15191
+ const subprocess = execa(pm, cmdArgs, options);
15192
+ let stdoutBuffer = "";
15193
+ let stderrBuffer = "";
15194
+ subprocess.stdout?.on("data", (chunk) => {
15195
+ const text = chunk.toString();
15196
+ stdoutBuffer += text;
15197
+ process.stdout.write(text);
15198
+ heartbeat.activity();
15199
+ });
15200
+ subprocess.stderr?.on("data", (chunk) => {
15201
+ const text = chunk.toString();
15202
+ stderrBuffer += text;
15203
+ process.stderr.write(text);
15204
+ heartbeat.activity();
15205
+ });
15206
+ const result = await subprocess;
15068
15207
  return {
15069
15208
  success: result.exitCode === 0,
15070
- stdout: truncateOutput2(String(result.stdout ?? "")),
15071
- stderr: truncateOutput2(String(result.stderr ?? "")),
15209
+ stdout: truncateOutput2(stdoutBuffer),
15210
+ stderr: truncateOutput2(stderrBuffer),
15072
15211
  exitCode: result.exitCode ?? 0,
15073
15212
  duration: performance.now() - startTime,
15074
15213
  packageManager: pm
@@ -15084,6 +15223,9 @@ Examples:
15084
15223
  `Failed to run script '${script}': ${error instanceof Error ? error.message : String(error)}`,
15085
15224
  { tool: "run_script", cause: error instanceof Error ? error : void 0 }
15086
15225
  );
15226
+ } finally {
15227
+ heartbeat.stop();
15228
+ process.stderr.write("\r \r");
15087
15229
  }
15088
15230
  }
15089
15231
  });
@@ -15109,7 +15251,21 @@ Examples:
15109
15251
  const projectDir = cwd ?? process.cwd();
15110
15252
  const startTime = performance.now();
15111
15253
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
15254
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
15255
+ const heartbeat = new CommandHeartbeat2({
15256
+ onUpdate: (stats) => {
15257
+ if (stats.elapsedSeconds > 10) {
15258
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
15259
+ }
15260
+ },
15261
+ onWarn: (message) => {
15262
+ process.stderr.write(`
15263
+ ${message}
15264
+ `);
15265
+ }
15266
+ });
15112
15267
  try {
15268
+ heartbeat.start();
15113
15269
  const pm = packageManager ?? await detectPackageManager(projectDir);
15114
15270
  let cmdArgs;
15115
15271
  if (packages && packages.length > 0) {
@@ -15149,13 +15305,30 @@ Examples:
15149
15305
  cwd: projectDir,
15150
15306
  timeout: timeoutMs,
15151
15307
  reject: false,
15308
+ buffer: false,
15309
+ // Enable streaming
15152
15310
  maxBuffer: MAX_OUTPUT_SIZE2
15153
15311
  };
15154
- const result = await execa(pm, cmdArgs, options);
15312
+ const subprocess = execa(pm, cmdArgs, options);
15313
+ let stdoutBuffer = "";
15314
+ let stderrBuffer = "";
15315
+ subprocess.stdout?.on("data", (chunk) => {
15316
+ const text = chunk.toString();
15317
+ stdoutBuffer += text;
15318
+ process.stdout.write(text);
15319
+ heartbeat.activity();
15320
+ });
15321
+ subprocess.stderr?.on("data", (chunk) => {
15322
+ const text = chunk.toString();
15323
+ stderrBuffer += text;
15324
+ process.stderr.write(text);
15325
+ heartbeat.activity();
15326
+ });
15327
+ const result = await subprocess;
15155
15328
  return {
15156
15329
  success: result.exitCode === 0,
15157
- stdout: truncateOutput2(String(result.stdout ?? "")),
15158
- stderr: truncateOutput2(String(result.stderr ?? "")),
15330
+ stdout: truncateOutput2(stdoutBuffer),
15331
+ stderr: truncateOutput2(stderrBuffer),
15159
15332
  exitCode: result.exitCode ?? 0,
15160
15333
  duration: performance.now() - startTime,
15161
15334
  packageManager: pm
@@ -15171,6 +15344,9 @@ Examples:
15171
15344
  `Failed to install dependencies: ${error instanceof Error ? error.message : String(error)}`,
15172
15345
  { tool: "install_deps", cause: error instanceof Error ? error : void 0 }
15173
15346
  );
15347
+ } finally {
15348
+ heartbeat.stop();
15349
+ process.stderr.write("\r \r");
15174
15350
  }
15175
15351
  }
15176
15352
  });
@@ -15195,12 +15371,26 @@ Examples:
15195
15371
  const projectDir = cwd ?? process.cwd();
15196
15372
  const startTime = performance.now();
15197
15373
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
15374
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
15375
+ const heartbeat = new CommandHeartbeat2({
15376
+ onUpdate: (stats) => {
15377
+ if (stats.elapsedSeconds > 10) {
15378
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
15379
+ }
15380
+ },
15381
+ onWarn: (message) => {
15382
+ process.stderr.write(`
15383
+ ${message}
15384
+ `);
15385
+ }
15386
+ });
15198
15387
  try {
15199
15388
  try {
15200
15389
  await fs14__default.access(path14__default.join(projectDir, "Makefile"));
15201
15390
  } catch {
15202
15391
  throw new ToolError("No Makefile found in directory", { tool: "make" });
15203
15392
  }
15393
+ heartbeat.start();
15204
15394
  const cmdArgs = [];
15205
15395
  if (target) {
15206
15396
  cmdArgs.push(...target.split(/\s+/));
@@ -15213,13 +15403,30 @@ Examples:
15213
15403
  timeout: timeoutMs,
15214
15404
  env: { ...process.env, ...env2 },
15215
15405
  reject: false,
15406
+ buffer: false,
15407
+ // Enable streaming
15216
15408
  maxBuffer: MAX_OUTPUT_SIZE2
15217
15409
  };
15218
- const result = await execa("make", cmdArgs, options);
15410
+ const subprocess = execa("make", cmdArgs, options);
15411
+ let stdoutBuffer = "";
15412
+ let stderrBuffer = "";
15413
+ subprocess.stdout?.on("data", (chunk) => {
15414
+ const text = chunk.toString();
15415
+ stdoutBuffer += text;
15416
+ process.stdout.write(text);
15417
+ heartbeat.activity();
15418
+ });
15419
+ subprocess.stderr?.on("data", (chunk) => {
15420
+ const text = chunk.toString();
15421
+ stderrBuffer += text;
15422
+ process.stderr.write(text);
15423
+ heartbeat.activity();
15424
+ });
15425
+ const result = await subprocess;
15219
15426
  return {
15220
15427
  success: result.exitCode === 0,
15221
- stdout: truncateOutput2(String(result.stdout ?? "")),
15222
- stderr: truncateOutput2(String(result.stderr ?? "")),
15428
+ stdout: truncateOutput2(stdoutBuffer),
15429
+ stderr: truncateOutput2(stderrBuffer),
15223
15430
  exitCode: result.exitCode ?? 0,
15224
15431
  duration: performance.now() - startTime
15225
15432
  };
@@ -15235,6 +15442,9 @@ Examples:
15235
15442
  `Make failed: ${error instanceof Error ? error.message : String(error)}`,
15236
15443
  { tool: "make", cause: error instanceof Error ? error : void 0 }
15237
15444
  );
15445
+ } finally {
15446
+ heartbeat.stop();
15447
+ process.stderr.write("\r \r");
15238
15448
  }
15239
15449
  }
15240
15450
  });
@@ -15260,7 +15470,21 @@ Examples:
15260
15470
  const projectDir = cwd ?? process.cwd();
15261
15471
  const startTime = performance.now();
15262
15472
  const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
15473
+ const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
15474
+ const heartbeat = new CommandHeartbeat2({
15475
+ onUpdate: (stats) => {
15476
+ if (stats.elapsedSeconds > 10) {
15477
+ process.stderr.write(`\r\u23F1\uFE0F ${stats.elapsedSeconds}s elapsed`);
15478
+ }
15479
+ },
15480
+ onWarn: (message) => {
15481
+ process.stderr.write(`
15482
+ ${message}
15483
+ `);
15484
+ }
15485
+ });
15263
15486
  try {
15487
+ heartbeat.start();
15264
15488
  const cmdArgs = [];
15265
15489
  if (project) {
15266
15490
  cmdArgs.push("--project", project);
@@ -15278,13 +15502,30 @@ Examples:
15278
15502
  cwd: projectDir,
15279
15503
  timeout: timeoutMs,
15280
15504
  reject: false,
15505
+ buffer: false,
15506
+ // Enable streaming
15281
15507
  maxBuffer: MAX_OUTPUT_SIZE2
15282
15508
  };
15283
- const result = await execa("npx", ["tsc", ...cmdArgs], options);
15509
+ const subprocess = execa("npx", ["tsc", ...cmdArgs], options);
15510
+ let stdoutBuffer = "";
15511
+ let stderrBuffer = "";
15512
+ subprocess.stdout?.on("data", (chunk) => {
15513
+ const text = chunk.toString();
15514
+ stdoutBuffer += text;
15515
+ process.stdout.write(text);
15516
+ heartbeat.activity();
15517
+ });
15518
+ subprocess.stderr?.on("data", (chunk) => {
15519
+ const text = chunk.toString();
15520
+ stderrBuffer += text;
15521
+ process.stderr.write(text);
15522
+ heartbeat.activity();
15523
+ });
15524
+ const result = await subprocess;
15284
15525
  return {
15285
15526
  success: result.exitCode === 0,
15286
- stdout: truncateOutput2(String(result.stdout ?? "")),
15287
- stderr: truncateOutput2(String(result.stderr ?? "")),
15527
+ stdout: truncateOutput2(stdoutBuffer),
15528
+ stderr: truncateOutput2(stderrBuffer),
15288
15529
  exitCode: result.exitCode ?? 0,
15289
15530
  duration: performance.now() - startTime
15290
15531
  };
@@ -15299,6 +15540,9 @@ Examples:
15299
15540
  `TypeScript compile failed: ${error instanceof Error ? error.message : String(error)}`,
15300
15541
  { tool: "tsc", cause: error instanceof Error ? error : void 0 }
15301
15542
  );
15543
+ } finally {
15544
+ heartbeat.stop();
15545
+ process.stderr.write("\r \r");
15302
15546
  }
15303
15547
  }
15304
15548
  });