@corbat-tech/coco 2.27.2 → 2.27.4

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
@@ -791,8 +791,8 @@ async function requestDeviceCode(provider) {
791
791
  }
792
792
  const contentType = response.headers.get("content-type") || "";
793
793
  if (!contentType.includes("application/json")) {
794
- const text14 = await response.text();
795
- if (text14.includes("<!DOCTYPE") || text14.includes("<html")) {
794
+ const text15 = await response.text();
795
+ if (text15.includes("<!DOCTYPE") || text15.includes("<html")) {
796
796
  throw new Error(
797
797
  "OAuth service returned HTML instead of JSON.\n The service may be temporarily unavailable.\n Please use an API key instead, or try again later."
798
798
  );
@@ -3377,25 +3377,25 @@ var init_anthropic = __esm({
3377
3377
  *
3378
3378
  * This heuristic analyzes the text to provide a better estimate.
3379
3379
  */
3380
- countTokens(text14) {
3381
- if (!text14) return 0;
3380
+ countTokens(text15) {
3381
+ if (!text15) return 0;
3382
3382
  const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
3383
3383
  const whitespacePattern = /\s/g;
3384
3384
  const wordPattern = /\b\w+\b/g;
3385
- const codeChars = (text14.match(codePatterns) || []).length;
3386
- const whitespace = (text14.match(whitespacePattern) || []).length;
3387
- const words = (text14.match(wordPattern) || []).length;
3388
- const isCodeLike = codeChars > text14.length * 0.05;
3385
+ const codeChars = (text15.match(codePatterns) || []).length;
3386
+ const whitespace = (text15.match(whitespacePattern) || []).length;
3387
+ const words = (text15.match(wordPattern) || []).length;
3388
+ const isCodeLike = codeChars > text15.length * 0.05;
3389
3389
  let charsPerToken;
3390
3390
  if (isCodeLike) {
3391
3391
  charsPerToken = 3.5;
3392
- } else if (whitespace > text14.length * 0.3) {
3392
+ } else if (whitespace > text15.length * 0.3) {
3393
3393
  charsPerToken = 5;
3394
3394
  } else {
3395
3395
  charsPerToken = 4.5;
3396
3396
  }
3397
3397
  const wordBasedEstimate = words * 1.3;
3398
- const charBasedEstimate = text14.length / charsPerToken;
3398
+ const charBasedEstimate = text15.length / charsPerToken;
3399
3399
  return Math.ceil((wordBasedEstimate + charBasedEstimate) / 2);
3400
3400
  }
3401
3401
  /**
@@ -3444,8 +3444,8 @@ var init_anthropic = __esm({
3444
3444
  const systemMsg = messages.find((m) => m.role === "system");
3445
3445
  if (!systemMsg) return void 0;
3446
3446
  if (typeof systemMsg.content === "string") return systemMsg.content;
3447
- const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
3448
- return text14 || void 0;
3447
+ const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
3448
+ return text15 || void 0;
3449
3449
  }
3450
3450
  /**
3451
3451
  * Convert messages to Anthropic format
@@ -3633,15 +3633,15 @@ var init_tool_call_normalizer = __esm({
3633
3633
  if (delta.function?.name) {
3634
3634
  builder.name = delta.function.name;
3635
3635
  }
3636
- const text14 = delta.function?.arguments ?? "";
3637
- if (!text14) return { started };
3638
- builder.arguments += text14;
3636
+ const text15 = delta.function?.arguments ?? "";
3637
+ if (!text15) return { started };
3638
+ builder.arguments += text15;
3639
3639
  return {
3640
3640
  started,
3641
3641
  argumentDelta: {
3642
3642
  id: builder.id,
3643
3643
  name: builder.name,
3644
- text: text14
3644
+ text: text15
3645
3645
  }
3646
3646
  };
3647
3647
  }
@@ -4230,23 +4230,23 @@ var init_openai = __esm({
4230
4230
  * For accurate counting, use the model's native tokenizer.
4231
4231
  * This heuristic provides a reasonable estimate without dependencies.
4232
4232
  */
4233
- countTokens(text14) {
4234
- if (!text14) return 0;
4233
+ countTokens(text15) {
4234
+ if (!text15) return 0;
4235
4235
  const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
4236
4236
  const whitespacePattern = /\s/g;
4237
4237
  const wordPattern = /\b\w+\b/g;
4238
4238
  const nonAsciiPattern = /[^\x00-\x7F]/g;
4239
- const codeChars = (text14.match(codePatterns) || []).length;
4240
- const whitespace = (text14.match(whitespacePattern) || []).length;
4241
- const words = (text14.match(wordPattern) || []).length;
4242
- const nonAscii = (text14.match(nonAsciiPattern) || []).length;
4243
- const isCodeLike = codeChars > text14.length * 0.05;
4239
+ const codeChars = (text15.match(codePatterns) || []).length;
4240
+ const whitespace = (text15.match(whitespacePattern) || []).length;
4241
+ const words = (text15.match(wordPattern) || []).length;
4242
+ const nonAscii = (text15.match(nonAsciiPattern) || []).length;
4243
+ const isCodeLike = codeChars > text15.length * 0.05;
4244
4244
  const isLocal = this.isLocalModel();
4245
4245
  let charsPerToken;
4246
4246
  if (isLocal) {
4247
4247
  if (isCodeLike) {
4248
4248
  charsPerToken = 3.2;
4249
- } else if (nonAscii > text14.length * 0.1) {
4249
+ } else if (nonAscii > text15.length * 0.1) {
4250
4250
  charsPerToken = 2;
4251
4251
  } else {
4252
4252
  charsPerToken = 3.5;
@@ -4254,7 +4254,7 @@ var init_openai = __esm({
4254
4254
  } else {
4255
4255
  if (isCodeLike) {
4256
4256
  charsPerToken = 3.3;
4257
- } else if (whitespace > text14.length * 0.3) {
4257
+ } else if (whitespace > text15.length * 0.3) {
4258
4258
  charsPerToken = 4.5;
4259
4259
  } else {
4260
4260
  charsPerToken = 4;
@@ -4262,7 +4262,7 @@ var init_openai = __esm({
4262
4262
  }
4263
4263
  const tokensPerWord = isLocal ? 1.4 : 1.3;
4264
4264
  const wordBasedEstimate = words * tokensPerWord;
4265
- const charBasedEstimate = text14.length / charsPerToken;
4265
+ const charBasedEstimate = text15.length / charsPerToken;
4266
4266
  const weight = isCodeLike ? 0.7 : 0.5;
4267
4267
  return Math.ceil(charBasedEstimate * weight + wordBasedEstimate * (1 - weight));
4268
4268
  }
@@ -5043,8 +5043,8 @@ var init_codex = __esm({
5043
5043
  * Count tokens in text (approximate)
5044
5044
  * Uses GPT-4 approximation: ~4 chars per token
5045
5045
  */
5046
- countTokens(text14) {
5047
- return Math.ceil(text14.length / 4);
5046
+ countTokens(text15) {
5047
+ return Math.ceil(text15.length / 4);
5048
5048
  }
5049
5049
  /**
5050
5050
  * Check if provider is available (has valid OAuth tokens)
@@ -5597,23 +5597,35 @@ var init_copilot2 = __esm({
5597
5597
  CONTEXT_WINDOWS4 = {
5598
5598
  // Claude models — Copilot API caps these at 168 000 (not 200 000 like Anthropic direct)
5599
5599
  "claude-sonnet-4.6": 168e3,
5600
+ "claude-sonnet-4": 168e3,
5600
5601
  "claude-opus-4.6": 168e3,
5602
+ "claude-opus-4.6-fast": 168e3,
5601
5603
  "claude-sonnet-4.5": 168e3,
5602
5604
  "claude-opus-4.5": 168e3,
5603
5605
  "claude-haiku-4.5": 168e3,
5604
5606
  // OpenAI models — chat/completions
5605
5607
  "gpt-4.1": 1048576,
5608
+ "gpt-4o": 128e3,
5606
5609
  // OpenAI models — /responses API (Codex/GPT-5+)
5607
5610
  "gpt-5.4-codex": 4e5,
5611
+ "gpt-5.4": 4e5,
5612
+ "gpt-5.4-mini": 4e5,
5608
5613
  "gpt-5.3-codex": 4e5,
5609
5614
  "gpt-5.2-codex": 4e5,
5610
5615
  "gpt-5.1-codex-max": 4e5,
5616
+ "gpt-5-mini": 4e5,
5611
5617
  "gpt-5.2": 4e5,
5612
5618
  "gpt-5.1": 4e5,
5613
5619
  // Google models
5620
+ "gemini-3.1-pro": 1e6,
5614
5621
  "gemini-3.1-pro-preview": 1e6,
5622
+ "gemini-3-flash": 1e6,
5615
5623
  "gemini-3-flash-preview": 1e6,
5616
- "gemini-2.5-pro": 1048576
5624
+ "gemini-2.5-pro": 1048576,
5625
+ // Evaluation models
5626
+ "grok-code-fast-1": 4e5,
5627
+ "raptor-mini": 4e5,
5628
+ goldeneye: 4e5
5617
5629
  };
5618
5630
  DEFAULT_MODEL4 = "claude-sonnet-4.6";
5619
5631
  COPILOT_HEADERS = {
@@ -5712,9 +5724,9 @@ var init_copilot2 = __esm({
5712
5724
  /**
5713
5725
  * Count tokens (approximate — Copilot models vary in tokenizer)
5714
5726
  */
5715
- countTokens(text14) {
5716
- if (!text14) return 0;
5717
- return Math.ceil(text14.length / 3.5);
5727
+ countTokens(text15) {
5728
+ if (!text15) return 0;
5729
+ return Math.ceil(text15.length / 3.5);
5718
5730
  }
5719
5731
  /**
5720
5732
  * Get context window for the current model
@@ -5812,9 +5824,9 @@ var init_gemini = __esm({
5812
5824
  });
5813
5825
  let streamStopReason = "end_turn";
5814
5826
  for await (const chunk of stream) {
5815
- const text14 = chunk.text;
5816
- if (text14) {
5817
- yield { type: "text", text: text14 };
5827
+ const text15 = chunk.text;
5828
+ if (text15) {
5829
+ yield { type: "text", text: text15 };
5818
5830
  }
5819
5831
  const finishReason = chunk.candidates?.[0]?.finishReason;
5820
5832
  if (finishReason) {
@@ -5838,9 +5850,9 @@ var init_gemini = __esm({
5838
5850
  let fallbackToolCounter = 0;
5839
5851
  const emittedToolIds = /* @__PURE__ */ new Set();
5840
5852
  for await (const chunk of stream) {
5841
- const text14 = chunk.text;
5842
- if (text14) {
5843
- yield { type: "text", text: text14 };
5853
+ const text15 = chunk.text;
5854
+ if (text15) {
5855
+ yield { type: "text", text: text15 };
5844
5856
  }
5845
5857
  const functionCalls = this.extractFunctionCalls(chunk);
5846
5858
  for (const functionCall of functionCalls) {
@@ -5876,9 +5888,9 @@ var init_gemini = __esm({
5876
5888
  throw this.handleError(error);
5877
5889
  }
5878
5890
  }
5879
- countTokens(text14) {
5880
- if (!text14) return 0;
5881
- return Math.ceil(text14.length / 3.5);
5891
+ countTokens(text15) {
5892
+ if (!text15) return 0;
5893
+ return Math.ceil(text15.length / 3.5);
5882
5894
  }
5883
5895
  getContextWindow() {
5884
5896
  const model = this.config.model ?? DEFAULT_MODEL5;
@@ -5926,8 +5938,8 @@ var init_gemini = __esm({
5926
5938
  const systemMsg = messages.find((m) => m.role === "system");
5927
5939
  if (!systemMsg) return void 0;
5928
5940
  if (typeof systemMsg.content === "string") return systemMsg.content;
5929
- const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
5930
- return text14 || void 0;
5941
+ const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
5942
+ return text15 || void 0;
5931
5943
  }
5932
5944
  convertContents(messages) {
5933
5945
  const toolNameByUseId = this.buildToolUseNameMap(messages);
@@ -6224,8 +6236,8 @@ var init_vertex = __esm({
6224
6236
  }
6225
6237
  yield { type: "done", stopReason };
6226
6238
  }
6227
- countTokens(text14) {
6228
- return Math.ceil(text14.length / 4);
6239
+ countTokens(text15) {
6240
+ return Math.ceil(text15.length / 4);
6229
6241
  }
6230
6242
  getContextWindow() {
6231
6243
  return CONTEXT_WINDOWS6[this.config.model ?? DEFAULT_MODEL6] ?? 1048576;
@@ -6287,8 +6299,8 @@ var init_vertex = __esm({
6287
6299
  const systemMsg = messages.find((m) => m.role === "system");
6288
6300
  if (!systemMsg) return void 0;
6289
6301
  if (typeof systemMsg.content === "string") return systemMsg.content;
6290
- const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
6291
- return text14 || void 0;
6302
+ const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
6303
+ return text15 || void 0;
6292
6304
  }
6293
6305
  buildToolUseNameMap(messages) {
6294
6306
  const map = /* @__PURE__ */ new Map();
@@ -6465,10 +6477,10 @@ var init_vertex = __esm({
6465
6477
  }
6466
6478
  parseResponse(response, model) {
6467
6479
  const candidate = response.candidates?.[0];
6468
- const text14 = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
6480
+ const text15 = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
6469
6481
  return {
6470
6482
  id: `vertex-${Date.now()}`,
6471
- content: text14,
6483
+ content: text15,
6472
6484
  stopReason: this.mapFinishReason(candidate?.finishReason),
6473
6485
  usage: {
6474
6486
  inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
@@ -6854,7 +6866,7 @@ var init_fallback = __esm({
6854
6866
  */
6855
6867
  async initialize(config) {
6856
6868
  const results = await Promise.allSettled(
6857
- this.providers.map((p45) => p45.provider.initialize(config))
6869
+ this.providers.map((p46) => p46.provider.initialize(config))
6858
6870
  );
6859
6871
  const anySuccess = results.some((r) => r.status === "fulfilled");
6860
6872
  if (!anySuccess) {
@@ -6951,9 +6963,9 @@ var init_fallback = __esm({
6951
6963
  * @param text - Text to count tokens for
6952
6964
  * @returns Estimated token count
6953
6965
  */
6954
- countTokens(text14) {
6966
+ countTokens(text15) {
6955
6967
  const provider = this.getCurrentProvider();
6956
- return provider.provider.countTokens(text14);
6968
+ return provider.provider.countTokens(text15);
6957
6969
  }
6958
6970
  /**
6959
6971
  * Get context window from current provider
@@ -6976,11 +6988,11 @@ var init_fallback = __esm({
6976
6988
  */
6977
6989
  async isAvailable() {
6978
6990
  const results = await Promise.all(
6979
- this.providers.map(async (p45) => {
6980
- if (p45.breaker.isOpen()) {
6991
+ this.providers.map(async (p46) => {
6992
+ if (p46.breaker.isOpen()) {
6981
6993
  return false;
6982
6994
  }
6983
- return p45.provider.isAvailable();
6995
+ return p46.provider.isAvailable();
6984
6996
  })
6985
6997
  );
6986
6998
  return results.some((available) => available);
@@ -7011,10 +7023,10 @@ var init_fallback = __esm({
7011
7023
  * @returns Array of provider status objects
7012
7024
  */
7013
7025
  getCircuitStatus() {
7014
- return this.providers.map((p45) => ({
7015
- providerId: p45.provider.id,
7016
- state: p45.breaker.getState(),
7017
- failureCount: p45.breaker.getFailureCount()
7026
+ return this.providers.map((p46) => ({
7027
+ providerId: p46.provider.id,
7028
+ state: p46.breaker.getState(),
7029
+ failureCount: p46.breaker.getFailureCount()
7018
7030
  }));
7019
7031
  }
7020
7032
  /**
@@ -7024,8 +7036,8 @@ var init_fallback = __esm({
7024
7036
  * previously failing providers to be tried again.
7025
7037
  */
7026
7038
  resetCircuits() {
7027
- for (const p45 of this.providers) {
7028
- p45.breaker.reset();
7039
+ for (const p46 of this.providers) {
7040
+ p46.breaker.reset();
7029
7041
  }
7030
7042
  }
7031
7043
  /**
@@ -7169,8 +7181,8 @@ var init_resilient = __esm({
7169
7181
  async *streamWithTools(messages, options) {
7170
7182
  yield* this.streamWithPolicy(() => this.provider.streamWithTools(messages, options));
7171
7183
  }
7172
- countTokens(text14) {
7173
- return this.provider.countTokens(text14);
7184
+ countTokens(text15) {
7185
+ return this.provider.countTokens(text15);
7174
7186
  }
7175
7187
  getContextWindow() {
7176
7188
  return this.provider.getContextWindow();
@@ -8483,8 +8495,8 @@ function tokenOverlap(queryTokens, targetTokens) {
8483
8495
  }
8484
8496
  return hits / queryTokens.length;
8485
8497
  }
8486
- function tokenize(text14) {
8487
- return text14.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/[\s-]+/).filter((word) => word.length > 1 && !STOP_WORDS.has(word)).map(stem);
8498
+ function tokenize(text15) {
8499
+ return text15.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/[\s-]+/).filter((word) => word.length > 1 && !STOP_WORDS.has(word)).map(stem);
8488
8500
  }
8489
8501
  function stem(word) {
8490
8502
  if (word.length < 4) return word;
@@ -9581,8 +9593,8 @@ ${tail}`
9581
9593
  estimateTokens(messages, provider) {
9582
9594
  let total = 0;
9583
9595
  for (const message of messages) {
9584
- const text14 = this.extractTextContent(message.content);
9585
- total += provider.countTokens(text14);
9596
+ const text15 = this.extractTextContent(message.content);
9597
+ total += provider.countTokens(text15);
9586
9598
  }
9587
9599
  return total;
9588
9600
  }
@@ -11616,7 +11628,7 @@ function humanizeError(message, toolName) {
11616
11628
  return msg;
11617
11629
  }
11618
11630
  function looksLikeTechnicalJargon(message) {
11619
- return JARGON_PATTERNS.some((p45) => p45.test(message));
11631
+ return JARGON_PATTERNS.some((p46) => p46.test(message));
11620
11632
  }
11621
11633
  async function humanizeWithLLM(errorMessage, toolName, provider) {
11622
11634
  const prompt = [
@@ -12377,9 +12389,9 @@ function renderFileBlock(file, opts) {
12377
12389
  );
12378
12390
  }
12379
12391
  const pairs = pairAdjacentLines(hunk.lines);
12380
- const pairedDeleteIndices = new Set(pairs.map((p45) => p45.deleteIdx));
12381
- const pairedAddIndices = new Set(pairs.map((p45) => p45.addIdx));
12382
- const pairByAdd = new Map(pairs.map((p45) => [p45.addIdx, p45.deleteIdx]));
12392
+ const pairedDeleteIndices = new Set(pairs.map((p46) => p46.deleteIdx));
12393
+ const pairedAddIndices = new Set(pairs.map((p46) => p46.addIdx));
12394
+ const pairByAdd = new Map(pairs.map((p46) => [p46.addIdx, p46.deleteIdx]));
12383
12395
  const wordHighlights = /* @__PURE__ */ new Map();
12384
12396
  for (const pair of pairs) {
12385
12397
  const delLine = hunk.lines[pair.deleteIdx];
@@ -12835,10 +12847,10 @@ var init_coverage = __esm({
12835
12847
  join(this.projectPath, ".coverage", "coverage-summary.json"),
12836
12848
  join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
12837
12849
  ];
12838
- for (const p45 of possiblePaths) {
12850
+ for (const p46 of possiblePaths) {
12839
12851
  try {
12840
- await access(p45, constants.R_OK);
12841
- const content = await readFile(p45, "utf-8");
12852
+ await access(p46, constants.R_OK);
12853
+ const content = await readFile(p46, "utf-8");
12842
12854
  const report = JSON.parse(content);
12843
12855
  return parseCoverageSummary(report);
12844
12856
  } catch {
@@ -18672,15 +18684,15 @@ ${message}
18672
18684
  let stdoutBuffer = "";
18673
18685
  let stderrBuffer = "";
18674
18686
  subprocess.stdout?.on("data", (chunk) => {
18675
- const text14 = chunk.toString();
18676
- stdoutBuffer += text14;
18677
- process.stdout.write(text14);
18687
+ const text15 = chunk.toString();
18688
+ stdoutBuffer += text15;
18689
+ process.stdout.write(text15);
18678
18690
  heartbeat.activity();
18679
18691
  });
18680
18692
  subprocess.stderr?.on("data", (chunk) => {
18681
- const text14 = chunk.toString();
18682
- stderrBuffer += text14;
18683
- process.stderr.write(text14);
18693
+ const text15 = chunk.toString();
18694
+ stderrBuffer += text15;
18695
+ process.stderr.write(text15);
18684
18696
  heartbeat.activity();
18685
18697
  });
18686
18698
  const result = await subprocess;
@@ -20641,11 +20653,11 @@ function isBlockedPath(absolute) {
20641
20653
  return void 0;
20642
20654
  }
20643
20655
  function isBlockedExecFile(filePath) {
20644
- return BLOCKED_EXEC_PATTERNS.some((p45) => p45.test(filePath));
20656
+ return BLOCKED_EXEC_PATTERNS.some((p46) => p46.test(filePath));
20645
20657
  }
20646
20658
  function hasDangerousArgs(args) {
20647
20659
  const joined = args.join(" ");
20648
- return DANGEROUS_ARG_PATTERNS.some((p45) => p45.test(joined));
20660
+ return DANGEROUS_ARG_PATTERNS.some((p46) => p46.test(joined));
20649
20661
  }
20650
20662
  function getInterpreter(ext) {
20651
20663
  return INTERPRETER_MAP[ext.toLowerCase()];
@@ -23146,22 +23158,22 @@ var init_types7 = __esm({
23146
23158
  });
23147
23159
 
23148
23160
  // src/cli/repl/interruptions/classifier.ts
23149
- function matchPatterns(text14, patterns) {
23161
+ function matchPatterns(text15, patterns) {
23150
23162
  for (let i = 0; i < patterns.length; i++) {
23151
- if (patterns[i].test(text14)) {
23163
+ if (patterns[i].test(text15)) {
23152
23164
  return 1 - i * 0.1;
23153
23165
  }
23154
23166
  }
23155
23167
  return 0;
23156
23168
  }
23157
23169
  function classifyInterruption(message) {
23158
- const text14 = message.text;
23159
- const abortConf = matchPatterns(text14, ABORT_PATTERNS);
23160
- const modifyConf = matchPatterns(text14, MODIFY_PATTERNS);
23161
- const correctConf = matchPatterns(text14, CORRECT_PATTERNS);
23170
+ const text15 = message.text;
23171
+ const abortConf = matchPatterns(text15, ABORT_PATTERNS);
23172
+ const modifyConf = matchPatterns(text15, MODIFY_PATTERNS);
23173
+ const correctConf = matchPatterns(text15, CORRECT_PATTERNS);
23162
23174
  if (abortConf > 0 && abortConf >= modifyConf && abortConf >= correctConf) {
23163
23175
  return {
23164
- text: text14,
23176
+ text: text15,
23165
23177
  type: "abort" /* Abort */,
23166
23178
  confidence: Math.min(1, abortConf),
23167
23179
  timestamp: message.timestamp
@@ -23169,7 +23181,7 @@ function classifyInterruption(message) {
23169
23181
  }
23170
23182
  if (modifyConf > 0 && modifyConf >= correctConf) {
23171
23183
  return {
23172
- text: text14,
23184
+ text: text15,
23173
23185
  type: "modify" /* Modify */,
23174
23186
  confidence: Math.min(1, modifyConf),
23175
23187
  timestamp: message.timestamp
@@ -23177,14 +23189,14 @@ function classifyInterruption(message) {
23177
23189
  }
23178
23190
  if (correctConf > 0) {
23179
23191
  return {
23180
- text: text14,
23192
+ text: text15,
23181
23193
  type: "correct" /* Correct */,
23182
23194
  confidence: Math.min(1, correctConf),
23183
23195
  timestamp: message.timestamp
23184
23196
  };
23185
23197
  }
23186
23198
  return {
23187
- text: text14,
23199
+ text: text15,
23188
23200
  type: "info" /* Info */,
23189
23201
  confidence: 0.5,
23190
23202
  timestamp: message.timestamp
@@ -25692,10 +25704,10 @@ function inferTargetUsers(session) {
25692
25704
  /(?:for|by)\s+(developers?|users?|administrators?|customers?)/gi,
25693
25705
  /(developers?|users?|administrators?|customers?)\s+(?:can|will|should)/gi
25694
25706
  ];
25695
- const text14 = session.requirements.map((r) => r.description).join(" ");
25707
+ const text15 = session.requirements.map((r) => r.description).join(" ");
25696
25708
  for (const pattern of userPatterns) {
25697
25709
  let match;
25698
- while ((match = pattern.exec(text14)) !== null) {
25710
+ while ((match = pattern.exec(text15)) !== null) {
25699
25711
  const user = match[1]?.toLowerCase();
25700
25712
  if (user && !users.includes(user)) {
25701
25713
  users.push(user);
@@ -25708,13 +25720,13 @@ function inferTargetUsers(session) {
25708
25720
  return users;
25709
25721
  }
25710
25722
  function inferProjectType(session) {
25711
- const text14 = session.initialInput.toLowerCase();
25712
- if (text14.includes("cli") || text14.includes("command line")) return "cli";
25713
- if (text14.includes("api") || text14.includes("rest") || text14.includes("graphql")) return "api";
25714
- if (text14.includes("web app") || text14.includes("frontend")) return "web_app";
25715
- if (text14.includes("library") || text14.includes("package")) return "library";
25716
- if (text14.includes("service") || text14.includes("daemon")) return "service";
25717
- if (text14.includes("full stack") || text14.includes("fullstack")) return "full_stack";
25723
+ const text15 = session.initialInput.toLowerCase();
25724
+ if (text15.includes("cli") || text15.includes("command line")) return "cli";
25725
+ if (text15.includes("api") || text15.includes("rest") || text15.includes("graphql")) return "api";
25726
+ if (text15.includes("web app") || text15.includes("frontend")) return "web_app";
25727
+ if (text15.includes("library") || text15.includes("package")) return "library";
25728
+ if (text15.includes("service") || text15.includes("daemon")) return "service";
25729
+ if (text15.includes("full stack") || text15.includes("fullstack")) return "full_stack";
25718
25730
  return "unknown";
25719
25731
  }
25720
25732
  function assessComplexity(session) {
@@ -29254,6 +29266,20 @@ var PROVIDER_DEFINITIONS = {
29254
29266
  contextWindow: 2e5,
29255
29267
  maxOutputTokens: 64e3
29256
29268
  },
29269
+ {
29270
+ id: "claude-sonnet-4",
29271
+ name: "Claude Sonnet 4",
29272
+ description: "Previous balanced Claude model via Copilot \u2014 Premium x1",
29273
+ contextWindow: 2e5,
29274
+ maxOutputTokens: 64e3
29275
+ },
29276
+ {
29277
+ id: "claude-opus-4.6-fast",
29278
+ name: "Claude Opus 4.6 (Fast)",
29279
+ description: "Public preview fast Opus mode via Copilot \u2014 Premium x30",
29280
+ contextWindow: 2e5,
29281
+ maxOutputTokens: 128e3
29282
+ },
29257
29283
  // OpenAI models (Codex/GPT-5+ use /responses API, others use /chat/completions)
29258
29284
  {
29259
29285
  id: "gpt-5.4-codex",
@@ -29278,40 +29304,111 @@ var PROVIDER_DEFINITIONS = {
29278
29304
  maxOutputTokens: 128e3
29279
29305
  },
29280
29306
  {
29281
- id: "gpt-5.1-codex-max",
29282
- name: "GPT-5.1 Codex Max",
29283
- description: "Frontier agentic coding model via Copilot \u2014 Premium x1",
29307
+ id: "gpt-5.2",
29308
+ name: "GPT-5.2",
29309
+ description: "General GPT-5 model via Copilot \u2014 Premium x1",
29310
+ contextWindow: 4e5,
29311
+ maxOutputTokens: 128e3
29312
+ },
29313
+ {
29314
+ id: "gpt-5.4",
29315
+ name: "GPT-5.4",
29316
+ description: "Latest general GPT-5 model via Copilot \u2014 Premium x1",
29317
+ contextWindow: 4e5,
29318
+ maxOutputTokens: 128e3
29319
+ },
29320
+ {
29321
+ id: "gpt-5.4-mini",
29322
+ name: "GPT-5.4 mini",
29323
+ description: "Fast GPT-5.4 variant via Copilot \u2014 Premium x0.33",
29324
+ contextWindow: 4e5,
29325
+ maxOutputTokens: 128e3
29326
+ },
29327
+ {
29328
+ id: "gpt-5-mini",
29329
+ name: "GPT-5 mini",
29330
+ description: "Included model via Copilot paid plans \u2014 Premium x0",
29331
+ contextWindow: 4e5,
29332
+ maxOutputTokens: 128e3
29333
+ },
29334
+ {
29335
+ id: "gpt-5.1",
29336
+ name: "GPT-5.1",
29337
+ description: "Legacy GPT-5 model via Copilot \u2014 Premium x1",
29284
29338
  contextWindow: 4e5,
29285
29339
  maxOutputTokens: 128e3
29286
29340
  },
29287
29341
  {
29288
29342
  id: "gpt-4.1",
29289
29343
  name: "GPT-4.1",
29290
- description: "OpenAI long-context model via Copilot (1M) \u2014 Premium x0",
29344
+ description: "Included OpenAI model via Copilot paid plans \u2014 Premium x0",
29291
29345
  contextWindow: 1048576,
29292
29346
  maxOutputTokens: 32768
29293
29347
  },
29348
+ {
29349
+ id: "gpt-4o",
29350
+ name: "GPT-4o",
29351
+ description: "Included fallback/LTS OpenAI model via Copilot paid plans \u2014 Premium x0",
29352
+ contextWindow: 128e3,
29353
+ maxOutputTokens: 16384
29354
+ },
29294
29355
  // Google models
29295
29356
  {
29296
- id: "gemini-3.1-pro-preview",
29357
+ id: "gemini-3.1-pro",
29297
29358
  name: "Gemini 3.1 Pro",
29298
29359
  description: "Google's latest model via Copilot (1M) \u2014 Premium x1",
29299
29360
  contextWindow: 1e6,
29300
29361
  maxOutputTokens: 64e3
29301
29362
  },
29302
29363
  {
29303
- id: "gemini-3-flash-preview",
29364
+ id: "gemini-3.1-pro-preview",
29365
+ name: "Gemini 3.1 Pro (Preview ID)",
29366
+ description: "Compatibility alias for Gemini 3.1 Pro via Copilot \u2014 Premium x1",
29367
+ contextWindow: 1e6,
29368
+ maxOutputTokens: 64e3
29369
+ },
29370
+ {
29371
+ id: "gemini-3-flash",
29304
29372
  name: "Gemini 3 Flash",
29305
29373
  description: "Google's fast model via Copilot (1M) \u2014 Premium x0.33",
29306
29374
  contextWindow: 1e6,
29307
29375
  maxOutputTokens: 64e3
29308
29376
  },
29377
+ {
29378
+ id: "gemini-3-flash-preview",
29379
+ name: "Gemini 3 Flash (Preview ID)",
29380
+ description: "Compatibility alias for Gemini 3 Flash via Copilot \u2014 Premium x0.33",
29381
+ contextWindow: 1e6,
29382
+ maxOutputTokens: 64e3
29383
+ },
29309
29384
  {
29310
29385
  id: "gemini-2.5-pro",
29311
29386
  name: "Gemini 2.5 Pro",
29312
29387
  description: "Google stable model via Copilot (1M) \u2014 Premium x1",
29313
29388
  contextWindow: 1048576,
29314
29389
  maxOutputTokens: 65536
29390
+ },
29391
+ // Evaluation models
29392
+ {
29393
+ id: "grok-code-fast-1",
29394
+ name: "Grok Code Fast 1",
29395
+ description: "xAI coding model via Copilot \u2014 Premium x0.25",
29396
+ contextWindow: 4e5,
29397
+ maxOutputTokens: 128e3
29398
+ },
29399
+ {
29400
+ id: "raptor-mini",
29401
+ name: "Raptor mini",
29402
+ description: "Fine-tuned GPT-5 mini via Copilot \u2014 Premium x0",
29403
+ contextWindow: 4e5,
29404
+ maxOutputTokens: 128e3
29405
+ },
29406
+ {
29407
+ id: "goldeneye",
29408
+ name: "Goldeneye",
29409
+ description: "Fine-tuned GPT-5.1-Codex via Copilot (Free x1)",
29410
+ contextWindow: 4e5,
29411
+ maxOutputTokens: 128e3
29315
29412
  }
29316
29413
  ]
29317
29414
  },
@@ -30095,7 +30192,7 @@ function getProviderDefinition(type) {
30095
30192
  return PROVIDER_DEFINITIONS[type];
30096
30193
  }
30097
30194
  function getAllProviders() {
30098
- return Object.values(PROVIDER_DEFINITIONS).filter((p45) => !p45.internal);
30195
+ return Object.values(PROVIDER_DEFINITIONS).filter((p46) => !p46.internal);
30099
30196
  }
30100
30197
  function getRecommendedModel(type) {
30101
30198
  const provider = PROVIDER_DEFINITIONS[type];
@@ -30116,20 +30213,20 @@ function hasLocalProviderConfig(type) {
30116
30213
  return process.env["COCO_PROVIDER"] === "ollama" || !!process.env["OLLAMA_MODEL"] || !!process.env["OLLAMA_BASE_URL"];
30117
30214
  }
30118
30215
  function getConfiguredProviders() {
30119
- return getAllProviders().filter((p45) => {
30120
- if (p45.id === "copilot") {
30216
+ return getAllProviders().filter((p46) => {
30217
+ if (p46.id === "copilot") {
30121
30218
  return !!process.env["GITHUB_TOKEN"] || !!process.env["GH_TOKEN"] || hasCopilotCredentials();
30122
30219
  }
30123
- if (p45.id === "openai") {
30124
- return !!process.env[p45.envVar] || !!process.env["OPENAI_CODEX_TOKEN"] || !!process.env["OPENAI_ACCESS_TOKEN"];
30220
+ if (p46.id === "openai") {
30221
+ return !!process.env[p46.envVar] || !!process.env["OPENAI_CODEX_TOKEN"] || !!process.env["OPENAI_ACCESS_TOKEN"];
30125
30222
  }
30126
- if (p45.id === "lmstudio" || p45.id === "ollama") {
30127
- return hasLocalProviderConfig(p45.id);
30223
+ if (p46.id === "lmstudio" || p46.id === "ollama") {
30224
+ return hasLocalProviderConfig(p46.id);
30128
30225
  }
30129
- if (p45.id === "vertex") {
30226
+ if (p46.id === "vertex") {
30130
30227
  return !!(process.env["VERTEX_API_KEY"] ?? process.env["GOOGLE_API_KEY"] ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]);
30131
30228
  }
30132
- return !!process.env[p45.envVar];
30229
+ return !!process.env[p46.envVar];
30133
30230
  });
30134
30231
  }
30135
30232
  function isProviderConfigured(type) {
@@ -31264,8 +31361,8 @@ ${suggestionsHtml}
31264
31361
  return filePath;
31265
31362
  }
31266
31363
  // ── Private helpers ───────────────────────────────────────────────────────
31267
- htmlEscape(text14) {
31268
- return text14.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
31364
+ htmlEscape(text15) {
31365
+ return text15.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
31269
31366
  }
31270
31367
  markdownIssue(issue) {
31271
31368
  const severity = issue.severity === "critical" ? "\u{1F534}" : issue.severity === "major" ? "\u{1F7E1}" : "\u{1F535}";
@@ -31787,12 +31884,12 @@ Return only JSON: { "score": <number 1-10>, "reasoning": "<brief explanation>" }
31787
31884
  }
31788
31885
  return classifyFeatureHeuristic(feature);
31789
31886
  }
31790
- function extractJsonScore(text14) {
31887
+ function extractJsonScore(text15) {
31791
31888
  try {
31792
- const stripped = text14.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
31889
+ const stripped = text15.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
31793
31890
  return JSON.parse(stripped);
31794
31891
  } catch {
31795
- const match = text14.match(/\{[\s\S]*?\}/);
31892
+ const match = text15.match(/\{[\s\S]*?\}/);
31796
31893
  if (match) {
31797
31894
  try {
31798
31895
  return JSON.parse(match[0]);
@@ -32016,25 +32113,25 @@ Rules:
32016
32113
  }
32017
32114
  }
32018
32115
  async function defaultPromptHandler(q) {
32019
- const p45 = await import('@clack/prompts');
32116
+ const p46 = await import('@clack/prompts');
32020
32117
  if (q.options && q.options.length > 0) {
32021
- const result = await p45.select({
32118
+ const result = await p46.select({
32022
32119
  message: q.question,
32023
32120
  options: [
32024
32121
  ...q.options.map((o) => ({ value: o, label: o })),
32025
32122
  { value: q.assumedAnswer, label: `${q.assumedAnswer} (default)` }
32026
32123
  ]
32027
32124
  });
32028
- if (p45.isCancel(result)) {
32125
+ if (p46.isCancel(result)) {
32029
32126
  return q.assumedAnswer;
32030
32127
  }
32031
32128
  return result;
32032
32129
  } else {
32033
- const result = await p45.text({
32130
+ const result = await p46.text({
32034
32131
  message: q.question,
32035
32132
  placeholder: q.assumedAnswer
32036
32133
  });
32037
- if (p45.isCancel(result) || !result) {
32134
+ if (p46.isCancel(result) || !result) {
32038
32135
  return q.assumedAnswer;
32039
32136
  }
32040
32137
  return result;
@@ -33005,12 +33102,12 @@ function computeGlobalScore(results) {
33005
33102
  const total = results.reduce((sum, r) => sum + r.reviewScore, 0);
33006
33103
  return Math.round(total / results.length);
33007
33104
  }
33008
- function extractJson(text14) {
33105
+ function extractJson(text15) {
33009
33106
  try {
33010
- const stripped = text14.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
33107
+ const stripped = text15.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
33011
33108
  return JSON.parse(stripped);
33012
33109
  } catch {
33013
- const match = text14.match(/\{[\s\S]*\}/);
33110
+ const match = text15.match(/\{[\s\S]*\}/);
33014
33111
  if (match) {
33015
33112
  try {
33016
33113
  return JSON.parse(match[0]);
@@ -33357,7 +33454,7 @@ init_env();
33357
33454
 
33358
33455
  // src/cli/repl/quality-loop.ts
33359
33456
  init_paths();
33360
- var qualityLoopEnabled = true;
33457
+ var qualityLoopEnabled = false;
33361
33458
  var hintShown = false;
33362
33459
  function isQualityLoop() {
33363
33460
  return qualityLoopEnabled;
@@ -33395,7 +33492,7 @@ function looksLikeFeatureRequest(input) {
33395
33492
  return featureKeywords.some((re) => re.test(trimmed));
33396
33493
  }
33397
33494
  function formatQualityLoopHint() {
33398
- return chalk.dim(" tip: ") + chalk.magenta("/quality") + chalk.dim(" enables auto-test & iterate until quality converges");
33495
+ return chalk.dim(" tip: ") + chalk.magenta("/quality on") + chalk.dim(" enables Coco quality mode: auto-test, self-review, and iterate until robust");
33399
33496
  }
33400
33497
  function formatQualityResult(result) {
33401
33498
  const lines = [];
@@ -33439,7 +33536,8 @@ async function loadQualityLoopPreference() {
33439
33536
  }
33440
33537
  } catch {
33441
33538
  }
33442
- return true;
33539
+ qualityLoopEnabled = false;
33540
+ return false;
33443
33541
  }
33444
33542
  async function saveQualityLoopPreference(enabled) {
33445
33543
  try {
@@ -33569,7 +33667,7 @@ async function renderStartupPanel(session, gitCtx, mcpServers = []) {
33569
33667
  if (gitCtx) {
33570
33668
  console.log(` ${formatGitLine(gitCtx)}`);
33571
33669
  }
33572
- const cocoStatus = isQualityLoop() ? chalk.magenta(" \u{1F504} quality mode: ") + chalk.green.bold("on") + chalk.dim(" \u2014 iterates until quality \u2265 85. /quality to disable") : chalk.dim(" \u{1F4A1} /quality on \u2014 enable auto-test & quality iteration");
33670
+ const cocoStatus = isQualityLoop() ? chalk.magenta(" \u{1F504} quality mode: ") + chalk.green.bold("on") + chalk.dim(" \u2014 iterates until quality \u2265 85. /quality to disable") : chalk.dim(" \u{1F4A1} quality mode is Coco's edge for robust code. Enable with /quality on");
33573
33671
  console.log(cocoStatus);
33574
33672
  const skillTotal = session.skillRegistry?.size ?? 0;
33575
33673
  const hasSomething = skillTotal > 0 || mcpServers.length > 0;
@@ -33995,7 +34093,7 @@ async function runOnboardingV2() {
33995
34093
  console.log(chalk.magenta(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
33996
34094
  console.log();
33997
34095
  p26.log.info(
33998
- `Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((p45) => p45.emoji + " " + p45.name).join(", ")}`
34096
+ `Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((p46) => p46.emoji + " " + p46.name).join(", ")}`
33999
34097
  );
34000
34098
  const useExisting = await p26.confirm({
34001
34099
  message: "Use an existing provider?",
@@ -34680,9 +34778,9 @@ async function setupOllamaProvider(port) {
34680
34778
  return setupLocalProvider("ollama", port);
34681
34779
  }
34682
34780
  async function selectExistingProvider(providers) {
34683
- const options = providers.map((p45) => ({
34684
- value: p45.id,
34685
- label: `${p45.emoji} ${p45.name}`,
34781
+ const options = providers.map((p46) => ({
34782
+ value: p46.id,
34783
+ label: `${p46.emoji} ${p46.name}`,
34686
34784
  hint: "Configured"
34687
34785
  }));
34688
34786
  options.push({ value: "__new__", label: "\u2795 Setup new provider", hint: "" });
@@ -35074,7 +35172,7 @@ async function ensureConfiguredV2(config) {
35074
35172
  } catch {
35075
35173
  }
35076
35174
  }
35077
- const preferredProviderDef = providers.find((p45) => p45.id === config.provider.type);
35175
+ const preferredProviderDef = providers.find((p46) => p46.id === config.provider.type);
35078
35176
  const preferredIsLocal = preferredProviderDef?.requiresApiKey === false && preferredProviderDef?.id !== "copilot";
35079
35177
  const preferredHasApiKey = preferredProviderDef ? !!process.env[preferredProviderDef.envVar] : false;
35080
35178
  const preferredHasOpenAIOAuth = preferredProviderDef?.id === "openai" && hasOpenAIOAuthTokens;
@@ -35104,12 +35202,12 @@ async function ensureConfiguredV2(config) {
35104
35202
  preferredUnavailableWasLocal = preferredIsLocal;
35105
35203
  }
35106
35204
  if (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal) {
35107
- const configuredProviders = providers.filter((p45) => {
35108
- if (p45.id === "copilot") return isProviderConfigured();
35109
- if (p45.id === "openai") {
35110
- return hasOpenAIOAuthTokens || !!process.env[p45.envVar];
35205
+ const configuredProviders = providers.filter((p46) => {
35206
+ if (p46.id === "copilot") return isProviderConfigured();
35207
+ if (p46.id === "openai") {
35208
+ return hasOpenAIOAuthTokens || !!process.env[p46.envVar];
35111
35209
  }
35112
- return p45.requiresApiKey === false || !!process.env[p45.envVar];
35210
+ return p46.requiresApiKey === false || !!process.env[p46.envVar];
35113
35211
  });
35114
35212
  for (const prov of configuredProviders) {
35115
35213
  try {
@@ -35182,7 +35280,7 @@ init_auth();
35182
35280
  init_env();
35183
35281
  async function selectProviderInteractively(providers, currentProviderId) {
35184
35282
  return new Promise((resolve4) => {
35185
- let selectedIndex = providers.findIndex((p45) => p45.id === currentProviderId);
35283
+ let selectedIndex = providers.findIndex((p46) => p46.id === currentProviderId);
35186
35284
  if (selectedIndex === -1) selectedIndex = 0;
35187
35285
  let lastTotalLines = 0;
35188
35286
  const clearPrevious = () => {
@@ -35280,12 +35378,12 @@ var providerCommand = {
35280
35378
  `));
35281
35379
  const allProviders2 = getAllProviders();
35282
35380
  const configuredProviders = getConfiguredProviders();
35283
- const providerOptions = allProviders2.map((p45) => ({
35284
- id: p45.id,
35285
- name: p45.name,
35286
- emoji: p45.emoji,
35287
- description: p45.description,
35288
- isConfigured: configuredProviders.some((cp) => cp.id === p45.id)
35381
+ const providerOptions = allProviders2.map((p46) => ({
35382
+ id: p46.id,
35383
+ name: p46.name,
35384
+ emoji: p46.emoji,
35385
+ description: p46.description,
35386
+ isConfigured: configuredProviders.some((cp) => cp.id === p46.id)
35289
35387
  }));
35290
35388
  const selectedProviderId = await selectProviderInteractively(
35291
35389
  providerOptions,
@@ -35300,15 +35398,15 @@ var providerCommand = {
35300
35398
  `));
35301
35399
  return false;
35302
35400
  }
35303
- const newProvider2 = allProviders2.find((p45) => p45.id === selectedProviderId);
35401
+ const newProvider2 = allProviders2.find((p46) => p46.id === selectedProviderId);
35304
35402
  return await switchProvider(newProvider2, session);
35305
35403
  }
35306
35404
  const newProviderId = args[0]?.toLowerCase();
35307
35405
  const allProviders = getAllProviders();
35308
- const newProvider = allProviders.find((p45) => p45.id === newProviderId);
35406
+ const newProvider = allProviders.find((p46) => p46.id === newProviderId);
35309
35407
  if (!newProvider) {
35310
35408
  console.log(chalk.red(`Unknown provider: ${newProviderId}`));
35311
- console.log(chalk.dim(`Available: ${allProviders.map((p45) => p45.id).join(", ")}
35409
+ console.log(chalk.dim(`Available: ${allProviders.map((p46) => p46.id).join(", ")}
35312
35410
  `));
35313
35411
  return false;
35314
35412
  }
@@ -36345,7 +36443,7 @@ async function showTrustStatus(session, trustStore) {
36345
36443
  }
36346
36444
  const level = trustStore.getLevel(projectPath);
36347
36445
  const list = trustStore.list();
36348
- const project = list.find((p45) => p45.path === projectPath);
36446
+ const project = list.find((p46) => p46.path === projectPath);
36349
36447
  p26.log.message("");
36350
36448
  p26.log.message(`\u{1F510} Project Trust Status`);
36351
36449
  p26.log.message(` Path: ${projectPath}`);
@@ -38312,8 +38410,8 @@ var STARTUP_TIMEOUT_MS = 5500;
38312
38410
  var CACHE_DIR = path39__default.join(os4__default.homedir(), ".coco");
38313
38411
  var CACHE_FILE = path39__default.join(CACHE_DIR, "version-check-cache.json");
38314
38412
  function compareVersions(a, b) {
38315
- const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
38316
- const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
38413
+ const partsA = a.replace(/^v/, "").split(".").map((p46) => Number(p46.replace(/-.*$/, "")));
38414
+ const partsB = b.replace(/^v/, "").split(".").map((p46) => Number(p46.replace(/-.*$/, "")));
38317
38415
  for (let i = 0; i < 3; i++) {
38318
38416
  const numA = partsA[i] ?? 0;
38319
38417
  const numB = partsB[i] ?? 0;
@@ -38437,13 +38535,13 @@ async function checkForUpdatesInteractive() {
38437
38535
  ]);
38438
38536
  clearTimeout(startupTimerId);
38439
38537
  if (!updateInfo) return;
38440
- const p45 = await import('@clack/prompts');
38538
+ const p46 = await import('@clack/prompts');
38441
38539
  printUpdateBanner(updateInfo);
38442
- const answer = await p45.confirm({
38540
+ const answer = await p46.confirm({
38443
38541
  message: "Exit now to update?",
38444
38542
  initialValue: true
38445
38543
  });
38446
- if (!p45.isCancel(answer) && answer) {
38544
+ if (!p46.isCancel(answer) && answer) {
38447
38545
  console.log();
38448
38546
  console.log(chalk.dim(` Running: ${updateInfo.updateCommand}`));
38449
38547
  console.log();
@@ -38572,7 +38670,7 @@ function getClipboardCommand() {
38572
38670
  }
38573
38671
  return null;
38574
38672
  }
38575
- async function copyToClipboard(text14) {
38673
+ async function copyToClipboard(text15) {
38576
38674
  const clipboardCmd = getClipboardCommand();
38577
38675
  if (!clipboardCmd) {
38578
38676
  return false;
@@ -38593,7 +38691,7 @@ async function copyToClipboard(text14) {
38593
38691
  });
38594
38692
  xselProc.on("error", () => resolve4(false));
38595
38693
  xselProc.on("close", (code) => resolve4(code === 0));
38596
- xselProc.stdin.write(text14);
38694
+ xselProc.stdin.write(text15);
38597
38695
  xselProc.stdin.end();
38598
38696
  } catch {
38599
38697
  resolve4(false);
@@ -38609,7 +38707,7 @@ async function copyToClipboard(text14) {
38609
38707
  });
38610
38708
  proc.stdin.on("error", () => {
38611
38709
  });
38612
- proc.stdin.write(text14);
38710
+ proc.stdin.write(text15);
38613
38711
  proc.stdin.end();
38614
38712
  } catch {
38615
38713
  resolve4(false);
@@ -39369,7 +39467,7 @@ async function shouldShowPermissionSuggestion(projectPath = process.cwd()) {
39369
39467
  }
39370
39468
  async function applyRecommendedPermissions(projectPath = process.cwd()) {
39371
39469
  for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
39372
- await saveTrustedTool(tool, null, true);
39470
+ await saveTrustedTool(tool, projectPath, false);
39373
39471
  }
39374
39472
  await saveProjectPermissionPreference("recommendedAllowlistAppliedProjects", projectPath, true);
39375
39473
  await saveProjectPermissionPreference(
@@ -39382,7 +39480,7 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
39382
39480
  console.log();
39383
39481
  console.log(chalk.magenta.bold(" \u{1F4CB} Recommended Permissions"));
39384
39482
  console.log();
39385
- console.log(chalk.dim(" Coco has a curated set of tool permissions for developers:"));
39483
+ console.log(chalk.dim(" Coco has a curated set of tool permissions for this project:"));
39386
39484
  console.log(chalk.dim(" \u2022 Allow: file read/write, search, git staging, build, tests..."));
39387
39485
  console.log(
39388
39486
  chalk.dim(" \u2022 Ask each time: git commit, curl, rm, git pull, docker exec, cloud...")
@@ -39391,12 +39489,17 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
39391
39489
  console.log();
39392
39490
  console.log(chalk.dim(" Stored in ~/.coco/trusted-tools.json \u2014 edit manually or let"));
39393
39491
  console.log(chalk.dim(" Coco manage it when you approve actions from the prompt."));
39492
+ console.log(chalk.dim(" Note: applying here affects only the current project."));
39394
39493
  console.log();
39395
39494
  const action = await p26.select({
39396
39495
  message: "Apply recommended permissions?",
39397
39496
  options: [
39398
39497
  { value: "view", label: "View details", hint: "See the full list before deciding" },
39399
- { value: "apply", label: "Apply", hint: "Apply recommended permissions now" },
39498
+ {
39499
+ value: "apply",
39500
+ label: "Apply",
39501
+ hint: "Apply recommended permissions for this project"
39502
+ },
39400
39503
  { value: "later", label: "Later", hint: "Remind me next time" },
39401
39504
  { value: "dismiss", label: "No thanks", hint: "Don't show again" }
39402
39505
  ]
@@ -40208,9 +40311,9 @@ var UserCancelledError = class extends Error {
40208
40311
  var SPEC_AGENT_SYSTEM = `You are a senior technical product manager specialising in rapid MVP delivery.
40209
40312
  Your job is to help a developer plan a software project efficiently and honestly.
40210
40313
  Always respond with valid JSON only \u2014 no markdown fences, no prose outside JSON.`;
40211
- function extractJson2(text14) {
40212
- const match = text14.match(/```(?:json)?\s*([\s\S]*?)```/) ?? text14.match(/(\{[\s\S]*\})/);
40213
- return match ? (match[1] ?? text14).trim() : text14.trim();
40314
+ function extractJson2(text15) {
40315
+ const match = text15.match(/```(?:json)?\s*([\s\S]*?)```/) ?? text15.match(/(\{[\s\S]*\})/);
40316
+ return match ? (match[1] ?? text15).trim() : text15.trim();
40214
40317
  }
40215
40318
  function validateBacklogSpec(raw) {
40216
40319
  if (!raw.sprints || raw.sprints.length === 0) {
@@ -43851,15 +43954,15 @@ ${message}
43851
43954
  let stdoutBuffer = "";
43852
43955
  let stderrBuffer = "";
43853
43956
  subprocess.stdout?.on("data", (chunk) => {
43854
- const text14 = chunk.toString();
43855
- stdoutBuffer += text14;
43856
- process.stdout.write(text14);
43957
+ const text15 = chunk.toString();
43958
+ stdoutBuffer += text15;
43959
+ process.stdout.write(text15);
43857
43960
  heartbeat.activity();
43858
43961
  });
43859
43962
  subprocess.stderr?.on("data", (chunk) => {
43860
- const text14 = chunk.toString();
43861
- stderrBuffer += text14;
43862
- process.stderr.write(text14);
43963
+ const text15 = chunk.toString();
43964
+ stderrBuffer += text15;
43965
+ process.stderr.write(text15);
43863
43966
  heartbeat.activity();
43864
43967
  });
43865
43968
  const result = await subprocess;
@@ -43976,15 +44079,15 @@ ${message}
43976
44079
  let stdoutBuffer = "";
43977
44080
  let stderrBuffer = "";
43978
44081
  subprocess.stdout?.on("data", (chunk) => {
43979
- const text14 = chunk.toString();
43980
- stdoutBuffer += text14;
43981
- process.stdout.write(text14);
44082
+ const text15 = chunk.toString();
44083
+ stdoutBuffer += text15;
44084
+ process.stdout.write(text15);
43982
44085
  heartbeat.activity();
43983
44086
  });
43984
44087
  subprocess.stderr?.on("data", (chunk) => {
43985
- const text14 = chunk.toString();
43986
- stderrBuffer += text14;
43987
- process.stderr.write(text14);
44088
+ const text15 = chunk.toString();
44089
+ stderrBuffer += text15;
44090
+ process.stderr.write(text15);
43988
44091
  heartbeat.activity();
43989
44092
  });
43990
44093
  const result = await subprocess;
@@ -44078,15 +44181,15 @@ ${message}
44078
44181
  let stdoutBuffer = "";
44079
44182
  let stderrBuffer = "";
44080
44183
  subprocess.stdout?.on("data", (chunk) => {
44081
- const text14 = chunk.toString();
44082
- stdoutBuffer += text14;
44083
- process.stdout.write(text14);
44184
+ const text15 = chunk.toString();
44185
+ stdoutBuffer += text15;
44186
+ process.stdout.write(text15);
44084
44187
  heartbeat.activity();
44085
44188
  });
44086
44189
  subprocess.stderr?.on("data", (chunk) => {
44087
- const text14 = chunk.toString();
44088
- stderrBuffer += text14;
44089
- process.stderr.write(text14);
44190
+ const text15 = chunk.toString();
44191
+ stderrBuffer += text15;
44192
+ process.stderr.write(text15);
44090
44193
  heartbeat.activity();
44091
44194
  });
44092
44195
  const result = await subprocess;
@@ -44181,15 +44284,15 @@ ${message}
44181
44284
  let stdoutBuffer = "";
44182
44285
  let stderrBuffer = "";
44183
44286
  subprocess.stdout?.on("data", (chunk) => {
44184
- const text14 = chunk.toString();
44185
- stdoutBuffer += text14;
44186
- process.stdout.write(text14);
44287
+ const text15 = chunk.toString();
44288
+ stdoutBuffer += text15;
44289
+ process.stdout.write(text15);
44187
44290
  heartbeat.activity();
44188
44291
  });
44189
44292
  subprocess.stderr?.on("data", (chunk) => {
44190
- const text14 = chunk.toString();
44191
- stderrBuffer += text14;
44192
- process.stderr.write(text14);
44293
+ const text15 = chunk.toString();
44294
+ stderrBuffer += text15;
44295
+ process.stderr.write(text15);
44193
44296
  heartbeat.activity();
44194
44297
  });
44195
44298
  const result = await subprocess;
@@ -44285,15 +44388,15 @@ ${message}
44285
44388
  let stdoutBuffer = "";
44286
44389
  let stderrBuffer = "";
44287
44390
  subprocess.stdout?.on("data", (chunk) => {
44288
- const text14 = chunk.toString();
44289
- stdoutBuffer += text14;
44290
- process.stdout.write(text14);
44391
+ const text15 = chunk.toString();
44392
+ stdoutBuffer += text15;
44393
+ process.stdout.write(text15);
44291
44394
  heartbeat.activity();
44292
44395
  });
44293
44396
  subprocess.stderr?.on("data", (chunk) => {
44294
- const text14 = chunk.toString();
44295
- stderrBuffer += text14;
44296
- process.stderr.write(text14);
44397
+ const text15 = chunk.toString();
44398
+ stderrBuffer += text15;
44399
+ process.stderr.write(text15);
44297
44400
  heartbeat.activity();
44298
44401
  });
44299
44402
  const result = await subprocess;
@@ -44372,15 +44475,15 @@ ${message}
44372
44475
  let stdoutBuffer = "";
44373
44476
  let stderrBuffer = "";
44374
44477
  subprocess.stdout?.on("data", (chunk) => {
44375
- const text14 = chunk.toString();
44376
- stdoutBuffer += text14;
44377
- process.stdout.write(text14);
44478
+ const text15 = chunk.toString();
44479
+ stdoutBuffer += text15;
44480
+ process.stdout.write(text15);
44378
44481
  heartbeat.activity();
44379
44482
  });
44380
44483
  subprocess.stderr?.on("data", (chunk) => {
44381
- const text14 = chunk.toString();
44382
- stderrBuffer += text14;
44383
- process.stderr.write(text14);
44484
+ const text15 = chunk.toString();
44485
+ stderrBuffer += text15;
44486
+ process.stderr.write(text15);
44384
44487
  heartbeat.activity();
44385
44488
  });
44386
44489
  const result = await subprocess;
@@ -44871,16 +44974,16 @@ function htmlToMarkdown(html) {
44871
44974
  const prefix = "#".repeat(i);
44872
44975
  const regex = new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, "gi");
44873
44976
  md = md.replace(regex, (_, content) => {
44874
- const text14 = content.replace(/<[^>]*>/g, "").trim();
44875
- return text14 ? `
44977
+ const text15 = content.replace(/<[^>]*>/g, "").trim();
44978
+ return text15 ? `
44876
44979
 
44877
- ${prefix} ${text14}
44980
+ ${prefix} ${text15}
44878
44981
 
44879
44982
  ` : "";
44880
44983
  });
44881
44984
  }
44882
- md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text14) => {
44883
- const cleanText = text14.replace(/<[^>]*>/g, "").trim();
44985
+ md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text15) => {
44986
+ const cleanText = text15.replace(/<[^>]*>/g, "").trim();
44884
44987
  if (!cleanText) return "";
44885
44988
  if (href.startsWith("#") || href.startsWith("javascript:")) return cleanText;
44886
44989
  return `[${cleanText}](${href})`;
@@ -44907,8 +45010,8 @@ ${decoded.trim()}
44907
45010
  });
44908
45011
  md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, items) => {
44909
45012
  return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
44910
- const text14 = item.replace(/<[^>]*>/g, "").trim();
44911
- return text14 ? `- ${text14}
45013
+ const text15 = item.replace(/<[^>]*>/g, "").trim();
45014
+ return text15 ? `- ${text15}
44912
45015
  ` : "";
44913
45016
  }) + "\n";
44914
45017
  });
@@ -44916,29 +45019,29 @@ ${decoded.trim()}
44916
45019
  let counter = 0;
44917
45020
  return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
44918
45021
  counter++;
44919
- const text14 = item.replace(/<[^>]*>/g, "").trim();
44920
- return text14 ? `${counter}. ${text14}
45022
+ const text15 = item.replace(/<[^>]*>/g, "").trim();
45023
+ return text15 ? `${counter}. ${text15}
44921
45024
  ` : "";
44922
45025
  }) + "\n";
44923
45026
  });
44924
45027
  md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
44925
- const text14 = content.replace(/<[^>]*>/g, "").trim();
44926
- return text14 ? "\n" + text14.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
45028
+ const text15 = content.replace(/<[^>]*>/g, "").trim();
45029
+ return text15 ? "\n" + text15.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
44927
45030
  });
44928
45031
  md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => {
44929
- const text14 = content.replace(/<[^>]*>/g, "").trim();
44930
- return text14 ? `
45032
+ const text15 = content.replace(/<[^>]*>/g, "").trim();
45033
+ return text15 ? `
44931
45034
 
44932
- ${text14}
45035
+ ${text15}
44933
45036
 
44934
45037
  ` : "";
44935
45038
  });
44936
45039
  md = md.replace(/<br\s*\/?>/gi, "\n");
44937
45040
  md = md.replace(
44938
45041
  /<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,
44939
- (_, text14) => `**${text14.trim()}**`
45042
+ (_, text15) => `**${text15.trim()}**`
44940
45043
  );
44941
- md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text14) => `*${text14.trim()}*`);
45044
+ md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text15) => `*${text15.trim()}*`);
44942
45045
  md = md.replace(/<hr\s*\/?>/gi, "\n---\n");
44943
45046
  md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
44944
45047
  const rows = [];
@@ -46068,10 +46171,10 @@ function chunkContent(content, chunkSize) {
46068
46171
  const chunks = [];
46069
46172
  for (let i = 0; i < lines.length; i += chunkSize) {
46070
46173
  const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
46071
- const text14 = chunkLines.join("\n").trim();
46072
- if (text14.length > 10) {
46174
+ const text15 = chunkLines.join("\n").trim();
46175
+ if (text15.length > 10) {
46073
46176
  chunks.push({
46074
- text: text14,
46177
+ text: text15,
46075
46178
  startLine: i + 1,
46076
46179
  endLine: Math.min(i + chunkSize, lines.length)
46077
46180
  });
@@ -46079,8 +46182,8 @@ function chunkContent(content, chunkSize) {
46079
46182
  }
46080
46183
  return chunks;
46081
46184
  }
46082
- function simpleEmbedding(text14) {
46083
- const words = text14.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
46185
+ function simpleEmbedding(text15) {
46186
+ const words = text15.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
46084
46187
  const freq = /* @__PURE__ */ new Map();
46085
46188
  for (const word of words) {
46086
46189
  freq.set(word, (freq.get(word) ?? 0) + 1);
@@ -46106,7 +46209,7 @@ function simpleEmbedding(text14) {
46106
46209
  }
46107
46210
  var embedFn = null;
46108
46211
  var usingFallbackEmbedding = false;
46109
- async function getEmbedding(text14) {
46212
+ async function getEmbedding(text15) {
46110
46213
  if (!embedFn) {
46111
46214
  try {
46112
46215
  const transformers = await import('@xenova/transformers');
@@ -46123,7 +46226,7 @@ async function getEmbedding(text14) {
46123
46226
  usingFallbackEmbedding = true;
46124
46227
  }
46125
46228
  }
46126
- return embedFn(text14);
46229
+ return embedFn(text15);
46127
46230
  }
46128
46231
  async function loadIndex2(indexDir) {
46129
46232
  try {
@@ -46676,23 +46779,23 @@ Examples:
46676
46779
  const pdfData = await pdfParse.default(dataBuffer, {
46677
46780
  max: maxPages
46678
46781
  });
46679
- let text14 = pdfData.text;
46782
+ let text15 = pdfData.text;
46680
46783
  let truncated = false;
46681
46784
  const totalPages = pdfData.numpages;
46682
46785
  if (pages) {
46683
46786
  const range = parsePageRange(pages, totalPages);
46684
- const pageTexts = text14.split(/\f/);
46787
+ const pageTexts = text15.split(/\f/);
46685
46788
  if (pageTexts.length > 1) {
46686
46789
  const selectedPages = pageTexts.slice(range.start - 1, range.end);
46687
- text14 = selectedPages.join("\n\n--- Page Break ---\n\n");
46790
+ text15 = selectedPages.join("\n\n--- Page Break ---\n\n");
46688
46791
  }
46689
46792
  }
46690
- if (text14.length > 5e5) {
46691
- text14 = text14.slice(0, 5e5);
46793
+ if (text15.length > 5e5) {
46794
+ text15 = text15.slice(0, 5e5);
46692
46795
  truncated = true;
46693
46796
  }
46694
46797
  return {
46695
- text: text14,
46798
+ text: text15,
46696
46799
  pages: totalPages,
46697
46800
  metadata: {
46698
46801
  title: pdfData.info?.Title,
@@ -47706,7 +47809,14 @@ var SuggestImprovementsSchema = z.object({
47706
47809
  context: z.string().optional().describe("Additional context about the code")
47707
47810
  });
47708
47811
  async function analyzeAndSuggest(filePath, _context) {
47709
- const content = await fs46.readFile(filePath, "utf-8");
47812
+ let rawContent = await fs46.readFile(filePath, "utf-8");
47813
+ if (typeof rawContent !== "string") {
47814
+ const defaultReadFile = fs46.default?.readFile;
47815
+ if (typeof defaultReadFile === "function") {
47816
+ rawContent = await defaultReadFile(filePath, "utf-8");
47817
+ }
47818
+ }
47819
+ const content = typeof rawContent === "string" ? rawContent : String(rawContent ?? "");
47710
47820
  const lines = content.split("\n");
47711
47821
  const suggestions = [];
47712
47822
  for (let i = 0; i < lines.length; i++) {
@@ -48071,11 +48181,11 @@ var getLearnedPatternsTool = defineTool({
48071
48181
  const patterns = store.getFrequentPatterns(typedInput.limit);
48072
48182
  return {
48073
48183
  totalPatterns: patterns.length,
48074
- patterns: patterns.map((p45) => ({
48075
- pattern: p45.pattern,
48076
- preference: p45.userPreference,
48077
- frequency: p45.frequency,
48078
- lastUsed: new Date(p45.lastUsed).toISOString()
48184
+ patterns: patterns.map((p46) => ({
48185
+ pattern: p46.pattern,
48186
+ preference: p46.userPreference,
48187
+ frequency: p46.frequency,
48188
+ lastUsed: new Date(p46.lastUsed).toISOString()
48079
48189
  }))
48080
48190
  };
48081
48191
  }
@@ -50119,24 +50229,24 @@ function formatHtmlLine(line) {
50119
50229
  }
50120
50230
  return null;
50121
50231
  }
50122
- function formatInlineMarkdown(text14) {
50123
- text14 = text14.replace(/\*\*\*(.+?)\*\*\*/g, (_, content) => chalk.bold.italic(content));
50124
- text14 = text14.replace(/\*\*(.+?)\*\*/g, (_, content) => chalk.bold(content));
50125
- text14 = text14.replace(/\*([^*]+)\*/g, (_, content) => chalk.italic(content));
50126
- text14 = text14.replace(/_([^_]+)_/g, (_, content) => chalk.italic(content));
50127
- text14 = text14.replace(/`([^`]+)`/g, (_, content) => chalk.cyan(content));
50128
- text14 = text14.replace(/~~(.+?)~~/g, (_, content) => chalk.strikethrough(content));
50129
- text14 = text14.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, linkText) => chalk.blue.underline(linkText));
50130
- return text14;
50131
- }
50132
- function wrapText(text14, maxWidth) {
50133
- if (maxWidth <= 0) return [text14];
50134
- const plainText = stripAnsi(text14);
50232
+ function formatInlineMarkdown(text15) {
50233
+ text15 = text15.replace(/\*\*\*(.+?)\*\*\*/g, (_, content) => chalk.bold.italic(content));
50234
+ text15 = text15.replace(/\*\*(.+?)\*\*/g, (_, content) => chalk.bold(content));
50235
+ text15 = text15.replace(/\*([^*]+)\*/g, (_, content) => chalk.italic(content));
50236
+ text15 = text15.replace(/_([^_]+)_/g, (_, content) => chalk.italic(content));
50237
+ text15 = text15.replace(/`([^`]+)`/g, (_, content) => chalk.cyan(content));
50238
+ text15 = text15.replace(/~~(.+?)~~/g, (_, content) => chalk.strikethrough(content));
50239
+ text15 = text15.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, linkText) => chalk.blue.underline(linkText));
50240
+ return text15;
50241
+ }
50242
+ function wrapText(text15, maxWidth) {
50243
+ if (maxWidth <= 0) return [text15];
50244
+ const plainText = stripAnsi(text15);
50135
50245
  if (plainText.length <= maxWidth) {
50136
- return [text14];
50246
+ return [text15];
50137
50247
  }
50138
50248
  const lines = [];
50139
- let remaining = text14;
50249
+ let remaining = text15;
50140
50250
  while (true) {
50141
50251
  const plain = stripAnsi(remaining);
50142
50252
  if (plain.length <= maxWidth) break;
@@ -50174,7 +50284,7 @@ function wrapText(text14, maxWidth) {
50174
50284
  if (remaining) {
50175
50285
  lines.push(remaining);
50176
50286
  }
50177
- return lines.length > 0 ? lines : [text14];
50287
+ return lines.length > 0 ? lines : [text15];
50178
50288
  }
50179
50289
  function stripAnsi(str) {
50180
50290
  return str.replace(/\x1b\[[0-9;]*m/g, "");
@@ -50326,9 +50436,9 @@ function printEditDiff(oldStr, newStr) {
50326
50436
  if (lines.length === 0) return;
50327
50437
  const truncate4 = (s) => s.length > termWidth - 2 ? s.slice(0, termWidth - 3) + "\u2026" : s;
50328
50438
  for (const l of lines) {
50329
- const text14 = `+ ${truncate4(l)}`;
50330
- const pad = Math.max(0, termWidth - stripAnsi(text14).length + 2);
50331
- console.log(" " + diffBgAdd(text14 + " ".repeat(pad)));
50439
+ const text15 = `+ ${truncate4(l)}`;
50440
+ const pad = Math.max(0, termWidth - stripAnsi(text15).length + 2);
50441
+ console.log(" " + diffBgAdd(text15 + " ".repeat(pad)));
50332
50442
  }
50333
50443
  return;
50334
50444
  }
@@ -50356,9 +50466,9 @@ function printEditDiff(oldStr, newStr) {
50356
50466
  }
50357
50467
  if (diffLineList.length === 0) return;
50358
50468
  const pairs = pairAdjacentDiffLines(diffLineList);
50359
- const pairedDeletes = new Set(pairs.map((p45) => p45.deleteIdx));
50360
- const pairedAdds = new Set(pairs.map((p45) => p45.addIdx));
50361
- const pairByAdd = new Map(pairs.map((p45) => [p45.addIdx, p45.deleteIdx]));
50469
+ const pairedDeletes = new Set(pairs.map((p46) => p46.deleteIdx));
50470
+ const pairedAdds = new Set(pairs.map((p46) => p46.addIdx));
50471
+ const pairByAdd = new Map(pairs.map((p46) => [p46.addIdx, p46.deleteIdx]));
50362
50472
  const wordHighlights = /* @__PURE__ */ new Map();
50363
50473
  for (const pair of pairs) {
50364
50474
  const del = diffLineList[pair.deleteIdx];
@@ -50784,10 +50894,10 @@ function findNextWordBoundary(line, pos) {
50784
50894
  while (i < line.length && line[i] === " ") i++;
50785
50895
  return i;
50786
50896
  }
50787
- function countVisualRows(text14, startCol, termCols) {
50897
+ function countVisualRows(text15, startCol, termCols) {
50788
50898
  let rows = 1;
50789
50899
  let col = startCol;
50790
- for (const char of text14) {
50900
+ for (const char of text15) {
50791
50901
  if (char === "\n") {
50792
50902
  if (col > 0) rows++;
50793
50903
  col = 0;
@@ -50801,11 +50911,11 @@ function countVisualRows(text14, startCol, termCols) {
50801
50911
  }
50802
50912
  return rows;
50803
50913
  }
50804
- function getCursorVisualPos(text14, cursorPos, promptLen, termCols) {
50914
+ function getCursorVisualPos(text15, cursorPos, promptLen, termCols) {
50805
50915
  let row = 0;
50806
50916
  let col = promptLen;
50807
50917
  for (let i = 0; i < cursorPos; i++) {
50808
- if (text14[i] === "\n") {
50918
+ if (text15[i] === "\n") {
50809
50919
  if (col > 0) row++;
50810
50920
  col = 0;
50811
50921
  } else {
@@ -50818,14 +50928,14 @@ function getCursorVisualPos(text14, cursorPos, promptLen, termCols) {
50818
50928
  }
50819
50929
  return { row, col };
50820
50930
  }
50821
- function computeWordWrap(text14, startCol, termCols) {
50931
+ function computeWordWrap(text15, startCol, termCols) {
50822
50932
  const passthrough = {
50823
- display: text14,
50824
- toDisplayPos: (p45) => p45,
50825
- toOrigPos: (p45) => p45
50933
+ display: text15,
50934
+ toDisplayPos: (p46) => p46,
50935
+ toOrigPos: (p46) => p46
50826
50936
  };
50827
- if (!text14 || termCols <= 1) return passthrough;
50828
- const origToDisp = new Int32Array(text14.length + 1);
50937
+ if (!text15 || termCols <= 1) return passthrough;
50938
+ const origToDisp = new Int32Array(text15.length + 1);
50829
50939
  const dispToOrig = [];
50830
50940
  let display = "";
50831
50941
  let col = startCol;
@@ -50841,15 +50951,15 @@ function computeWordWrap(text14, startCol, termCols) {
50841
50951
  col = 0;
50842
50952
  }
50843
50953
  let i = 0;
50844
- while (i < text14.length) {
50845
- const ch = text14[i];
50954
+ while (i < text15.length) {
50955
+ const ch = text15[i];
50846
50956
  if (ch === "\n") {
50847
50957
  emitChar("\n", i++);
50848
50958
  continue;
50849
50959
  }
50850
50960
  if (ch !== " ") {
50851
50961
  let wordEnd = i;
50852
- while (wordEnd < text14.length && text14[wordEnd] !== " " && text14[wordEnd] !== "\n") {
50962
+ while (wordEnd < text15.length && text15[wordEnd] !== " " && text15[wordEnd] !== "\n") {
50853
50963
  wordEnd++;
50854
50964
  }
50855
50965
  const wordLen = wordEnd - i;
@@ -50857,7 +50967,7 @@ function computeWordWrap(text14, startCol, termCols) {
50857
50967
  injectNewline();
50858
50968
  }
50859
50969
  for (let k = i; k < wordEnd; k++) {
50860
- emitChar(text14[k], k);
50970
+ emitChar(text15[k], k);
50861
50971
  if (col >= termCols && k + 1 < wordEnd) {
50862
50972
  injectNewline();
50863
50973
  }
@@ -50869,7 +50979,7 @@ function computeWordWrap(text14, startCol, termCols) {
50869
50979
  col = 0;
50870
50980
  } else {
50871
50981
  let nextWordEnd = i;
50872
- while (nextWordEnd < text14.length && text14[nextWordEnd] !== " " && text14[nextWordEnd] !== "\n") {
50982
+ while (nextWordEnd < text15.length && text15[nextWordEnd] !== " " && text15[nextWordEnd] !== "\n") {
50873
50983
  nextWordEnd++;
50874
50984
  }
50875
50985
  const nextWordLen = nextWordEnd - i;
@@ -50879,10 +50989,10 @@ function computeWordWrap(text14, startCol, termCols) {
50879
50989
  }
50880
50990
  }
50881
50991
  }
50882
- origToDisp[text14.length] = display.length;
50992
+ origToDisp[text15.length] = display.length;
50883
50993
  return {
50884
50994
  display,
50885
- toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text14.length)] ?? display.length,
50995
+ toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text15.length)] ?? display.length,
50886
50996
  toOrigPos: (displayPos) => {
50887
50997
  const dp = Math.max(0, Math.min(displayPos, dispToOrig.length - 1));
50888
50998
  for (let d = dp; d >= 0; d--) {
@@ -51015,11 +51125,11 @@ function createInputHandler(_session) {
51015
51125
  const item = visibleItems[itemIndex];
51016
51126
  const actualIndex = startIndex + itemIndex;
51017
51127
  const isSelected = actualIndex === selectedCompletion;
51018
- const text14 = ` ${item.cmd}`.padEnd(ITEM_WIDTH);
51128
+ const text15 = ` ${item.cmd}`.padEnd(ITEM_WIDTH);
51019
51129
  if (isSelected) {
51020
- output += chalk.bgBlue.white(text14);
51130
+ output += chalk.bgBlue.white(text15);
51021
51131
  } else {
51022
- output += chalk.cyan(text14);
51132
+ output += chalk.cyan(text15);
51023
51133
  }
51024
51134
  }
51025
51135
  }
@@ -51071,8 +51181,8 @@ function createInputHandler(_session) {
51071
51181
  process.stdout.write("\r" + ansiEscapes.eraseDown);
51072
51182
  lastMenuLines = 0;
51073
51183
  }
51074
- function insertTextAtCursor(text14) {
51075
- const cleaned = text14.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
51184
+ function insertTextAtCursor(text15) {
51185
+ const cleaned = text15.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
51076
51186
  const printable = cleaned.replace(/[^\n\x20-\x7E\u00A0-\uFFFF]/g, "");
51077
51187
  if (printable.length === 0) return;
51078
51188
  currentLine = currentLine.slice(0, cursorPos) + printable + currentLine.slice(cursorPos);
@@ -51975,10 +52085,10 @@ function formatWriteFilePreview(toolCall, maxLines = 10) {
51975
52085
  const footer = truncated ? chalk.dim(` \u2514\u2500 ... ${lines.length - maxLines} more lines`) : "";
51976
52086
  return formatted + (footer ? "\n" + footer : "");
51977
52087
  }
51978
- function wrapCommandText(text14, maxWidth = 70, indent = " ") {
51979
- if (text14.length <= maxWidth) return text14;
52088
+ function wrapCommandText(text15, maxWidth = 70, indent = " ") {
52089
+ if (text15.length <= maxWidth) return text15;
51980
52090
  const lines = [];
51981
- let remaining = text14;
52091
+ let remaining = text15;
51982
52092
  while (remaining.length > maxWidth) {
51983
52093
  let breakAt = maxWidth;
51984
52094
  const spaceIdx = remaining.lastIndexOf(" ", maxWidth);
@@ -52081,16 +52191,16 @@ function formatToolCallForConfirmation(toolCall, metadata) {
52081
52191
  const reason = input.reason ? String(input.reason) : void 0;
52082
52192
  const actionLabel = action === "allow" ? chalk.green.bold("ALLOW") : chalk.red.bold(action.toUpperCase());
52083
52193
  const scopeLabel = scope === "global" ? chalk.blue("Global (all projects)") : chalk.magenta("Project (current only)");
52084
- const patternList = patterns.map((p45) => chalk.cyan(p45)).join(", ");
52194
+ const patternList = patterns.map((p46) => chalk.cyan(p46)).join(", ");
52085
52195
  const lines = [`${actionLabel}: ${patternList}`];
52086
52196
  lines.push(`${chalk.dim(" Scope:")} ${scopeLabel}`);
52087
52197
  if (reason) {
52088
52198
  lines.push(`${chalk.dim(" Reason:")} ${reason}`);
52089
52199
  }
52090
- for (const p45 of patterns) {
52091
- lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(p45)}`);
52200
+ for (const p46 of patterns) {
52201
+ lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(p46)}`);
52092
52202
  lines.push(
52093
- `${chalk.dim(" Effect:")} ${getEffectDescription(action, p45, scope)}`
52203
+ `${chalk.dim(" Effect:")} ${getEffectDescription(action, p46, scope)}`
52094
52204
  );
52095
52205
  }
52096
52206
  description = lines.join("\n ");
@@ -52331,6 +52441,46 @@ async function confirmToolExecution(toolCall) {
52331
52441
  process.stdin.on("data", onData);
52332
52442
  });
52333
52443
  }
52444
+ async function confirmToolExecutionFallback(toolCall) {
52445
+ const { description } = formatToolCallForConfirmation(toolCall);
52446
+ const isBashExec = toolCall.name === "bash_exec";
52447
+ console.log();
52448
+ console.log(chalk.yellow(" \u26A0 Interactive tool selector unavailable. Using safe fallback."));
52449
+ const options = [
52450
+ { value: "yes", label: "yes", hint: "Allow once" },
52451
+ { value: "no", label: "no", hint: "Skip this action" },
52452
+ { value: "trust_project", label: "trust (project)", hint: "Always allow in this project" },
52453
+ { value: "trust_global", label: "trust (global)", hint: "Always allow everywhere" }
52454
+ ];
52455
+ if (isBashExec) {
52456
+ options.splice(2, 0, { value: "edit", label: "edit command", hint: "Modify before running" });
52457
+ }
52458
+ const choice = await p26.select({
52459
+ message: `Confirm tool action:
52460
+ ${description}`,
52461
+ options
52462
+ });
52463
+ if (p26.isCancel(choice)) return "abort";
52464
+ if (choice === "edit") {
52465
+ const currentCommand = String(toolCall.input.command ?? "");
52466
+ const edited = await p26.text({
52467
+ message: "Edit command:",
52468
+ placeholder: currentCommand,
52469
+ initialValue: currentCommand,
52470
+ validate: (value) => !value?.trim() ? "Command is required" : void 0
52471
+ });
52472
+ if (p26.isCancel(edited)) return "abort";
52473
+ return { type: "edit", newCommand: edited.trim() };
52474
+ }
52475
+ return choice;
52476
+ }
52477
+ async function confirmToolExecutionWithFallback(toolCall) {
52478
+ try {
52479
+ return await confirmToolExecution(toolCall);
52480
+ } catch {
52481
+ return await confirmToolExecutionFallback(toolCall);
52482
+ }
52483
+ }
52334
52484
 
52335
52485
  // src/cli/repl/parallel-executor.ts
52336
52486
  init_error_resilience();
@@ -53060,14 +53210,15 @@ ${tail}`;
53060
53210
  options.onBeforeConfirmation?.();
53061
53211
  let confirmResult;
53062
53212
  try {
53063
- confirmResult = await confirmToolExecution(toolCall);
53213
+ confirmResult = await confirmToolExecutionWithFallback(toolCall);
53064
53214
  } catch (confirmError) {
53065
53215
  options.onAfterConfirmation?.();
53066
- declinedTools.set(
53067
- toolCall.id,
53216
+ declinedTools.set(toolCall.id, "Confirmation failed");
53217
+ options.onToolSkipped?.(
53218
+ toolCall,
53068
53219
  `Confirmation failed: ${confirmError instanceof Error ? confirmError.message : String(confirmError)}`
53069
53220
  );
53070
- options.onToolSkipped?.(toolCall, "Confirmation error");
53221
+ turnAborted = true;
53071
53222
  continue;
53072
53223
  }
53073
53224
  options.onAfterConfirmation?.();
@@ -53137,29 +53288,29 @@ ${tail}`;
53137
53288
  const patterns = executed.input.patterns;
53138
53289
  const scope = executed.input.scope || "project";
53139
53290
  if (Array.isArray(patterns)) {
53140
- for (const p45 of patterns) {
53291
+ for (const p46 of patterns) {
53141
53292
  if (action === "allow") {
53142
- session.trustedTools.add(p45);
53293
+ session.trustedTools.add(p46);
53143
53294
  if (scope === "global") {
53144
- saveTrustedTool(p45, null, true).catch(() => {
53295
+ saveTrustedTool(p46, null, true).catch(() => {
53145
53296
  });
53146
53297
  } else {
53147
- saveTrustedTool(p45, session.projectPath, false).catch(() => {
53298
+ saveTrustedTool(p46, session.projectPath, false).catch(() => {
53148
53299
  });
53149
53300
  }
53150
- removeDeniedTool(p45, session.projectPath).catch(() => {
53301
+ removeDeniedTool(p46, session.projectPath).catch(() => {
53151
53302
  });
53152
53303
  } else if (action === "deny") {
53153
- session.trustedTools.delete(p45);
53304
+ session.trustedTools.delete(p46);
53154
53305
  if (scope === "global") {
53155
- removeTrustedTool(p45, session.projectPath, true).catch(() => {
53306
+ removeTrustedTool(p46, session.projectPath, true).catch(() => {
53156
53307
  });
53157
53308
  } else {
53158
- saveDeniedTool(p45, session.projectPath).catch(() => {
53309
+ saveDeniedTool(p46, session.projectPath).catch(() => {
53159
53310
  });
53160
53311
  }
53161
53312
  } else {
53162
- session.trustedTools.delete(p45);
53313
+ session.trustedTools.delete(p46);
53163
53314
  }
53164
53315
  }
53165
53316
  }
@@ -54207,14 +54358,14 @@ async function startRepl(options = {}) {
54207
54358
  imageCount++;
54208
54359
  }
54209
54360
  }
54210
- const text14 = textParts.join("\n\n").trim();
54211
- if (text14.length > 0) {
54361
+ const text15 = textParts.join("\n\n").trim();
54362
+ if (text15.length > 0) {
54212
54363
  if (imageCount > 0) {
54213
- return `${text14}
54364
+ return `${text15}
54214
54365
 
54215
54366
  [System: The original request included ${imageCount} image(s). Use the image context already provided in this conversation.]`;
54216
54367
  }
54217
- return text14;
54368
+ return text15;
54218
54369
  }
54219
54370
  if (imageCount > 0) {
54220
54371
  return `[System: Retry the previous image-based user request (${imageCount} image(s)). Use the existing image context in the conversation and do not repeat the same failed action.]`;
@@ -54233,8 +54384,8 @@ async function startRepl(options = {}) {
54233
54384
  };
54234
54385
  const getAutoSwitchCandidates = (current) => {
54235
54386
  const ordered = [];
54236
- const push = (p45) => {
54237
- if (p45 !== current && !ordered.includes(p45)) ordered.push(p45);
54387
+ const push = (p46) => {
54388
+ if (p46 !== current && !ordered.includes(p46)) ordered.push(p46);
54238
54389
  };
54239
54390
  if (current === "openai") {
54240
54391
  push("codex");
@@ -54272,7 +54423,7 @@ async function startRepl(options = {}) {
54272
54423
  "lmstudio",
54273
54424
  "ollama"
54274
54425
  ];
54275
- for (const p45 of genericOrder) push(p45);
54426
+ for (const p46 of genericOrder) push(p46);
54276
54427
  return ordered;
54277
54428
  };
54278
54429
  const attemptAutoProviderSwitch = async (reason, originalMessage) => {