@corbat-tech/coco 2.27.3 → 2.27.5

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.d.ts CHANGED
@@ -963,6 +963,8 @@ interface ToolUseContent {
963
963
  id: string;
964
964
  name: string;
965
965
  input: Record<string, unknown>;
966
+ /** Gemini-specific: preserve function-call thought signature across tool turns */
967
+ geminiThoughtSignature?: string;
966
968
  }
967
969
  /**
968
970
  * Tool result content block
@@ -999,6 +1001,8 @@ interface ToolCall {
999
1001
  id: string;
1000
1002
  name: string;
1001
1003
  input: Record<string, unknown>;
1004
+ /** Gemini-specific: preserve function-call thought signature across tool turns */
1005
+ geminiThoughtSignature?: string;
1002
1006
  }
1003
1007
  /**
1004
1008
  * Chat options
package/dist/index.js CHANGED
@@ -8,11 +8,11 @@ import fs16__default, { access, readFile, readdir, writeFile, mkdir } from 'fs/p
8
8
  import { randomUUID, randomBytes, createHash } from 'crypto';
9
9
  import * as http from 'http';
10
10
  import { fileURLToPath, URL as URL$1 } from 'url';
11
+ import { exec, execFile, execSync, spawn } from 'child_process';
12
+ import { promisify } from 'util';
11
13
  import { z } from 'zod';
12
14
  import * as p4 from '@clack/prompts';
13
15
  import chalk5 from 'chalk';
14
- import { exec, execFile, execSync, spawn } from 'child_process';
15
- import { promisify } from 'util';
16
16
  import { homedir } from 'os';
17
17
  import JSON5 from 'json5';
18
18
  import { execa } from 'execa';
@@ -676,6 +676,15 @@ async function exchangeForCopilotToken(githubToken) {
676
676
  }
677
677
  return await response.json();
678
678
  }
679
+ async function getGitHubCliToken() {
680
+ try {
681
+ const { stdout } = await execFileAsync("gh", ["auth", "token"], { timeout: 5e3 });
682
+ const token = stdout.trim();
683
+ return token.length > 0 ? token : null;
684
+ } catch {
685
+ return null;
686
+ }
687
+ }
679
688
  function getCopilotBaseUrl(accountType) {
680
689
  if (accountType && accountType in COPILOT_BASE_URLS) {
681
690
  return COPILOT_BASE_URLS[accountType];
@@ -713,10 +722,11 @@ function isCopilotTokenExpired(creds) {
713
722
  }
714
723
  async function getValidCopilotToken() {
715
724
  const creds = await loadCopilotCredentials();
716
- if (!creds) return null;
717
- const envToken = process.env["GITHUB_TOKEN"] || process.env["GH_TOKEN"];
718
- const githubToken = envToken || creds.githubToken;
719
- if (!isCopilotTokenExpired(creds) && creds.copilotToken) {
725
+ const envToken = process.env["COPILOT_GITHUB_TOKEN"] || process.env["GH_TOKEN"] || process.env["GITHUB_TOKEN"];
726
+ const fallbackGhToken = await getGitHubCliToken();
727
+ const githubToken = envToken || creds?.githubToken || fallbackGhToken;
728
+ if (!githubToken) return null;
729
+ if (creds && !isCopilotTokenExpired(creds) && creds.copilotToken) {
720
730
  return {
721
731
  token: creds.copilotToken,
722
732
  baseUrl: getCopilotBaseUrl(creds.accountType),
@@ -726,11 +736,11 @@ async function getValidCopilotToken() {
726
736
  try {
727
737
  const copilotToken = await exchangeForCopilotToken(githubToken);
728
738
  const updatedCreds = {
729
- ...creds,
730
- githubToken: creds.githubToken,
739
+ ...creds ?? { githubToken },
740
+ githubToken: creds?.githubToken ?? githubToken,
731
741
  copilotToken: copilotToken.token,
732
742
  copilotTokenExpiresAt: copilotToken.expires_at * 1e3,
733
- accountType: copilotToken.annotations?.copilot_plan ?? creds.accountType
743
+ accountType: copilotToken.annotations?.copilot_plan ?? creds?.accountType
734
744
  };
735
745
  await saveCopilotCredentials(updatedCreds);
736
746
  return {
@@ -746,7 +756,7 @@ async function getValidCopilotToken() {
746
756
  throw error;
747
757
  }
748
758
  }
749
- var COPILOT_TOKEN_URL, COPILOT_BASE_URLS, DEFAULT_COPILOT_BASE_URL, REFRESH_BUFFER_MS, CopilotAuthError, CopilotCredentialsSchema;
759
+ var COPILOT_TOKEN_URL, COPILOT_BASE_URLS, DEFAULT_COPILOT_BASE_URL, REFRESH_BUFFER_MS, execFileAsync, CopilotAuthError, CopilotCredentialsSchema;
750
760
  var init_copilot = __esm({
751
761
  "src/auth/copilot.ts"() {
752
762
  COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
@@ -757,6 +767,7 @@ var init_copilot = __esm({
757
767
  };
758
768
  DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
759
769
  REFRESH_BUFFER_MS = 6e4;
770
+ execFileAsync = promisify(execFile);
760
771
  CopilotAuthError = class extends Error {
761
772
  constructor(message, permanent) {
762
773
  super(message);
@@ -1482,7 +1493,7 @@ function getDefaultModel(provider) {
1482
1493
  case "anthropic":
1483
1494
  return process.env["ANTHROPIC_MODEL"] ?? "claude-opus-4-6";
1484
1495
  case "openai":
1485
- return process.env["OPENAI_MODEL"] ?? "gpt-5.4-codex";
1496
+ return process.env["OPENAI_MODEL"] ?? "gpt-5.3-codex";
1486
1497
  case "gemini":
1487
1498
  return process.env["GEMINI_MODEL"] ?? "gemini-3.1-pro-preview";
1488
1499
  case "vertex":
@@ -14107,7 +14118,7 @@ var ResponsesToolCallAssembler = class {
14107
14118
  };
14108
14119
 
14109
14120
  // src/providers/openai.ts
14110
- var DEFAULT_MODEL2 = "gpt-5.4-codex";
14121
+ var DEFAULT_MODEL2 = "gpt-5.3-codex";
14111
14122
  var CONTEXT_WINDOWS2 = {
14112
14123
  // OpenAI models
14113
14124
  "gpt-4o": 128e3,
@@ -15313,7 +15324,7 @@ function createKimiProvider(config) {
15313
15324
  init_errors();
15314
15325
  init_auth();
15315
15326
  var CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
15316
- var DEFAULT_MODEL3 = "gpt-5.4-codex";
15327
+ var DEFAULT_MODEL3 = "gpt-5.3-codex";
15317
15328
  var CONTEXT_WINDOWS3 = {
15318
15329
  "gpt-5.4-codex": 2e5,
15319
15330
  "gpt-5.3-codex": 2e5,
@@ -15930,23 +15941,35 @@ init_copilot();
15930
15941
  var CONTEXT_WINDOWS4 = {
15931
15942
  // Claude models — Copilot API caps these at 168 000 (not 200 000 like Anthropic direct)
15932
15943
  "claude-sonnet-4.6": 168e3,
15944
+ "claude-sonnet-4": 168e3,
15933
15945
  "claude-opus-4.6": 168e3,
15946
+ "claude-opus-4.6-fast": 168e3,
15934
15947
  "claude-sonnet-4.5": 168e3,
15935
15948
  "claude-opus-4.5": 168e3,
15936
15949
  "claude-haiku-4.5": 168e3,
15937
15950
  // OpenAI models — chat/completions
15938
15951
  "gpt-4.1": 1048576,
15952
+ "gpt-4o": 128e3,
15939
15953
  // OpenAI models — /responses API (Codex/GPT-5+)
15940
15954
  "gpt-5.4-codex": 4e5,
15955
+ "gpt-5.4": 4e5,
15956
+ "gpt-5.4-mini": 4e5,
15941
15957
  "gpt-5.3-codex": 4e5,
15942
15958
  "gpt-5.2-codex": 4e5,
15943
15959
  "gpt-5.1-codex-max": 4e5,
15960
+ "gpt-5-mini": 4e5,
15944
15961
  "gpt-5.2": 4e5,
15945
15962
  "gpt-5.1": 4e5,
15946
15963
  // Google models
15964
+ "gemini-3.1-pro": 1e6,
15947
15965
  "gemini-3.1-pro-preview": 1e6,
15966
+ "gemini-3-flash": 1e6,
15948
15967
  "gemini-3-flash-preview": 1e6,
15949
- "gemini-2.5-pro": 1048576
15968
+ "gemini-2.5-pro": 1048576,
15969
+ // Evaluation models
15970
+ "grok-code-fast-1": 4e5,
15971
+ "raptor-mini": 4e5,
15972
+ goldeneye: 4e5
15950
15973
  };
15951
15974
  var DEFAULT_MODEL4 = "claude-sonnet-4.6";
15952
15975
  function normalizeModel(model) {
@@ -16077,6 +16100,7 @@ var CopilotProvider = class extends OpenAIProvider {
16077
16100
  // src/providers/gemini.ts
16078
16101
  init_errors();
16079
16102
  var DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
16103
+ var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
16080
16104
  var CONTEXT_WINDOWS5 = {
16081
16105
  "gemini-3.1-pro-preview": 1e6,
16082
16106
  "gemini-3.1-flash-lite-preview": 1e6,
@@ -16169,30 +16193,29 @@ var GeminiProvider = class {
16169
16193
  if (text) {
16170
16194
  yield { type: "text", text };
16171
16195
  }
16172
- const functionCalls = this.extractFunctionCalls(chunk);
16173
- for (const functionCall of functionCalls) {
16174
- const toolCallId = functionCall.id ?? `gemini_call_${++fallbackToolCounter}`;
16196
+ const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
16197
+ for (const toolCall of toolCalls) {
16198
+ const toolCallId = toolCall.id ?? `gemini_call_${++fallbackToolCounter}`;
16175
16199
  if (emittedToolIds.has(toolCallId)) continue;
16176
16200
  emittedToolIds.add(toolCallId);
16177
- const toolCall = {
16178
- id: toolCallId,
16179
- name: functionCall.name ?? "unknown_function",
16180
- input: functionCall.args ?? {}
16201
+ const normalizedToolCall = {
16202
+ ...toolCall,
16203
+ id: toolCallId
16181
16204
  };
16182
16205
  yield {
16183
16206
  type: "tool_use_start",
16184
16207
  toolCall: {
16185
- id: toolCall.id,
16186
- name: toolCall.name
16208
+ id: normalizedToolCall.id,
16209
+ name: normalizedToolCall.name
16187
16210
  }
16188
16211
  };
16189
16212
  yield {
16190
16213
  type: "tool_use_end",
16191
- toolCall
16214
+ toolCall: normalizedToolCall
16192
16215
  };
16193
16216
  }
16194
16217
  const finishReason = chunk.candidates?.[0]?.finishReason;
16195
- if (functionCalls.length > 0) {
16218
+ if (toolCalls.length > 0) {
16196
16219
  streamStopReason = "tool_use";
16197
16220
  } else if (finishReason) {
16198
16221
  streamStopReason = this.mapFinishReason(finishReason);
@@ -16316,13 +16339,18 @@ var GeminiProvider = class {
16316
16339
  });
16317
16340
  } else if (block.type === "tool_use") {
16318
16341
  const toolUse = block;
16319
- parts.push({
16320
- functionCall: {
16321
- id: toolUse.id,
16322
- name: toolUse.name,
16323
- args: toolUse.input
16324
- }
16325
- });
16342
+ const thoughtSignature = toolUse.geminiThoughtSignature ?? SKIP_THOUGHT_SIGNATURE_VALIDATOR;
16343
+ const functionCall = {
16344
+ id: toolUse.id,
16345
+ name: toolUse.name,
16346
+ args: toolUse.input
16347
+ };
16348
+ const part = {
16349
+ functionCall,
16350
+ thoughtSignature,
16351
+ thought_signature: thoughtSignature
16352
+ };
16353
+ parts.push(part);
16326
16354
  }
16327
16355
  }
16328
16356
  return parts.length > 0 ? parts : [{ text: "" }];
@@ -16346,13 +16374,31 @@ var GeminiProvider = class {
16346
16374
  allowedFunctionNames: [choice.name]
16347
16375
  };
16348
16376
  }
16349
- extractFunctionCalls(response) {
16350
- if (response.functionCalls && response.functionCalls.length > 0) {
16351
- return response.functionCalls;
16377
+ extractThoughtSignatureFromPart(part) {
16378
+ const withSignature = part;
16379
+ return withSignature.thoughtSignature ?? withSignature.thought_signature ?? withSignature.functionCall?.thoughtSignature ?? withSignature.functionCall?.thought_signature;
16380
+ }
16381
+ extractToolCalls(response, options) {
16382
+ const toolCallsFromParts = (response.candidates?.[0]?.content?.parts ?? []).filter((part) => !!part.functionCall).map((part, index) => ({
16383
+ id: part.functionCall.id ?? `gemini_call_${index + 1}`,
16384
+ name: part.functionCall.name ?? "unknown_function",
16385
+ input: part.functionCall.args ?? {},
16386
+ geminiThoughtSignature: this.extractThoughtSignatureFromPart(part)
16387
+ }));
16388
+ if (toolCallsFromParts.length > 0) {
16389
+ return toolCallsFromParts;
16352
16390
  }
16353
- const candidate = response.candidates?.[0];
16354
- const parts = candidate?.content?.parts ?? [];
16355
- return parts.filter((part) => !!part.functionCall).map((part) => part.functionCall).filter(Boolean);
16391
+ if (!options?.includeLegacyFunctionCalls || !response.functionCalls?.length) {
16392
+ return [];
16393
+ }
16394
+ return response.functionCalls.map((functionCall, index) => ({
16395
+ id: functionCall.id ?? `gemini_call_${index + 1}`,
16396
+ name: functionCall.name ?? "unknown_function",
16397
+ input: functionCall.args ?? {},
16398
+ geminiThoughtSignature: this.extractThoughtSignatureFromPart({
16399
+ functionCall
16400
+ })
16401
+ }));
16356
16402
  }
16357
16403
  parseResponse(response, model) {
16358
16404
  const usage = response.usageMetadata;
@@ -16369,11 +16415,7 @@ var GeminiProvider = class {
16369
16415
  }
16370
16416
  parseResponseWithTools(response, model) {
16371
16417
  const usage = response.usageMetadata;
16372
- const toolCalls = this.extractFunctionCalls(response).map((functionCall, index) => ({
16373
- id: functionCall.id ?? `gemini_call_${index + 1}`,
16374
- name: functionCall.name ?? "unknown_function",
16375
- input: functionCall.args ?? {}
16376
- }));
16418
+ const toolCalls = this.extractToolCalls(response, { includeLegacyFunctionCalls: true });
16377
16419
  return {
16378
16420
  id: `gemini-${Date.now()}`,
16379
16421
  content: response.text ?? "",
@@ -16425,12 +16467,22 @@ var DEFAULT_MODEL6 = "gemini-2.5-pro";
16425
16467
  var DEFAULT_BASE_URL = "https://aiplatform.googleapis.com/v1";
16426
16468
  var DEFAULT_LOCATION = "global";
16427
16469
  var CONTEXT_WINDOWS6 = {
16470
+ "gemini-3-pro-preview": 1048576,
16471
+ "gemini-3-flash-preview": 1048576,
16428
16472
  "gemini-2.5-pro": 1048576,
16429
16473
  "gemini-2.5-flash": 1048576,
16430
16474
  "gemini-2.5-flash-lite": 1048576,
16431
16475
  "gemini-2.0-flash-001": 1048576,
16432
16476
  "gemini-2.0-flash-lite-001": 1048576
16433
16477
  };
16478
+ var SKIP_THOUGHT_SIGNATURE_VALIDATOR2 = "skip_thought_signature_validator";
16479
+ function extractSseEventData(rawEvent) {
16480
+ const dataLines = rawEvent.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean);
16481
+ if (dataLines.length === 0) {
16482
+ return null;
16483
+ }
16484
+ return dataLines.join("\n");
16485
+ }
16434
16486
  var VertexProvider = class {
16435
16487
  id = "vertex";
16436
16488
  name = "Google Vertex AI Gemini";
@@ -16515,12 +16567,14 @@ var VertexProvider = class {
16515
16567
  }
16516
16568
  if (part.functionCall) {
16517
16569
  streamToolCallCounter++;
16570
+ const geminiThoughtSignature = part.thoughtSignature ?? part.thought_signature ?? part.functionCall.thoughtSignature ?? part.functionCall.thought_signature;
16518
16571
  yield {
16519
16572
  type: "tool_use_start",
16520
16573
  toolCall: {
16521
16574
  id: `vertex_call_${streamToolCallCounter}`,
16522
16575
  name: part.functionCall.name,
16523
- input: part.functionCall.args ?? {}
16576
+ input: part.functionCall.args ?? {},
16577
+ geminiThoughtSignature
16524
16578
  }
16525
16579
  };
16526
16580
  yield {
@@ -16528,7 +16582,8 @@ var VertexProvider = class {
16528
16582
  toolCall: {
16529
16583
  id: `vertex_call_${streamToolCallCounter}`,
16530
16584
  name: part.functionCall.name,
16531
- input: part.functionCall.args ?? {}
16585
+ input: part.functionCall.args ?? {},
16586
+ geminiThoughtSignature
16532
16587
  }
16533
16588
  };
16534
16589
  }
@@ -16661,11 +16716,14 @@ var VertexProvider = class {
16661
16716
  });
16662
16717
  } else if (block.type === "tool_use") {
16663
16718
  const toolUse = block;
16719
+ const thoughtSignature = toolUse.geminiThoughtSignature ?? SKIP_THOUGHT_SIGNATURE_VALIDATOR2;
16664
16720
  parts.push({
16665
16721
  functionCall: {
16666
16722
  name: toolUse.name,
16667
16723
  args: toolUse.input
16668
- }
16724
+ },
16725
+ thoughtSignature,
16726
+ thought_signature: thoughtSignature
16669
16727
  });
16670
16728
  }
16671
16729
  }
@@ -16757,22 +16815,27 @@ var VertexProvider = class {
16757
16815
  if (done) break;
16758
16816
  buffer += decoder.decode(value, { stream: true });
16759
16817
  while (true) {
16760
- const eventBoundary = buffer.indexOf("\n\n");
16761
- if (eventBoundary === -1) break;
16762
- const rawEvent = buffer.slice(0, eventBoundary);
16763
- buffer = buffer.slice(eventBoundary + 2);
16764
- const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean);
16765
- for (const line of dataLines) {
16766
- if (line === "[DONE]") return;
16767
- yield JSON.parse(line);
16818
+ const boundaryMatch = /\r?\n\r?\n/.exec(buffer);
16819
+ if (!boundaryMatch || boundaryMatch.index === void 0) break;
16820
+ const rawEvent = buffer.slice(0, boundaryMatch.index);
16821
+ buffer = buffer.slice(boundaryMatch.index + boundaryMatch[0].length);
16822
+ const data = extractSseEventData(rawEvent);
16823
+ if (!data || data === "[DONE]") {
16824
+ if (data === "[DONE]") return;
16825
+ continue;
16826
+ }
16827
+ try {
16828
+ yield JSON.parse(data);
16829
+ } catch {
16830
+ continue;
16768
16831
  }
16769
16832
  }
16770
16833
  }
16771
- const trailing = buffer.trim();
16772
- if (trailing.startsWith("data:")) {
16773
- const line = trailing.slice(5).trim();
16774
- if (line && line !== "[DONE]") {
16775
- yield JSON.parse(line);
16834
+ const trailingData = extractSseEventData(buffer.trim());
16835
+ if (trailingData && trailingData !== "[DONE]") {
16836
+ try {
16837
+ yield JSON.parse(trailingData);
16838
+ } catch {
16776
16839
  }
16777
16840
  }
16778
16841
  }
@@ -16805,7 +16868,8 @@ var VertexProvider = class {
16805
16868
  toolCalls.push({
16806
16869
  id: `vertex_call_${toolIndex}`,
16807
16870
  name: part.functionCall.name,
16808
- input: part.functionCall.args ?? {}
16871
+ input: part.functionCall.args ?? {},
16872
+ geminiThoughtSignature: part.thoughtSignature ?? part.thought_signature ?? part.functionCall.thoughtSignature ?? part.functionCall.thought_signature
16809
16873
  });
16810
16874
  }
16811
16875
  }
@@ -21436,9 +21500,6 @@ var buildTools = [
21436
21500
  runGradleTool
21437
21501
  ];
21438
21502
 
21439
- // src/cli/repl/recommended-permissions.ts
21440
- init_paths();
21441
-
21442
21503
  // src/cli/repl/session.ts
21443
21504
  init_env();
21444
21505
  init_paths();
@@ -21473,6 +21534,7 @@ z.object({
21473
21534
  // src/cli/repl/session.ts
21474
21535
  path17__default.dirname(CONFIG_PATHS.trustedTools);
21475
21536
  CONFIG_PATHS.trustedTools;
21537
+ path17__default.join(".coco", "trusted-tools.json");
21476
21538
 
21477
21539
  // src/cli/repl/recommended-permissions.ts
21478
21540
  var RECOMMENDED_GLOBAL = [
@@ -25961,7 +26023,13 @@ var SuggestImprovementsSchema = z.object({
25961
26023
  context: z.string().optional().describe("Additional context about the code")
25962
26024
  });
25963
26025
  async function analyzeAndSuggest(filePath, _context) {
25964
- const rawContent = await fs33.readFile(filePath, "utf-8");
26026
+ let rawContent = await fs33.readFile(filePath, "utf-8");
26027
+ if (typeof rawContent !== "string") {
26028
+ const defaultReadFile = fs33.default?.readFile;
26029
+ if (typeof defaultReadFile === "function") {
26030
+ rawContent = await defaultReadFile(filePath, "utf-8");
26031
+ }
26032
+ }
25965
26033
  const content = typeof rawContent === "string" ? rawContent : String(rawContent ?? "");
25966
26034
  const lines = content.split("\n");
25967
26035
  const suggestions = [];
@@ -27485,7 +27553,7 @@ init_errors2();
27485
27553
  init_callback_server();
27486
27554
  init_paths();
27487
27555
  init_logger();
27488
- var execFileAsync2 = promisify(execFile);
27556
+ var execFileAsync3 = promisify(execFile);
27489
27557
  var TOKEN_STORE_PATH = path17__default.join(CONFIG_PATHS.tokens, "mcp-oauth.json");
27490
27558
  var OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
27491
27559
  var logger = getLogger();
@@ -27582,7 +27650,7 @@ async function openBrowser(url) {
27582
27650
  }
27583
27651
  for (const { cmd, args } of commands) {
27584
27652
  try {
27585
- await execFileAsync2(cmd, args);
27653
+ await execFileAsync3(cmd, args);
27586
27654
  return true;
27587
27655
  } catch {
27588
27656
  continue;