@corbat-tech/coco 2.20.0 → 2.20.1

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
@@ -10530,15 +10530,19 @@ function installProcessSafetyNet() {
10530
10530
  _safetyNetInstalled = true;
10531
10531
  const debug = Boolean(process.env["COCO_DEBUG"]);
10532
10532
  process.on("uncaughtException", (error) => {
10533
+ if (isAbortError(error)) return;
10533
10534
  const msg = error instanceof Error ? error.message : String(error);
10534
10535
  console.error(chalk2.red(`
10535
- \xD7 Unexpected error (uncaught): ${msg}`));
10536
+ \xD7 Unexpected error: ${msg}`));
10537
+ console.error(chalk2.dim(" The REPL continues \u2014 type your next message or /help"));
10536
10538
  if (debug) console.error(error.stack);
10537
10539
  });
10538
10540
  process.on("unhandledRejection", (reason) => {
10541
+ if (isAbortError(reason)) return;
10539
10542
  const msg = reason instanceof Error ? reason.message : String(reason);
10540
10543
  console.error(chalk2.red(`
10541
- \xD7 Unhandled rejection: ${msg}`));
10544
+ \xD7 Unhandled error: ${msg}`));
10545
+ console.error(chalk2.dim(" The REPL continues \u2014 type your next message or /help"));
10542
10546
  if (debug && reason instanceof Error) console.error(reason.stack);
10543
10547
  });
10544
10548
  }
@@ -36816,7 +36820,22 @@ async function savePermissionPreference(key, value) {
36816
36820
  }
36817
36821
  async function shouldShowPermissionSuggestion() {
36818
36822
  const prefs = await loadPermissionPreferences();
36819
- return !prefs.recommendedAllowlistApplied && !prefs.recommendedAllowlistDismissed;
36823
+ if (prefs.recommendedAllowlistDismissed) {
36824
+ return false;
36825
+ }
36826
+ if (!prefs.recommendedAllowlistApplied) {
36827
+ return true;
36828
+ }
36829
+ try {
36830
+ const content = await fs34__default.readFile(CONFIG_PATHS.trustedTools, "utf-8");
36831
+ const settings = JSON.parse(content);
36832
+ if (!settings.globalTrusted || settings.globalTrusted.length === 0) {
36833
+ return true;
36834
+ }
36835
+ } catch {
36836
+ return true;
36837
+ }
36838
+ return false;
36820
36839
  }
36821
36840
  async function applyRecommendedPermissions() {
36822
36841
  for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
@@ -47606,11 +47625,7 @@ ${icon} ${label}`);
47606
47625
  if (toolName === "edit_file") {
47607
47626
  console.log(`
47608
47627
  ${icon} ${chalk2.yellow.bold("EDIT")} ${chalk2.cyan(String(input.path || ""))}`);
47609
- const editPreview = renderEditPreview(
47610
- String(input.old_string || ""),
47611
- String(input.new_string || "")
47612
- );
47613
- if (editPreview) console.log(editPreview);
47628
+ printEditDiff(String(input.oldText || ""), String(input.newText || ""));
47614
47629
  return;
47615
47630
  }
47616
47631
  console.log(`
@@ -47682,20 +47697,21 @@ function wordLevelHighlight(deletedContent, addedContent) {
47682
47697
  }
47683
47698
  return { styledDelete, styledAdd };
47684
47699
  }
47685
- function renderEditPreview(oldStr, newStr) {
47700
+ function printEditDiff(oldStr, newStr) {
47686
47701
  const termWidth = Math.max(getTerminalWidth2() - 14, 30);
47687
47702
  const MAX_SHOWN = 30;
47688
47703
  if (!oldStr.trim()) {
47689
47704
  const lines = newStr.split("\n").filter((l) => l.trim().length > 0).slice(0, 6);
47690
- if (lines.length === 0) return "";
47705
+ if (lines.length === 0) return;
47691
47706
  const truncate4 = (s) => s.length > termWidth - 2 ? s.slice(0, termWidth - 3) + "\u2026" : s;
47692
- return lines.map((l) => {
47707
+ for (const l of lines) {
47693
47708
  const text13 = `+ ${truncate4(l)}`;
47694
47709
  const pad = Math.max(0, termWidth - stripAnsi(text13).length + 2);
47695
- return " " + diffBgAdd(text13 + " ".repeat(pad));
47696
- }).join("\n");
47710
+ console.log(" " + diffBgAdd(text13 + " ".repeat(pad)));
47711
+ }
47712
+ return;
47697
47713
  }
47698
- if (!newStr.trim() && !oldStr.trim()) return "";
47714
+ if (!newStr.trim() && !oldStr.trim()) return;
47699
47715
  const changes = diffLines(oldStr, newStr);
47700
47716
  const diffLineList = [];
47701
47717
  let oldNo = 1;
@@ -47717,7 +47733,7 @@ function renderEditPreview(oldStr, newStr) {
47717
47733
  }
47718
47734
  }
47719
47735
  }
47720
- if (diffLineList.length === 0) return "";
47736
+ if (diffLineList.length === 0) return;
47721
47737
  const pairs = pairAdjacentDiffLines(diffLineList);
47722
47738
  const pairedDeletes = new Set(pairs.map((p45) => p45.deleteIdx));
47723
47739
  const pairedAdds = new Set(pairs.map((p45) => p45.addIdx));
@@ -47739,7 +47755,6 @@ function renderEditPreview(oldStr, newStr) {
47739
47755
  if (n >= 0 && n < diffLineList.length) visibleIndices.add(n);
47740
47756
  }
47741
47757
  }
47742
- const result = [];
47743
47758
  let shown = 0;
47744
47759
  let prevIdx = -1;
47745
47760
  const truncate3 = (s) => s.length > termWidth ? s.slice(0, termWidth - 1) + "\u2026" : s;
@@ -47751,11 +47766,11 @@ function renderEditPreview(oldStr, newStr) {
47751
47766
  for (let i = 0; i < diffLineList.length; i++) {
47752
47767
  if (!visibleIndices.has(i)) continue;
47753
47768
  if (shown >= MAX_SHOWN) {
47754
- result.push(chalk2.dim(` \u2026 +${diffLineList.length - i} more lines`));
47769
+ console.log(chalk2.dim(` \u2026 +${diffLineList.length - i} more lines`));
47755
47770
  break;
47756
47771
  }
47757
47772
  if (prevIdx >= 0 && i > prevIdx + 1) {
47758
- result.push(chalk2.dim(" \u22EE"));
47773
+ console.log(chalk2.dim(" \u22EE"));
47759
47774
  }
47760
47775
  prevIdx = i;
47761
47776
  shown++;
@@ -47765,20 +47780,19 @@ function renderEditPreview(oldStr, newStr) {
47765
47780
  const visLen = stripAnsi(rawContent).length;
47766
47781
  const pad = Math.max(0, termWidth - visLen);
47767
47782
  const line = diffBgAdd(` + ${rawContent}${" ".repeat(pad)}`);
47768
- result.push(" " + gutter(void 0, dl.newLineNo) + line);
47783
+ console.log(" " + gutter(void 0, dl.newLineNo) + line);
47769
47784
  } else if (dl.type === "delete") {
47770
47785
  const rawContent = pairedDeletes.has(i) ? wordHighlights.get(i)?.styledDelete ?? truncate3(dl.content) : truncate3(dl.content);
47771
47786
  const visLen = stripAnsi(rawContent).length;
47772
47787
  const pad = Math.max(0, termWidth - visLen);
47773
47788
  const line = diffBgDel(` - ${rawContent}${" ".repeat(pad)}`);
47774
- result.push(" " + gutter(dl.oldLineNo, void 0) + line);
47789
+ console.log(" " + gutter(dl.oldLineNo, void 0) + line);
47775
47790
  } else {
47776
- result.push(
47791
+ console.log(
47777
47792
  " " + gutter(dl.oldLineNo, dl.newLineNo) + chalk2.dim(` ${truncate3(dl.content)}`)
47778
47793
  );
47779
47794
  }
47780
47795
  }
47781
- return result.join("\n");
47782
47796
  }
47783
47797
  function renderToolEnd(result) {
47784
47798
  const status = result.result.success ? chalk2.green("\u2713") : chalk2.red("\u2717");
@@ -49800,7 +49814,21 @@ var ParallelToolExecutor = class {
49800
49814
  if (isAbortError(error, signal)) {
49801
49815
  return null;
49802
49816
  }
49803
- throw error;
49817
+ const errMsg = error instanceof Error ? error.message : String(error);
49818
+ const duration2 = performance.now() - startTime;
49819
+ const executedCall2 = {
49820
+ id: toolCall.id,
49821
+ name: toolCall.name,
49822
+ input: toolCall.input,
49823
+ result: {
49824
+ success: false,
49825
+ output: `Unexpected error in ${toolCall.name}: ${errMsg}`,
49826
+ error: errMsg
49827
+ },
49828
+ duration: duration2
49829
+ };
49830
+ onToolEnd?.(executedCall2);
49831
+ return executedCall2;
49804
49832
  }
49805
49833
  if (!result.success && result.error && onPathAccessDenied) {
49806
49834
  const dirPath = extractDeniedPath(result.error);
@@ -49811,7 +49839,13 @@ var ParallelToolExecutor = class {
49811
49839
  } catch {
49812
49840
  }
49813
49841
  if (authorized) {
49814
- result = await registry.execute(toolCall.name, toolCall.input, { signal });
49842
+ try {
49843
+ result = await registry.execute(toolCall.name, toolCall.input, { signal });
49844
+ } catch (retryError) {
49845
+ if (isAbortError(retryError, signal)) return null;
49846
+ const msg = retryError instanceof Error ? retryError.message : String(retryError);
49847
+ result = { success: false, error: `Retry failed: ${msg}`, duration: 0 };
49848
+ }
49815
49849
  }
49816
49850
  }
49817
49851
  }
@@ -50110,7 +50144,18 @@ ${tail}`;
50110
50144
  const needsConfirmation = !options.skipConfirmation && !session.trustedTools.has(trustPattern) && requiresConfirmation(toolCall.name, toolCall.input);
50111
50145
  if (needsConfirmation) {
50112
50146
  options.onBeforeConfirmation?.();
50113
- const confirmResult = await confirmToolExecution(toolCall);
50147
+ let confirmResult;
50148
+ try {
50149
+ confirmResult = await confirmToolExecution(toolCall);
50150
+ } catch (confirmError) {
50151
+ options.onAfterConfirmation?.();
50152
+ declinedTools.set(
50153
+ toolCall.id,
50154
+ `Confirmation failed: ${confirmError instanceof Error ? confirmError.message : String(confirmError)}`
50155
+ );
50156
+ options.onToolSkipped?.(toolCall, "Confirmation error");
50157
+ continue;
50158
+ }
50114
50159
  options.onAfterConfirmation?.();
50115
50160
  if (typeof confirmResult === "object" && confirmResult.type === "edit") {
50116
50161
  const editedToolCall = {
@@ -51164,6 +51209,11 @@ async function startRepl(options = {}) {
51164
51209
  agentMessage = commandResult.forkPrompt;
51165
51210
  } else if (hasPendingImage()) {
51166
51211
  const images = consumePendingImages();
51212
+ const imagePrompts = images.map((img) => img.prompt).join("\n");
51213
+ const userText = input?.trim() || "";
51214
+ const combinedText = userText ? `${userText}
51215
+
51216
+ ${imagePrompts}`.trim() : imagePrompts;
51167
51217
  agentMessage = [
51168
51218
  ...images.map(
51169
51219
  (img) => ({
@@ -51173,7 +51223,7 @@ async function startRepl(options = {}) {
51173
51223
  ),
51174
51224
  {
51175
51225
  type: "text",
51176
- text: images.map((img) => img.prompt).join("\n")
51226
+ text: combinedText
51177
51227
  }
51178
51228
  ];
51179
51229
  } else {
@@ -51182,6 +51232,11 @@ async function startRepl(options = {}) {
51182
51232
  }
51183
51233
  if (agentMessage === null && hasPendingImage()) {
51184
51234
  const images = consumePendingImages();
51235
+ const imagePrompts = images.map((img) => img.prompt).join("\n");
51236
+ const userText = input?.trim() || "";
51237
+ const combinedText = userText ? `${userText}
51238
+
51239
+ ${imagePrompts}`.trim() : imagePrompts;
51185
51240
  agentMessage = [
51186
51241
  ...images.map(
51187
51242
  (img) => ({
@@ -51191,7 +51246,7 @@ async function startRepl(options = {}) {
51191
51246
  ),
51192
51247
  {
51193
51248
  type: "text",
51194
- text: images.map((img) => img.prompt).join("\n")
51249
+ text: combinedText
51195
51250
  }
51196
51251
  ];
51197
51252
  }
@@ -51524,6 +51579,31 @@ async function startRepl(options = {}) {
51524
51579
  console.log();
51525
51580
  continue;
51526
51581
  }
51582
+ if (result.error) {
51583
+ session.messages.length = preCallMessageLength;
51584
+ if (originalUserMessage !== null && consecutiveErrors < MAX_CONSECUTIVE_ERRORS && !isNonRetryableProviderError(new Error(result.error))) {
51585
+ consecutiveErrors++;
51586
+ const humanized = humanizeProviderError(new Error(result.error));
51587
+ renderError(humanized);
51588
+ console.log(
51589
+ chalk2.dim(
51590
+ ` \u21BB Retrying automatically (attempt ${consecutiveErrors}/${MAX_CONSECUTIVE_ERRORS})\u2026`
51591
+ )
51592
+ );
51593
+ const recoveryPrefix = `[System: The previous attempt failed with: "${humanized}". Please try a different approach, tool, or method to complete the task. Do NOT repeat the exact same action that caused the error.]
51594
+
51595
+ `;
51596
+ pendingQueuedMessages = [recoveryPrefix + originalUserMessage];
51597
+ } else {
51598
+ renderError(result.error);
51599
+ console.log(
51600
+ chalk2.dim(" Recovery failed or error is non-retryable. Returning to prompt.")
51601
+ );
51602
+ consecutiveErrors = 0;
51603
+ }
51604
+ console.log();
51605
+ continue;
51606
+ }
51527
51607
  console.log();
51528
51608
  if (pendingExplanations.length > 0) {
51529
51609
  const settled = await Promise.race([
@@ -52122,6 +52202,7 @@ registerSwarmCommand(program);
52122
52202
  program.command("setup").description("Configure AI provider and API key").action(async () => {
52123
52203
  const result = await runOnboardingV2();
52124
52204
  if (result) {
52205
+ await saveConfiguration(result);
52125
52206
  console.log("\n\u2705 Configuration saved! Run `coco` to start coding.");
52126
52207
  } else {
52127
52208
  console.log("\n\u274C Setup cancelled.");
@@ -52135,6 +52216,7 @@ program.command("chat", { isDefault: true }).description("Start interactive chat
52135
52216
  console.log("\n\u274C Setup cancelled.");
52136
52217
  return;
52137
52218
  }
52219
+ await saveConfiguration(result);
52138
52220
  }
52139
52221
  const providerType = options.provider ?? await getLastUsedProvider();
52140
52222
  if (options.print !== void 0) {