@corbat-tech/coco 2.27.4 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +728 -384
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +158 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -13,10 +13,10 @@ import JSON5 from 'json5';
|
|
|
13
13
|
import * as crypto from 'crypto';
|
|
14
14
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
15
15
|
import * as http from 'http';
|
|
16
|
-
import * as p26 from '@clack/prompts';
|
|
17
|
-
import chalk from 'chalk';
|
|
18
16
|
import { execFile, execSync, spawn, execFileSync, exec } from 'child_process';
|
|
19
17
|
import { promisify } from 'util';
|
|
18
|
+
import * as p26 from '@clack/prompts';
|
|
19
|
+
import chalk from 'chalk';
|
|
20
20
|
import { Logger } from 'tslog';
|
|
21
21
|
import Anthropic from '@anthropic-ai/sdk';
|
|
22
22
|
import { jsonrepair } from 'jsonrepair';
|
|
@@ -1477,6 +1477,32 @@ async function exchangeForCopilotToken(githubToken) {
|
|
|
1477
1477
|
}
|
|
1478
1478
|
return await response.json();
|
|
1479
1479
|
}
|
|
1480
|
+
async function getGitHubLogin(githubToken) {
|
|
1481
|
+
try {
|
|
1482
|
+
const response = await fetch("https://api.github.com/user", {
|
|
1483
|
+
method: "GET",
|
|
1484
|
+
headers: {
|
|
1485
|
+
Authorization: `token ${githubToken}`,
|
|
1486
|
+
Accept: "application/json",
|
|
1487
|
+
"User-Agent": "Corbat-Coco/1.0"
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
if (!response.ok) return null;
|
|
1491
|
+
const data = await response.json();
|
|
1492
|
+
return data.login ?? null;
|
|
1493
|
+
} catch {
|
|
1494
|
+
return null;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
async function getGitHubCliToken() {
|
|
1498
|
+
try {
|
|
1499
|
+
const { stdout } = await execFileAsync("gh", ["auth", "token"], { timeout: 5e3 });
|
|
1500
|
+
const token = stdout.trim();
|
|
1501
|
+
return token.length > 0 ? token : null;
|
|
1502
|
+
} catch {
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1480
1506
|
function getCopilotBaseUrl(accountType) {
|
|
1481
1507
|
if (accountType && accountType in COPILOT_BASE_URLS) {
|
|
1482
1508
|
return COPILOT_BASE_URLS[accountType];
|
|
@@ -1514,10 +1540,11 @@ function isCopilotTokenExpired(creds) {
|
|
|
1514
1540
|
}
|
|
1515
1541
|
async function getValidCopilotToken() {
|
|
1516
1542
|
const creds = await loadCopilotCredentials();
|
|
1517
|
-
|
|
1518
|
-
const
|
|
1519
|
-
const githubToken = envToken || creds
|
|
1520
|
-
if (!
|
|
1543
|
+
const envToken = process.env["COPILOT_GITHUB_TOKEN"] || process.env["GH_TOKEN"] || process.env["GITHUB_TOKEN"];
|
|
1544
|
+
const fallbackGhToken = await getGitHubCliToken();
|
|
1545
|
+
const githubToken = envToken || creds?.githubToken || fallbackGhToken;
|
|
1546
|
+
if (!githubToken) return null;
|
|
1547
|
+
if (creds && !isCopilotTokenExpired(creds) && creds.copilotToken) {
|
|
1521
1548
|
return {
|
|
1522
1549
|
token: creds.copilotToken,
|
|
1523
1550
|
baseUrl: getCopilotBaseUrl(creds.accountType),
|
|
@@ -1527,11 +1554,11 @@ async function getValidCopilotToken() {
|
|
|
1527
1554
|
try {
|
|
1528
1555
|
const copilotToken = await exchangeForCopilotToken(githubToken);
|
|
1529
1556
|
const updatedCreds = {
|
|
1530
|
-
...creds,
|
|
1531
|
-
githubToken: creds
|
|
1557
|
+
...creds ?? { githubToken },
|
|
1558
|
+
githubToken: creds?.githubToken ?? githubToken,
|
|
1532
1559
|
copilotToken: copilotToken.token,
|
|
1533
1560
|
copilotTokenExpiresAt: copilotToken.expires_at * 1e3,
|
|
1534
|
-
accountType: copilotToken.annotations?.copilot_plan ?? creds
|
|
1561
|
+
accountType: copilotToken.annotations?.copilot_plan ?? creds?.accountType
|
|
1535
1562
|
};
|
|
1536
1563
|
await saveCopilotCredentials(updatedCreds);
|
|
1537
1564
|
return {
|
|
@@ -1547,7 +1574,7 @@ async function getValidCopilotToken() {
|
|
|
1547
1574
|
throw error;
|
|
1548
1575
|
}
|
|
1549
1576
|
}
|
|
1550
|
-
var COPILOT_CLIENT_ID, GITHUB_DEVICE_CODE_URL, GITHUB_TOKEN_URL, COPILOT_TOKEN_URL, COPILOT_BASE_URLS, DEFAULT_COPILOT_BASE_URL, REFRESH_BUFFER_MS, CopilotAuthError, CopilotCredentialsSchema;
|
|
1577
|
+
var COPILOT_CLIENT_ID, GITHUB_DEVICE_CODE_URL, GITHUB_TOKEN_URL, COPILOT_TOKEN_URL, COPILOT_BASE_URLS, DEFAULT_COPILOT_BASE_URL, REFRESH_BUFFER_MS, execFileAsync, CopilotAuthError, CopilotCredentialsSchema;
|
|
1551
1578
|
var init_copilot = __esm({
|
|
1552
1579
|
"src/auth/copilot.ts"() {
|
|
1553
1580
|
COPILOT_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
@@ -1561,6 +1588,7 @@ var init_copilot = __esm({
|
|
|
1561
1588
|
};
|
|
1562
1589
|
DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
1563
1590
|
REFRESH_BUFFER_MS = 6e4;
|
|
1591
|
+
execFileAsync = promisify(execFile);
|
|
1564
1592
|
CopilotAuthError = class extends Error {
|
|
1565
1593
|
constructor(message, permanent) {
|
|
1566
1594
|
super(message);
|
|
@@ -1648,13 +1676,13 @@ async function openBrowser(url) {
|
|
|
1648
1676
|
const platform = process.platform;
|
|
1649
1677
|
try {
|
|
1650
1678
|
if (platform === "darwin") {
|
|
1651
|
-
await
|
|
1679
|
+
await execFileAsync2("open", [sanitizedUrl]);
|
|
1652
1680
|
} else if (platform === "win32") {
|
|
1653
|
-
await
|
|
1681
|
+
await execFileAsync2("rundll32", ["url.dll,FileProtocolHandler", sanitizedUrl]);
|
|
1654
1682
|
} else if (isWSL) {
|
|
1655
|
-
await
|
|
1683
|
+
await execFileAsync2("cmd.exe", ["/c", "start", "", sanitizedUrl]);
|
|
1656
1684
|
} else {
|
|
1657
|
-
await
|
|
1685
|
+
await execFileAsync2("xdg-open", [sanitizedUrl]);
|
|
1658
1686
|
}
|
|
1659
1687
|
return true;
|
|
1660
1688
|
} catch {
|
|
@@ -1704,7 +1732,7 @@ async function openBrowserFallback(url) {
|
|
|
1704
1732
|
}
|
|
1705
1733
|
for (const { cmd, args } of commands2) {
|
|
1706
1734
|
try {
|
|
1707
|
-
await
|
|
1735
|
+
await execFileAsync2(cmd, args);
|
|
1708
1736
|
return true;
|
|
1709
1737
|
} catch {
|
|
1710
1738
|
continue;
|
|
@@ -2168,6 +2196,10 @@ async function runCopilotDeviceFlow() {
|
|
|
2168
2196
|
}
|
|
2169
2197
|
);
|
|
2170
2198
|
spinner18.stop(chalk.green("\u2713 GitHub authentication successful!"));
|
|
2199
|
+
const githubLogin = await getGitHubLogin(githubToken);
|
|
2200
|
+
if (githubLogin) {
|
|
2201
|
+
console.log(chalk.dim(` Authenticated as: @${githubLogin}`));
|
|
2202
|
+
}
|
|
2171
2203
|
console.log(chalk.dim(" Exchanging token for Copilot access..."));
|
|
2172
2204
|
const copilotToken = await exchangeForCopilotToken(githubToken);
|
|
2173
2205
|
const creds = {
|
|
@@ -2194,6 +2226,11 @@ async function runCopilotDeviceFlow() {
|
|
|
2194
2226
|
console.log(chalk.red(" \u2717 GitHub Copilot is not enabled for this account."));
|
|
2195
2227
|
console.log(chalk.dim(" Please ensure you have an active Copilot subscription:"));
|
|
2196
2228
|
console.log(chalk.cyan(" \u2192 https://github.com/settings/copilot"));
|
|
2229
|
+
console.log(
|
|
2230
|
+
chalk.dim(
|
|
2231
|
+
" If this account is wrong, sign out of github.com in your browser and run /provider again."
|
|
2232
|
+
)
|
|
2233
|
+
);
|
|
2197
2234
|
} else if (errorMsg.includes("expired") || errorMsg.includes("timed out")) {
|
|
2198
2235
|
console.log(chalk.yellow(" \u26A0 Authentication timed out. Please try again."));
|
|
2199
2236
|
} else if (errorMsg.includes("denied")) {
|
|
@@ -2229,7 +2266,7 @@ async function getOrRefreshOAuthToken(provider) {
|
|
|
2229
2266
|
}
|
|
2230
2267
|
return null;
|
|
2231
2268
|
}
|
|
2232
|
-
var
|
|
2269
|
+
var execFileAsync2;
|
|
2233
2270
|
var init_flow = __esm({
|
|
2234
2271
|
"src/auth/flow.ts"() {
|
|
2235
2272
|
init_oauth();
|
|
@@ -2237,7 +2274,7 @@ var init_flow = __esm({
|
|
|
2237
2274
|
init_callback_server();
|
|
2238
2275
|
init_platform();
|
|
2239
2276
|
init_copilot();
|
|
2240
|
-
|
|
2277
|
+
execFileAsync2 = promisify(execFile);
|
|
2241
2278
|
}
|
|
2242
2279
|
});
|
|
2243
2280
|
function getADCPath() {
|
|
@@ -2340,6 +2377,22 @@ async function runGcloudADCLogin() {
|
|
|
2340
2377
|
}
|
|
2341
2378
|
}
|
|
2342
2379
|
}
|
|
2380
|
+
async function runGcloudADCRevoke() {
|
|
2381
|
+
try {
|
|
2382
|
+
await execAsync(ADC_REVOKE_COMMAND, {
|
|
2383
|
+
timeout: 12e4
|
|
2384
|
+
});
|
|
2385
|
+
clearADCCache();
|
|
2386
|
+
return true;
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2389
|
+
if (message.includes("No credentialed accounts") || message.includes("There are no credentials") || message.includes("No active credentials")) {
|
|
2390
|
+
clearADCCache();
|
|
2391
|
+
return true;
|
|
2392
|
+
}
|
|
2393
|
+
return false;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2343
2396
|
async function getGeminiADCKey() {
|
|
2344
2397
|
const token = await getADCAccessToken();
|
|
2345
2398
|
if (!token) return null;
|
|
@@ -2355,12 +2408,13 @@ async function getCachedADCToken() {
|
|
|
2355
2408
|
function clearADCCache() {
|
|
2356
2409
|
cachedToken = null;
|
|
2357
2410
|
}
|
|
2358
|
-
var execAsync, PRINT_ACCESS_TOKEN_COMMAND, ADC_LOGIN_COMMAND, GEMINI_OAUTH_SCOPES, cachedToken;
|
|
2411
|
+
var execAsync, PRINT_ACCESS_TOKEN_COMMAND, ADC_LOGIN_COMMAND, ADC_REVOKE_COMMAND, GEMINI_OAUTH_SCOPES, cachedToken;
|
|
2359
2412
|
var init_gcloud = __esm({
|
|
2360
2413
|
"src/auth/gcloud.ts"() {
|
|
2361
2414
|
execAsync = promisify(exec);
|
|
2362
2415
|
PRINT_ACCESS_TOKEN_COMMAND = "gcloud auth application-default print-access-token";
|
|
2363
2416
|
ADC_LOGIN_COMMAND = "gcloud auth application-default login";
|
|
2417
|
+
ADC_REVOKE_COMMAND = "gcloud auth application-default revoke --quiet";
|
|
2364
2418
|
GEMINI_OAUTH_SCOPES = [
|
|
2365
2419
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
2366
2420
|
"https://www.googleapis.com/auth/generative-language.retriever"
|
|
@@ -2408,6 +2462,7 @@ __export(auth_exports, {
|
|
|
2408
2462
|
requestDeviceCode: () => requestDeviceCode,
|
|
2409
2463
|
requestGitHubDeviceCode: () => requestGitHubDeviceCode,
|
|
2410
2464
|
runGcloudADCLogin: () => runGcloudADCLogin,
|
|
2465
|
+
runGcloudADCRevoke: () => runGcloudADCRevoke,
|
|
2411
2466
|
runOAuthFlow: () => runOAuthFlow,
|
|
2412
2467
|
saveCopilotCredentials: () => saveCopilotCredentials,
|
|
2413
2468
|
saveTokens: () => saveTokens,
|
|
@@ -2585,7 +2640,7 @@ function getDefaultModel(provider) {
|
|
|
2585
2640
|
case "anthropic":
|
|
2586
2641
|
return process.env["ANTHROPIC_MODEL"] ?? "claude-opus-4-6";
|
|
2587
2642
|
case "openai":
|
|
2588
|
-
return process.env["OPENAI_MODEL"] ?? "gpt-5.
|
|
2643
|
+
return process.env["OPENAI_MODEL"] ?? "gpt-5.3-codex";
|
|
2589
2644
|
case "gemini":
|
|
2590
2645
|
return process.env["GEMINI_MODEL"] ?? "gemini-3.1-pro-preview";
|
|
2591
2646
|
case "vertex":
|
|
@@ -3773,7 +3828,7 @@ var init_openai = __esm({
|
|
|
3773
3828
|
init_errors();
|
|
3774
3829
|
init_retry();
|
|
3775
3830
|
init_tool_call_normalizer();
|
|
3776
|
-
DEFAULT_MODEL2 = "gpt-5.
|
|
3831
|
+
DEFAULT_MODEL2 = "gpt-5.3-codex";
|
|
3777
3832
|
CONTEXT_WINDOWS2 = {
|
|
3778
3833
|
// OpenAI models
|
|
3779
3834
|
"gpt-4o": 128e3,
|
|
@@ -4983,7 +5038,7 @@ var init_codex = __esm({
|
|
|
4983
5038
|
init_retry();
|
|
4984
5039
|
init_tool_call_normalizer();
|
|
4985
5040
|
CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
4986
|
-
DEFAULT_MODEL3 = "gpt-5.
|
|
5041
|
+
DEFAULT_MODEL3 = "gpt-5.3-codex";
|
|
4987
5042
|
CONTEXT_WINDOWS3 = {
|
|
4988
5043
|
"gpt-5.4-codex": 2e5,
|
|
4989
5044
|
"gpt-5.3-codex": 2e5,
|
|
@@ -5757,11 +5812,12 @@ function createGeminiProvider(config) {
|
|
|
5757
5812
|
}
|
|
5758
5813
|
return provider;
|
|
5759
5814
|
}
|
|
5760
|
-
var DEFAULT_MODEL5, CONTEXT_WINDOWS5, GeminiProvider;
|
|
5815
|
+
var DEFAULT_MODEL5, SKIP_THOUGHT_SIGNATURE_VALIDATOR, CONTEXT_WINDOWS5, GeminiProvider;
|
|
5761
5816
|
var init_gemini = __esm({
|
|
5762
5817
|
"src/providers/gemini.ts"() {
|
|
5763
5818
|
init_errors();
|
|
5764
5819
|
DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
|
|
5820
|
+
SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
|
|
5765
5821
|
CONTEXT_WINDOWS5 = {
|
|
5766
5822
|
"gemini-3.1-pro-preview": 1e6,
|
|
5767
5823
|
"gemini-3.1-flash-lite-preview": 1e6,
|
|
@@ -5854,30 +5910,29 @@ var init_gemini = __esm({
|
|
|
5854
5910
|
if (text15) {
|
|
5855
5911
|
yield { type: "text", text: text15 };
|
|
5856
5912
|
}
|
|
5857
|
-
const
|
|
5858
|
-
for (const
|
|
5859
|
-
const toolCallId =
|
|
5913
|
+
const toolCalls = this.extractToolCalls(chunk, { includeLegacyFunctionCalls: true });
|
|
5914
|
+
for (const toolCall of toolCalls) {
|
|
5915
|
+
const toolCallId = toolCall.id ?? `gemini_call_${++fallbackToolCounter}`;
|
|
5860
5916
|
if (emittedToolIds.has(toolCallId)) continue;
|
|
5861
5917
|
emittedToolIds.add(toolCallId);
|
|
5862
|
-
const
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
input: functionCall.args ?? {}
|
|
5918
|
+
const normalizedToolCall = {
|
|
5919
|
+
...toolCall,
|
|
5920
|
+
id: toolCallId
|
|
5866
5921
|
};
|
|
5867
5922
|
yield {
|
|
5868
5923
|
type: "tool_use_start",
|
|
5869
5924
|
toolCall: {
|
|
5870
|
-
id:
|
|
5871
|
-
name:
|
|
5925
|
+
id: normalizedToolCall.id,
|
|
5926
|
+
name: normalizedToolCall.name
|
|
5872
5927
|
}
|
|
5873
5928
|
};
|
|
5874
5929
|
yield {
|
|
5875
5930
|
type: "tool_use_end",
|
|
5876
|
-
toolCall
|
|
5931
|
+
toolCall: normalizedToolCall
|
|
5877
5932
|
};
|
|
5878
5933
|
}
|
|
5879
5934
|
const finishReason = chunk.candidates?.[0]?.finishReason;
|
|
5880
|
-
if (
|
|
5935
|
+
if (toolCalls.length > 0) {
|
|
5881
5936
|
streamStopReason = "tool_use";
|
|
5882
5937
|
} else if (finishReason) {
|
|
5883
5938
|
streamStopReason = this.mapFinishReason(finishReason);
|
|
@@ -6001,13 +6056,18 @@ var init_gemini = __esm({
|
|
|
6001
6056
|
});
|
|
6002
6057
|
} else if (block.type === "tool_use") {
|
|
6003
6058
|
const toolUse = block;
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6059
|
+
const thoughtSignature = toolUse.geminiThoughtSignature ?? SKIP_THOUGHT_SIGNATURE_VALIDATOR;
|
|
6060
|
+
const functionCall = {
|
|
6061
|
+
id: toolUse.id,
|
|
6062
|
+
name: toolUse.name,
|
|
6063
|
+
args: toolUse.input
|
|
6064
|
+
};
|
|
6065
|
+
const part = {
|
|
6066
|
+
functionCall,
|
|
6067
|
+
thoughtSignature,
|
|
6068
|
+
thought_signature: thoughtSignature
|
|
6069
|
+
};
|
|
6070
|
+
parts.push(part);
|
|
6011
6071
|
}
|
|
6012
6072
|
}
|
|
6013
6073
|
return parts.length > 0 ? parts : [{ text: "" }];
|
|
@@ -6031,13 +6091,31 @@ var init_gemini = __esm({
|
|
|
6031
6091
|
allowedFunctionNames: [choice.name]
|
|
6032
6092
|
};
|
|
6033
6093
|
}
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6094
|
+
extractThoughtSignatureFromPart(part) {
|
|
6095
|
+
const withSignature = part;
|
|
6096
|
+
return withSignature.thoughtSignature ?? withSignature.thought_signature ?? withSignature.functionCall?.thoughtSignature ?? withSignature.functionCall?.thought_signature;
|
|
6097
|
+
}
|
|
6098
|
+
extractToolCalls(response, options) {
|
|
6099
|
+
const toolCallsFromParts = (response.candidates?.[0]?.content?.parts ?? []).filter((part) => !!part.functionCall).map((part, index) => ({
|
|
6100
|
+
id: part.functionCall.id ?? `gemini_call_${index + 1}`,
|
|
6101
|
+
name: part.functionCall.name ?? "unknown_function",
|
|
6102
|
+
input: part.functionCall.args ?? {},
|
|
6103
|
+
geminiThoughtSignature: this.extractThoughtSignatureFromPart(part)
|
|
6104
|
+
}));
|
|
6105
|
+
if (toolCallsFromParts.length > 0) {
|
|
6106
|
+
return toolCallsFromParts;
|
|
6037
6107
|
}
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6108
|
+
if (!options?.includeLegacyFunctionCalls || !response.functionCalls?.length) {
|
|
6109
|
+
return [];
|
|
6110
|
+
}
|
|
6111
|
+
return response.functionCalls.map((functionCall, index) => ({
|
|
6112
|
+
id: functionCall.id ?? `gemini_call_${index + 1}`,
|
|
6113
|
+
name: functionCall.name ?? "unknown_function",
|
|
6114
|
+
input: functionCall.args ?? {},
|
|
6115
|
+
geminiThoughtSignature: this.extractThoughtSignatureFromPart({
|
|
6116
|
+
functionCall
|
|
6117
|
+
})
|
|
6118
|
+
}));
|
|
6041
6119
|
}
|
|
6042
6120
|
parseResponse(response, model) {
|
|
6043
6121
|
const usage = response.usageMetadata;
|
|
@@ -6054,11 +6132,7 @@ var init_gemini = __esm({
|
|
|
6054
6132
|
}
|
|
6055
6133
|
parseResponseWithTools(response, model) {
|
|
6056
6134
|
const usage = response.usageMetadata;
|
|
6057
|
-
const toolCalls = this.
|
|
6058
|
-
id: functionCall.id ?? `gemini_call_${index + 1}`,
|
|
6059
|
-
name: functionCall.name ?? "unknown_function",
|
|
6060
|
-
input: functionCall.args ?? {}
|
|
6061
|
-
}));
|
|
6135
|
+
const toolCalls = this.extractToolCalls(response, { includeLegacyFunctionCalls: true });
|
|
6062
6136
|
return {
|
|
6063
6137
|
id: `gemini-${Date.now()}`,
|
|
6064
6138
|
content: response.text ?? "",
|
|
@@ -6106,6 +6180,24 @@ var init_gemini = __esm({
|
|
|
6106
6180
|
});
|
|
6107
6181
|
|
|
6108
6182
|
// src/providers/vertex.ts
|
|
6183
|
+
function extractSseEventData(rawEvent) {
|
|
6184
|
+
const dataLines = rawEvent.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean);
|
|
6185
|
+
if (dataLines.length === 0) {
|
|
6186
|
+
return null;
|
|
6187
|
+
}
|
|
6188
|
+
return dataLines.join("\n");
|
|
6189
|
+
}
|
|
6190
|
+
function getToolCallFingerprint(part) {
|
|
6191
|
+
const name = part.functionCall?.name ?? "unknown_function";
|
|
6192
|
+
let argsSerialized = "{}";
|
|
6193
|
+
try {
|
|
6194
|
+
argsSerialized = JSON.stringify(part.functionCall?.args ?? {});
|
|
6195
|
+
} catch {
|
|
6196
|
+
argsSerialized = "{}";
|
|
6197
|
+
}
|
|
6198
|
+
const thoughtSignature = part.thoughtSignature ?? part.thought_signature ?? part.functionCall?.thoughtSignature ?? part.functionCall?.thought_signature ?? "";
|
|
6199
|
+
return `${name}:${argsSerialized}:${thoughtSignature}`;
|
|
6200
|
+
}
|
|
6109
6201
|
function createVertexProvider(config) {
|
|
6110
6202
|
const provider = new VertexProvider();
|
|
6111
6203
|
if (config) {
|
|
@@ -6114,7 +6206,7 @@ function createVertexProvider(config) {
|
|
|
6114
6206
|
}
|
|
6115
6207
|
return provider;
|
|
6116
6208
|
}
|
|
6117
|
-
var DEFAULT_MODEL6, DEFAULT_BASE_URL, DEFAULT_LOCATION, CONTEXT_WINDOWS6, VertexProvider;
|
|
6209
|
+
var DEFAULT_MODEL6, DEFAULT_BASE_URL, DEFAULT_LOCATION, CONTEXT_WINDOWS6, SKIP_THOUGHT_SIGNATURE_VALIDATOR2, VertexProvider;
|
|
6118
6210
|
var init_vertex = __esm({
|
|
6119
6211
|
"src/providers/vertex.ts"() {
|
|
6120
6212
|
init_errors();
|
|
@@ -6124,12 +6216,15 @@ var init_vertex = __esm({
|
|
|
6124
6216
|
DEFAULT_BASE_URL = "https://aiplatform.googleapis.com/v1";
|
|
6125
6217
|
DEFAULT_LOCATION = "global";
|
|
6126
6218
|
CONTEXT_WINDOWS6 = {
|
|
6219
|
+
"gemini-3-pro-preview": 1048576,
|
|
6220
|
+
"gemini-3-flash-preview": 1048576,
|
|
6127
6221
|
"gemini-2.5-pro": 1048576,
|
|
6128
6222
|
"gemini-2.5-flash": 1048576,
|
|
6129
6223
|
"gemini-2.5-flash-lite": 1048576,
|
|
6130
6224
|
"gemini-2.0-flash-001": 1048576,
|
|
6131
6225
|
"gemini-2.0-flash-lite-001": 1048576
|
|
6132
6226
|
};
|
|
6227
|
+
SKIP_THOUGHT_SIGNATURE_VALIDATOR2 = "skip_thought_signature_validator";
|
|
6133
6228
|
VertexProvider = class {
|
|
6134
6229
|
id = "vertex";
|
|
6135
6230
|
name = "Google Vertex AI Gemini";
|
|
@@ -6205,6 +6300,7 @@ var init_vertex = __esm({
|
|
|
6205
6300
|
);
|
|
6206
6301
|
let stopReason = "end_turn";
|
|
6207
6302
|
let streamToolCallCounter = 0;
|
|
6303
|
+
const emittedToolFingerprints = /* @__PURE__ */ new Set();
|
|
6208
6304
|
for await (const chunk of stream) {
|
|
6209
6305
|
const candidate = chunk.candidates?.[0];
|
|
6210
6306
|
const parts = candidate?.content?.parts ?? [];
|
|
@@ -6213,13 +6309,20 @@ var init_vertex = __esm({
|
|
|
6213
6309
|
yield { type: "text", text: part.text };
|
|
6214
6310
|
}
|
|
6215
6311
|
if (part.functionCall) {
|
|
6312
|
+
const fingerprint = getToolCallFingerprint(part);
|
|
6313
|
+
if (emittedToolFingerprints.has(fingerprint)) {
|
|
6314
|
+
continue;
|
|
6315
|
+
}
|
|
6316
|
+
emittedToolFingerprints.add(fingerprint);
|
|
6216
6317
|
streamToolCallCounter++;
|
|
6318
|
+
const geminiThoughtSignature = part.thoughtSignature ?? part.thought_signature ?? part.functionCall.thoughtSignature ?? part.functionCall.thought_signature;
|
|
6217
6319
|
yield {
|
|
6218
6320
|
type: "tool_use_start",
|
|
6219
6321
|
toolCall: {
|
|
6220
6322
|
id: `vertex_call_${streamToolCallCounter}`,
|
|
6221
6323
|
name: part.functionCall.name,
|
|
6222
|
-
input: part.functionCall.args ?? {}
|
|
6324
|
+
input: part.functionCall.args ?? {},
|
|
6325
|
+
geminiThoughtSignature
|
|
6223
6326
|
}
|
|
6224
6327
|
};
|
|
6225
6328
|
yield {
|
|
@@ -6227,7 +6330,8 @@ var init_vertex = __esm({
|
|
|
6227
6330
|
toolCall: {
|
|
6228
6331
|
id: `vertex_call_${streamToolCallCounter}`,
|
|
6229
6332
|
name: part.functionCall.name,
|
|
6230
|
-
input: part.functionCall.args ?? {}
|
|
6333
|
+
input: part.functionCall.args ?? {},
|
|
6334
|
+
geminiThoughtSignature
|
|
6231
6335
|
}
|
|
6232
6336
|
};
|
|
6233
6337
|
}
|
|
@@ -6360,11 +6464,14 @@ var init_vertex = __esm({
|
|
|
6360
6464
|
});
|
|
6361
6465
|
} else if (block.type === "tool_use") {
|
|
6362
6466
|
const toolUse = block;
|
|
6467
|
+
const thoughtSignature = toolUse.geminiThoughtSignature ?? SKIP_THOUGHT_SIGNATURE_VALIDATOR2;
|
|
6363
6468
|
parts.push({
|
|
6364
6469
|
functionCall: {
|
|
6365
6470
|
name: toolUse.name,
|
|
6366
6471
|
args: toolUse.input
|
|
6367
|
-
}
|
|
6472
|
+
},
|
|
6473
|
+
thoughtSignature,
|
|
6474
|
+
thought_signature: thoughtSignature
|
|
6368
6475
|
});
|
|
6369
6476
|
}
|
|
6370
6477
|
}
|
|
@@ -6456,22 +6563,27 @@ var init_vertex = __esm({
|
|
|
6456
6563
|
if (done) break;
|
|
6457
6564
|
buffer += decoder.decode(value, { stream: true });
|
|
6458
6565
|
while (true) {
|
|
6459
|
-
const
|
|
6460
|
-
if (
|
|
6461
|
-
const rawEvent = buffer.slice(0,
|
|
6462
|
-
buffer = buffer.slice(
|
|
6463
|
-
const
|
|
6464
|
-
|
|
6465
|
-
if (
|
|
6466
|
-
|
|
6566
|
+
const boundaryMatch = /\r?\n\r?\n/.exec(buffer);
|
|
6567
|
+
if (!boundaryMatch || boundaryMatch.index === void 0) break;
|
|
6568
|
+
const rawEvent = buffer.slice(0, boundaryMatch.index);
|
|
6569
|
+
buffer = buffer.slice(boundaryMatch.index + boundaryMatch[0].length);
|
|
6570
|
+
const data = extractSseEventData(rawEvent);
|
|
6571
|
+
if (!data || data === "[DONE]") {
|
|
6572
|
+
if (data === "[DONE]") return;
|
|
6573
|
+
continue;
|
|
6574
|
+
}
|
|
6575
|
+
try {
|
|
6576
|
+
yield JSON.parse(data);
|
|
6577
|
+
} catch {
|
|
6578
|
+
continue;
|
|
6467
6579
|
}
|
|
6468
6580
|
}
|
|
6469
6581
|
}
|
|
6470
|
-
const
|
|
6471
|
-
if (
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6582
|
+
const trailingData = extractSseEventData(buffer.trim());
|
|
6583
|
+
if (trailingData && trailingData !== "[DONE]") {
|
|
6584
|
+
try {
|
|
6585
|
+
yield JSON.parse(trailingData);
|
|
6586
|
+
} catch {
|
|
6475
6587
|
}
|
|
6476
6588
|
}
|
|
6477
6589
|
}
|
|
@@ -6504,7 +6616,8 @@ var init_vertex = __esm({
|
|
|
6504
6616
|
toolCalls.push({
|
|
6505
6617
|
id: `vertex_call_${toolIndex}`,
|
|
6506
6618
|
name: part.functionCall.name,
|
|
6507
|
-
input: part.functionCall.args ?? {}
|
|
6619
|
+
input: part.functionCall.args ?? {},
|
|
6620
|
+
geminiThoughtSignature: part.thoughtSignature ?? part.thought_signature ?? part.functionCall.thoughtSignature ?? part.functionCall.thought_signature
|
|
6508
6621
|
});
|
|
6509
6622
|
}
|
|
6510
6623
|
}
|
|
@@ -6609,6 +6722,7 @@ var init_pricing = __esm({
|
|
|
6609
6722
|
"gpt-4o": { inputPerMillion: 2.5, outputPerMillion: 10, contextWindow: 128e3 },
|
|
6610
6723
|
"gpt-4o-mini": { inputPerMillion: 0.15, outputPerMillion: 0.6, contextWindow: 128e3 },
|
|
6611
6724
|
// Google Gemini models
|
|
6725
|
+
"gemini-3-pro-preview": { inputPerMillion: 1.25, outputPerMillion: 5, contextWindow: 1e6 },
|
|
6612
6726
|
"gemini-3.1-pro-preview": { inputPerMillion: 1.25, outputPerMillion: 5, contextWindow: 1e6 },
|
|
6613
6727
|
"gemini-3-flash-preview": {
|
|
6614
6728
|
inputPerMillion: 0.15,
|
|
@@ -10446,17 +10560,55 @@ async function saveTrustSettings(settings) {
|
|
|
10446
10560
|
console.warn(`[Trust] Failed to save trust settings: ${msg}`);
|
|
10447
10561
|
}
|
|
10448
10562
|
}
|
|
10449
|
-
|
|
10563
|
+
function getProjectTrustSettingsFile(projectPath) {
|
|
10564
|
+
return path39__default.join(projectPath, PROJECT_TRUST_FILE_RELATIVE_PATH);
|
|
10565
|
+
}
|
|
10566
|
+
async function loadProjectTrustSettings(projectPath) {
|
|
10450
10567
|
const settings = await loadTrustSettings();
|
|
10568
|
+
const legacyTrusted = settings.projectTrusted[projectPath] ?? [];
|
|
10569
|
+
const legacyDenied = settings.projectDenied[projectPath] ?? [];
|
|
10570
|
+
const defaultState = {
|
|
10571
|
+
trusted: legacyTrusted,
|
|
10572
|
+
denied: legacyDenied,
|
|
10573
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10574
|
+
};
|
|
10575
|
+
try {
|
|
10576
|
+
const content = await fs35__default.readFile(getProjectTrustSettingsFile(projectPath), "utf-8");
|
|
10577
|
+
const raw = JSON.parse(content);
|
|
10578
|
+
return {
|
|
10579
|
+
trusted: raw.trusted ?? defaultState.trusted,
|
|
10580
|
+
denied: raw.denied ?? defaultState.denied,
|
|
10581
|
+
updatedAt: raw.updatedAt ?? defaultState.updatedAt
|
|
10582
|
+
};
|
|
10583
|
+
} catch {
|
|
10584
|
+
return defaultState;
|
|
10585
|
+
}
|
|
10586
|
+
}
|
|
10587
|
+
async function saveProjectTrustSettings(projectPath, settings) {
|
|
10588
|
+
try {
|
|
10589
|
+
const filePath = getProjectTrustSettingsFile(projectPath);
|
|
10590
|
+
await fs35__default.mkdir(path39__default.dirname(filePath), { recursive: true });
|
|
10591
|
+
settings.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10592
|
+
await fs35__default.writeFile(filePath, JSON.stringify(settings, null, 2), "utf-8");
|
|
10593
|
+
} catch (error) {
|
|
10594
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
10595
|
+
console.warn(`[Trust] Failed to save project trust settings: ${msg}`);
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
async function loadTrustedTools(projectPath) {
|
|
10599
|
+
const [settings, projectSettings] = await Promise.all([
|
|
10600
|
+
loadTrustSettings(),
|
|
10601
|
+
loadProjectTrustSettings(projectPath)
|
|
10602
|
+
]);
|
|
10451
10603
|
const trusted = /* @__PURE__ */ new Set();
|
|
10452
10604
|
for (const tool of settings.globalTrusted) {
|
|
10453
10605
|
trusted.add(tool);
|
|
10454
10606
|
}
|
|
10455
|
-
const projectTrusted =
|
|
10607
|
+
const projectTrusted = projectSettings.trusted;
|
|
10456
10608
|
for (const tool of projectTrusted) {
|
|
10457
10609
|
trusted.add(tool);
|
|
10458
10610
|
}
|
|
10459
|
-
const projectDenied =
|
|
10611
|
+
const projectDenied = projectSettings.denied;
|
|
10460
10612
|
for (const tool of projectDenied) {
|
|
10461
10613
|
trusted.delete(tool);
|
|
10462
10614
|
}
|
|
@@ -10469,61 +10621,54 @@ async function saveTrustedTool(toolName, projectPath, global = false) {
|
|
|
10469
10621
|
settings.globalTrusted.push(toolName);
|
|
10470
10622
|
}
|
|
10471
10623
|
} else if (projectPath) {
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
const projectTrusted = settings.projectTrusted[projectPath];
|
|
10476
|
-
if (projectTrusted && !projectTrusted.includes(toolName)) {
|
|
10477
|
-
projectTrusted.push(toolName);
|
|
10624
|
+
const projectSettings = await loadProjectTrustSettings(projectPath);
|
|
10625
|
+
if (!projectSettings.trusted.includes(toolName)) {
|
|
10626
|
+
projectSettings.trusted.push(toolName);
|
|
10478
10627
|
}
|
|
10628
|
+
projectSettings.denied = projectSettings.denied.filter((t) => t !== toolName);
|
|
10629
|
+
await saveProjectTrustSettings(projectPath, projectSettings);
|
|
10630
|
+
}
|
|
10631
|
+
if (global) {
|
|
10632
|
+
await saveTrustSettings(settings);
|
|
10479
10633
|
}
|
|
10480
|
-
await saveTrustSettings(settings);
|
|
10481
10634
|
}
|
|
10482
10635
|
async function removeTrustedTool(toolName, projectPath, global = false) {
|
|
10483
10636
|
const settings = await loadTrustSettings();
|
|
10484
10637
|
if (global) {
|
|
10485
10638
|
settings.globalTrusted = settings.globalTrusted.filter((t) => t !== toolName);
|
|
10639
|
+
await saveTrustSettings(settings);
|
|
10486
10640
|
} else {
|
|
10487
|
-
const
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
}
|
|
10641
|
+
const projectSettings = await loadProjectTrustSettings(projectPath);
|
|
10642
|
+
projectSettings.trusted = projectSettings.trusted.filter((t) => t !== toolName);
|
|
10643
|
+
await saveProjectTrustSettings(projectPath, projectSettings);
|
|
10491
10644
|
}
|
|
10492
|
-
await saveTrustSettings(settings);
|
|
10493
10645
|
}
|
|
10494
10646
|
async function saveDeniedTool(toolName, projectPath) {
|
|
10495
|
-
const
|
|
10496
|
-
if (!
|
|
10497
|
-
|
|
10647
|
+
const projectSettings = await loadProjectTrustSettings(projectPath);
|
|
10648
|
+
if (!projectSettings.denied.includes(toolName)) {
|
|
10649
|
+
projectSettings.denied.push(toolName);
|
|
10498
10650
|
}
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
denied.push(toolName);
|
|
10502
|
-
}
|
|
10503
|
-
const projectTrusted = settings.projectTrusted[projectPath];
|
|
10504
|
-
if (projectTrusted) {
|
|
10505
|
-
settings.projectTrusted[projectPath] = projectTrusted.filter((t) => t !== toolName);
|
|
10506
|
-
}
|
|
10507
|
-
await saveTrustSettings(settings);
|
|
10651
|
+
projectSettings.trusted = projectSettings.trusted.filter((t) => t !== toolName);
|
|
10652
|
+
await saveProjectTrustSettings(projectPath, projectSettings);
|
|
10508
10653
|
}
|
|
10509
10654
|
async function removeDeniedTool(toolName, projectPath) {
|
|
10510
|
-
const
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
settings.projectDenied[projectPath] = denied.filter((t) => t !== toolName);
|
|
10514
|
-
}
|
|
10515
|
-
await saveTrustSettings(settings);
|
|
10655
|
+
const projectSettings = await loadProjectTrustSettings(projectPath);
|
|
10656
|
+
projectSettings.denied = projectSettings.denied.filter((t) => t !== toolName);
|
|
10657
|
+
await saveProjectTrustSettings(projectPath, projectSettings);
|
|
10516
10658
|
}
|
|
10517
10659
|
async function getDeniedTools(projectPath) {
|
|
10518
|
-
const settings = await
|
|
10519
|
-
return settings.
|
|
10660
|
+
const settings = await loadProjectTrustSettings(projectPath);
|
|
10661
|
+
return settings.denied;
|
|
10520
10662
|
}
|
|
10521
10663
|
async function getAllTrustedTools(projectPath) {
|
|
10522
|
-
const settings = await
|
|
10664
|
+
const [settings, projectSettings] = await Promise.all([
|
|
10665
|
+
loadTrustSettings(),
|
|
10666
|
+
loadProjectTrustSettings(projectPath)
|
|
10667
|
+
]);
|
|
10523
10668
|
return {
|
|
10524
10669
|
global: settings.globalTrusted,
|
|
10525
|
-
project:
|
|
10526
|
-
denied:
|
|
10670
|
+
project: projectSettings.trusted,
|
|
10671
|
+
denied: projectSettings.denied
|
|
10527
10672
|
};
|
|
10528
10673
|
}
|
|
10529
10674
|
async function initializeSessionTrust(session) {
|
|
@@ -10614,7 +10759,7 @@ function getSessionMemory(session) {
|
|
|
10614
10759
|
async function reloadSessionMemory(session) {
|
|
10615
10760
|
await initializeSessionMemory(session);
|
|
10616
10761
|
}
|
|
10617
|
-
var MAX_SKILL_INSTRUCTIONS_CHARS, TRUST_SETTINGS_DIR, TRUST_SETTINGS_FILE, CATEGORY_LABELS, COCO_SYSTEM_PROMPT, SHELL_METACHARACTERS, SAFE_COMMAND_VALIDATORS;
|
|
10762
|
+
var MAX_SKILL_INSTRUCTIONS_CHARS, TRUST_SETTINGS_DIR, TRUST_SETTINGS_FILE, PROJECT_TRUST_FILE_RELATIVE_PATH, CATEGORY_LABELS, COCO_SYSTEM_PROMPT, SHELL_METACHARACTERS, SAFE_COMMAND_VALIDATORS;
|
|
10618
10763
|
var init_session = __esm({
|
|
10619
10764
|
"src/cli/repl/session.ts"() {
|
|
10620
10765
|
init_env();
|
|
@@ -10629,6 +10774,7 @@ var init_session = __esm({
|
|
|
10629
10774
|
MAX_SKILL_INSTRUCTIONS_CHARS = 16e3;
|
|
10630
10775
|
TRUST_SETTINGS_DIR = path39__default.dirname(CONFIG_PATHS.trustedTools);
|
|
10631
10776
|
TRUST_SETTINGS_FILE = CONFIG_PATHS.trustedTools;
|
|
10777
|
+
PROJECT_TRUST_FILE_RELATIVE_PATH = path39__default.join(".coco", "trusted-tools.json");
|
|
10632
10778
|
CATEGORY_LABELS = {
|
|
10633
10779
|
mcp: "MCP Connected Services",
|
|
10634
10780
|
file: "File Operations",
|
|
@@ -21620,7 +21766,7 @@ async function openBrowser2(url) {
|
|
|
21620
21766
|
}
|
|
21621
21767
|
for (const { cmd, args } of commands2) {
|
|
21622
21768
|
try {
|
|
21623
|
-
await
|
|
21769
|
+
await execFileAsync3(cmd, args);
|
|
21624
21770
|
return true;
|
|
21625
21771
|
} catch {
|
|
21626
21772
|
continue;
|
|
@@ -21896,13 +22042,13 @@ async function authenticateMcpOAuth(params) {
|
|
|
21896
22042
|
await persistToken(resource, token, { authorizationServer, clientId });
|
|
21897
22043
|
return token.access_token;
|
|
21898
22044
|
}
|
|
21899
|
-
var
|
|
22045
|
+
var execFileAsync3, TOKEN_STORE_PATH, OAUTH_TIMEOUT_MS, logger;
|
|
21900
22046
|
var init_oauth2 = __esm({
|
|
21901
22047
|
"src/mcp/oauth.ts"() {
|
|
21902
22048
|
init_callback_server();
|
|
21903
22049
|
init_paths();
|
|
21904
22050
|
init_logger();
|
|
21905
|
-
|
|
22051
|
+
execFileAsync3 = promisify(execFile);
|
|
21906
22052
|
TOKEN_STORE_PATH = path39__default.join(CONFIG_PATHS.tokens, "mcp-oauth.json");
|
|
21907
22053
|
OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
21908
22054
|
logger = getLogger();
|
|
@@ -22543,6 +22689,25 @@ var init_lifecycle = __esm({
|
|
|
22543
22689
|
connections = /* @__PURE__ */ new Map();
|
|
22544
22690
|
logger = getLogger();
|
|
22545
22691
|
static STOP_TIMEOUT_MS = 5e3;
|
|
22692
|
+
/**
|
|
22693
|
+
* Run an async operation with a timeout, always clearing timer resources.
|
|
22694
|
+
*/
|
|
22695
|
+
async runWithTimeout(operation, timeoutMs, timeoutMessage) {
|
|
22696
|
+
let timeoutId;
|
|
22697
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
22698
|
+
timeoutId = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
|
|
22699
|
+
if (typeof timeoutId.unref === "function") {
|
|
22700
|
+
timeoutId.unref();
|
|
22701
|
+
}
|
|
22702
|
+
});
|
|
22703
|
+
try {
|
|
22704
|
+
return await Promise.race([operation, timeoutPromise]);
|
|
22705
|
+
} finally {
|
|
22706
|
+
if (timeoutId) {
|
|
22707
|
+
clearTimeout(timeoutId);
|
|
22708
|
+
}
|
|
22709
|
+
}
|
|
22710
|
+
}
|
|
22546
22711
|
/**
|
|
22547
22712
|
* Create transport for a server config
|
|
22548
22713
|
*/
|
|
@@ -22629,15 +22794,11 @@ var init_lifecycle = __esm({
|
|
|
22629
22794
|
}
|
|
22630
22795
|
this.logger.info(`Stopping MCP server: ${name}`);
|
|
22631
22796
|
try {
|
|
22632
|
-
await
|
|
22797
|
+
await this.runWithTimeout(
|
|
22633
22798
|
connection.transport.disconnect(),
|
|
22634
|
-
|
|
22635
|
-
|
|
22636
|
-
|
|
22637
|
-
_MCPServerManager.STOP_TIMEOUT_MS
|
|
22638
|
-
)
|
|
22639
|
-
)
|
|
22640
|
-
]);
|
|
22799
|
+
_MCPServerManager.STOP_TIMEOUT_MS,
|
|
22800
|
+
"MCP disconnect timeout"
|
|
22801
|
+
);
|
|
22641
22802
|
} catch (error) {
|
|
22642
22803
|
this.logger.error(
|
|
22643
22804
|
`Error disconnecting server '${name}': ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -22674,12 +22835,11 @@ var init_lifecycle = __esm({
|
|
|
22674
22835
|
}
|
|
22675
22836
|
const startTime = performance.now();
|
|
22676
22837
|
try {
|
|
22677
|
-
const { tools } = await
|
|
22838
|
+
const { tools } = await this.runWithTimeout(
|
|
22678
22839
|
connection.client.listTools(),
|
|
22679
|
-
|
|
22680
|
-
|
|
22681
|
-
|
|
22682
|
-
]);
|
|
22840
|
+
5e3,
|
|
22841
|
+
"Health check timeout"
|
|
22842
|
+
);
|
|
22683
22843
|
const latencyMs = performance.now() - startTime;
|
|
22684
22844
|
connection.healthy = true;
|
|
22685
22845
|
connection.toolCount = tools.length;
|
|
@@ -29123,20 +29283,13 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29123
29283
|
},
|
|
29124
29284
|
// Updated: March 2026 — from platform.openai.com/docs/models
|
|
29125
29285
|
models: [
|
|
29126
|
-
{
|
|
29127
|
-
id: "gpt-5.4-codex",
|
|
29128
|
-
name: "GPT-5.4 Codex",
|
|
29129
|
-
description: "Latest agentic coding model (Mar 2026)",
|
|
29130
|
-
contextWindow: 4e5,
|
|
29131
|
-
maxOutputTokens: 128e3,
|
|
29132
|
-
recommended: true
|
|
29133
|
-
},
|
|
29134
29286
|
{
|
|
29135
29287
|
id: "gpt-5.3-codex",
|
|
29136
29288
|
name: "GPT-5.3 Codex",
|
|
29137
|
-
description: "
|
|
29289
|
+
description: "Latest available agentic coding model",
|
|
29138
29290
|
contextWindow: 4e5,
|
|
29139
|
-
maxOutputTokens: 128e3
|
|
29291
|
+
maxOutputTokens: 128e3,
|
|
29292
|
+
recommended: true
|
|
29140
29293
|
},
|
|
29141
29294
|
{
|
|
29142
29295
|
id: "gpt-5.2-codex",
|
|
@@ -29437,20 +29590,13 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29437
29590
|
vision: true
|
|
29438
29591
|
},
|
|
29439
29592
|
models: [
|
|
29440
|
-
{
|
|
29441
|
-
id: "gpt-5.4-codex",
|
|
29442
|
-
name: "GPT-5.4 Codex",
|
|
29443
|
-
description: "Latest coding model via ChatGPT subscription (Mar 2026)",
|
|
29444
|
-
contextWindow: 2e5,
|
|
29445
|
-
maxOutputTokens: 128e3,
|
|
29446
|
-
recommended: true
|
|
29447
|
-
},
|
|
29448
29593
|
{
|
|
29449
29594
|
id: "gpt-5.3-codex",
|
|
29450
29595
|
name: "GPT-5.3 Codex",
|
|
29451
|
-
description: "
|
|
29596
|
+
description: "Latest available coding model via ChatGPT subscription",
|
|
29452
29597
|
contextWindow: 2e5,
|
|
29453
|
-
maxOutputTokens: 128e3
|
|
29598
|
+
maxOutputTokens: 128e3,
|
|
29599
|
+
recommended: true
|
|
29454
29600
|
},
|
|
29455
29601
|
{
|
|
29456
29602
|
id: "gpt-5.2-codex",
|
|
@@ -29560,13 +29706,27 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29560
29706
|
},
|
|
29561
29707
|
models: [
|
|
29562
29708
|
{
|
|
29563
|
-
id: "gemini-
|
|
29564
|
-
name: "Gemini
|
|
29565
|
-
description: "
|
|
29709
|
+
id: "gemini-3-pro-preview",
|
|
29710
|
+
name: "Gemini 3 Pro (Preview)",
|
|
29711
|
+
description: "Most capable Vertex Gemini 3 model (preview)",
|
|
29566
29712
|
contextWindow: 1048576,
|
|
29567
29713
|
maxOutputTokens: 65536,
|
|
29568
29714
|
recommended: true
|
|
29569
29715
|
},
|
|
29716
|
+
{
|
|
29717
|
+
id: "gemini-3-flash-preview",
|
|
29718
|
+
name: "Gemini 3 Flash (Preview)",
|
|
29719
|
+
description: "Fast Gemini 3 model on Vertex (preview)",
|
|
29720
|
+
contextWindow: 1048576,
|
|
29721
|
+
maxOutputTokens: 65536
|
|
29722
|
+
},
|
|
29723
|
+
{
|
|
29724
|
+
id: "gemini-2.5-pro",
|
|
29725
|
+
name: "Gemini 2.5 Pro",
|
|
29726
|
+
description: "Stable high-quality Vertex model for coding and complex reasoning",
|
|
29727
|
+
contextWindow: 1048576,
|
|
29728
|
+
maxOutputTokens: 65536
|
|
29729
|
+
},
|
|
29570
29730
|
{
|
|
29571
29731
|
id: "gemini-2.5-flash",
|
|
29572
29732
|
name: "Gemini 2.5 Flash",
|
|
@@ -33847,10 +34007,13 @@ async function selectModelInteractively(models, currentModelId) {
|
|
|
33847
34007
|
totalLines++;
|
|
33848
34008
|
}
|
|
33849
34009
|
const star = model.recommended ? " \u2B50" : "";
|
|
33850
|
-
const
|
|
34010
|
+
const multiplierMatch = model.description?.match(
|
|
34011
|
+
/\b(?:Premium|Free)\s*x([0-9]+(?:\.[0-9]+)?)\b/i
|
|
34012
|
+
);
|
|
34013
|
+
const metric = multiplierMatch ? ` x${multiplierMatch[1]}` : model.contextWindow ? ` ${Math.round(model.contextWindow / 1e3)}K` : "";
|
|
33851
34014
|
const desc = model.description ? ` ${model.description}` : "";
|
|
33852
34015
|
const hint = model.hint ? ` \u2192 ${model.hint}` : "";
|
|
33853
|
-
const suffix = truncate2(`${star}${
|
|
34016
|
+
const suffix = truncate2(`${star}${metric}${desc}${hint}`, descWidth, "\u2026");
|
|
33854
34017
|
if (model.disabled) {
|
|
33855
34018
|
let line2 = chalk.dim(" \u25CB ");
|
|
33856
34019
|
line2 += chalk.dim(model.id.padEnd(30));
|
|
@@ -34173,7 +34336,10 @@ async function setupProviderWithAuth(provider) {
|
|
|
34173
34336
|
authMethod = choice;
|
|
34174
34337
|
}
|
|
34175
34338
|
if (authMethod === "oauth") {
|
|
34339
|
+
const oauthSpinner = p26.spinner();
|
|
34340
|
+
oauthSpinner.start("Starting OAuth sign-in flow...");
|
|
34176
34341
|
const result = await runOAuthFlow(provider.id);
|
|
34342
|
+
oauthSpinner.stop(result ? "OAuth sign-in completed" : "OAuth sign-in cancelled");
|
|
34177
34343
|
if (!result) return null;
|
|
34178
34344
|
if (provider.id === "copilot") {
|
|
34179
34345
|
const model3 = await selectModel(provider);
|
|
@@ -34257,7 +34423,10 @@ async function setupGcloudADC(provider) {
|
|
|
34257
34423
|
);
|
|
34258
34424
|
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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
34259
34425
|
console.log();
|
|
34426
|
+
const gcloudCheckSpinner = p26.spinner();
|
|
34427
|
+
gcloudCheckSpinner.start("Checking gcloud CLI...");
|
|
34260
34428
|
const gcloudInstalled = await isGcloudInstalled();
|
|
34429
|
+
gcloudCheckSpinner.stop(gcloudInstalled ? "gcloud CLI detected" : "gcloud CLI not detected");
|
|
34261
34430
|
if (!gcloudInstalled) {
|
|
34262
34431
|
p26.log.error("gcloud CLI is not installed");
|
|
34263
34432
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install"));
|
|
@@ -34288,10 +34457,50 @@ async function setupGcloudADC(provider) {
|
|
|
34288
34457
|
location: vertexSettings2?.location
|
|
34289
34458
|
};
|
|
34290
34459
|
}
|
|
34460
|
+
const adcInspectSpinner = p26.spinner();
|
|
34461
|
+
adcInspectSpinner.start("Checking existing ADC credentials...");
|
|
34291
34462
|
let adc = await inspectADC();
|
|
34463
|
+
adcInspectSpinner.stop(
|
|
34464
|
+
adc.status === "ok" && adc.token ? "ADC credentials found" : "No reusable ADC credentials found"
|
|
34465
|
+
);
|
|
34292
34466
|
if (adc.status === "ok" && adc.token) {
|
|
34293
34467
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!"));
|
|
34294
34468
|
console.log();
|
|
34469
|
+
const adcChoice = await p26.select({
|
|
34470
|
+
message: "ADC session detected. What do you want to do?",
|
|
34471
|
+
options: [
|
|
34472
|
+
{ value: "use", label: "Use current ADC session" },
|
|
34473
|
+
{ value: "switch", label: "Switch Google account (revoke and re-login)" },
|
|
34474
|
+
{ value: "cancel", label: "Cancel" }
|
|
34475
|
+
]
|
|
34476
|
+
});
|
|
34477
|
+
if (p26.isCancel(adcChoice) || adcChoice === "cancel") return null;
|
|
34478
|
+
if (adcChoice === "switch") {
|
|
34479
|
+
const revokeSpinner = p26.spinner();
|
|
34480
|
+
revokeSpinner.start("Revoking current gcloud ADC session...");
|
|
34481
|
+
const revoked = await runGcloudADCRevoke();
|
|
34482
|
+
revokeSpinner.stop(
|
|
34483
|
+
revoked ? "Current ADC session revoked" : "Could not revoke current ADC session"
|
|
34484
|
+
);
|
|
34485
|
+
if (!revoked) {
|
|
34486
|
+
p26.log.error("Could not revoke gcloud ADC from Coco.");
|
|
34487
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke"));
|
|
34488
|
+
console.log();
|
|
34489
|
+
return null;
|
|
34490
|
+
}
|
|
34491
|
+
const loginSpinner = p26.spinner();
|
|
34492
|
+
loginSpinner.start("Running `gcloud auth application-default login`...");
|
|
34493
|
+
const loginOk = await runGcloudADCLogin();
|
|
34494
|
+
loginSpinner.stop(loginOk ? "gcloud login flow completed" : "gcloud login flow failed");
|
|
34495
|
+
if (!loginOk) return null;
|
|
34496
|
+
const recheckSpinner = p26.spinner();
|
|
34497
|
+
recheckSpinner.start("Verifying ADC credentials after re-login...");
|
|
34498
|
+
adc = await inspectADC();
|
|
34499
|
+
recheckSpinner.stop(
|
|
34500
|
+
adc.status === "ok" && adc.token ? "ADC credentials verified" : "ADC verification failed after re-login"
|
|
34501
|
+
);
|
|
34502
|
+
if (!(adc.status === "ok" && adc.token)) return null;
|
|
34503
|
+
}
|
|
34295
34504
|
p26.log.success("Authentication verified");
|
|
34296
34505
|
const vertexSettings2 = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
34297
34506
|
if (provider.id === "vertex" && !vertexSettings2) return null;
|
|
@@ -34318,9 +34527,17 @@ async function setupGcloudADC(provider) {
|
|
|
34318
34527
|
if (p26.isCancel(runLoginNow)) return null;
|
|
34319
34528
|
if (runLoginNow) {
|
|
34320
34529
|
p26.log.step("Running `gcloud auth application-default login`...");
|
|
34530
|
+
const loginSpinner = p26.spinner();
|
|
34531
|
+
loginSpinner.start("Launching gcloud login flow (browser may open)...");
|
|
34321
34532
|
const loginOk = await runGcloudADCLogin();
|
|
34533
|
+
loginSpinner.stop(loginOk ? "gcloud login flow completed" : "gcloud login flow failed");
|
|
34322
34534
|
if (loginOk) {
|
|
34535
|
+
const recheckSpinner = p26.spinner();
|
|
34536
|
+
recheckSpinner.start("Verifying ADC credentials after login...");
|
|
34323
34537
|
adc = await inspectADC();
|
|
34538
|
+
recheckSpinner.stop(
|
|
34539
|
+
adc.status === "ok" && adc.token ? "ADC credentials verified" : "ADC verification failed after login"
|
|
34540
|
+
);
|
|
34324
34541
|
if (adc.status === "ok" && adc.token) {
|
|
34325
34542
|
console.log(chalk.green(" \u2713 gcloud ADC is now configured."));
|
|
34326
34543
|
console.log();
|
|
@@ -34382,6 +34599,19 @@ async function setupGcloudADC(provider) {
|
|
|
34382
34599
|
async function promptVertexSettings() {
|
|
34383
34600
|
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
34384
34601
|
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
34602
|
+
console.log(chalk.dim("\n Need help finding these values?"));
|
|
34603
|
+
console.log(chalk.cyan(" $ gcloud projects list"));
|
|
34604
|
+
console.log(chalk.cyan(" $ gcloud config set project <PROJECT_ID>"));
|
|
34605
|
+
console.log(chalk.cyan(" $ gcloud config get-value project"));
|
|
34606
|
+
console.log(chalk.cyan(" $ gcloud config get-value compute/region"));
|
|
34607
|
+
console.log(
|
|
34608
|
+
chalk.cyan(" $ gcloud config set compute/region <LOCATION> # e.g. global, europe-west1")
|
|
34609
|
+
);
|
|
34610
|
+
console.log(
|
|
34611
|
+
chalk.dim(
|
|
34612
|
+
" (If compute/region is unset, set it as above, then use that value for Vertex location)\n"
|
|
34613
|
+
)
|
|
34614
|
+
);
|
|
34385
34615
|
const project = await p26.text({
|
|
34386
34616
|
message: "Google Cloud project ID:",
|
|
34387
34617
|
placeholder: projectDefault || "my-gcp-project",
|
|
@@ -35445,12 +35675,27 @@ async function switchProvider(initialProvider, session) {
|
|
|
35445
35675
|
const apiKey = supportsApiKey ? process.env[newProvider.envVar] : void 0;
|
|
35446
35676
|
const hasOAuth = supportsOAuth(newProvider.id) || newProvider.supportsOAuth;
|
|
35447
35677
|
const hasGcloudADC = newProvider.supportsGcloudADC;
|
|
35678
|
+
let adcConnected = false;
|
|
35679
|
+
if (hasGcloudADC) {
|
|
35680
|
+
try {
|
|
35681
|
+
const adc = await inspectADC();
|
|
35682
|
+
adcConnected = adc.status === "ok" && adc.token !== null;
|
|
35683
|
+
} catch {
|
|
35684
|
+
adcConnected = false;
|
|
35685
|
+
}
|
|
35686
|
+
}
|
|
35448
35687
|
const oauthProviderName = newProvider.id === "copilot" ? "copilot" : newProvider.id === "gemini" ? "gemini" : "openai";
|
|
35449
35688
|
let oauthConnected = false;
|
|
35450
35689
|
if (hasOAuth) {
|
|
35690
|
+
const oauthCheckSpinner = p26.spinner();
|
|
35691
|
+
oauthCheckSpinner.start("Checking existing OAuth session...");
|
|
35451
35692
|
try {
|
|
35452
35693
|
oauthConnected = await isOAuthConfigured(oauthProviderName);
|
|
35694
|
+
oauthCheckSpinner.stop(
|
|
35695
|
+
oauthConnected ? "Existing OAuth session found" : "No existing OAuth session"
|
|
35696
|
+
);
|
|
35453
35697
|
} catch {
|
|
35698
|
+
oauthCheckSpinner.stop("Could not verify OAuth session");
|
|
35454
35699
|
}
|
|
35455
35700
|
}
|
|
35456
35701
|
{
|
|
@@ -35486,8 +35731,8 @@ async function switchProvider(initialProvider, session) {
|
|
|
35486
35731
|
if (hasGcloudADC) {
|
|
35487
35732
|
authOptions.push({
|
|
35488
35733
|
value: "gcloud",
|
|
35489
|
-
label: "\u2601\uFE0F Use gcloud ADC",
|
|
35490
|
-
hint: "Authenticate via gcloud CLI"
|
|
35734
|
+
label: adcConnected ? "\u2601\uFE0F Use gcloud ADC (configured \u2713)" : "\u2601\uFE0F Use gcloud ADC",
|
|
35735
|
+
hint: adcConnected ? "Reuse current ADC session or switch account" : "Authenticate via gcloud CLI"
|
|
35491
35736
|
});
|
|
35492
35737
|
}
|
|
35493
35738
|
if (supportsApiKey) {
|
|
@@ -35505,7 +35750,7 @@ async function switchProvider(initialProvider, session) {
|
|
|
35505
35750
|
});
|
|
35506
35751
|
}
|
|
35507
35752
|
}
|
|
35508
|
-
if (oauthConnected || apiKey) {
|
|
35753
|
+
if (oauthConnected || apiKey || adcConnected) {
|
|
35509
35754
|
authOptions.push({
|
|
35510
35755
|
value: "remove",
|
|
35511
35756
|
label: "\u{1F5D1}\uFE0F Remove saved credentials",
|
|
@@ -35517,159 +35762,103 @@ async function switchProvider(initialProvider, session) {
|
|
|
35517
35762
|
label: "\u274C Cancel",
|
|
35518
35763
|
hint: ""
|
|
35519
35764
|
});
|
|
35765
|
+
let authChoice;
|
|
35520
35766
|
if (authOptions.length > 2) {
|
|
35521
|
-
const
|
|
35767
|
+
const selected = await p26.select({
|
|
35522
35768
|
message: `How would you like to authenticate with ${newProvider.name}?`,
|
|
35523
35769
|
options: authOptions
|
|
35524
35770
|
});
|
|
35525
|
-
if (p26.isCancel(
|
|
35771
|
+
if (p26.isCancel(selected) || selected === "cancel") {
|
|
35526
35772
|
return false;
|
|
35527
35773
|
}
|
|
35528
|
-
|
|
35529
|
-
|
|
35530
|
-
|
|
35531
|
-
|
|
35532
|
-
|
|
35533
|
-
|
|
35774
|
+
authChoice = selected;
|
|
35775
|
+
} else {
|
|
35776
|
+
authChoice = authOptions.find((option) => option.value !== "cancel")?.value ?? "cancel";
|
|
35777
|
+
if (authChoice === "cancel") return false;
|
|
35778
|
+
}
|
|
35779
|
+
if (authChoice === "oauth") {
|
|
35780
|
+
const isCopilot = newProvider.id === "copilot";
|
|
35781
|
+
const isGemini = newProvider.id === "gemini";
|
|
35782
|
+
if (isCopilot) {
|
|
35783
|
+
if (oauthConnected) {
|
|
35784
|
+
console.log(chalk.dim(`
|
|
35534
35785
|
Using existing GitHub session...`));
|
|
35535
|
-
} else {
|
|
35536
|
-
const result = await runOAuthFlow("copilot");
|
|
35537
|
-
if (!result) return false;
|
|
35538
|
-
}
|
|
35539
|
-
selectedAuthMethod = "oauth";
|
|
35540
35786
|
} else {
|
|
35541
|
-
const
|
|
35542
|
-
|
|
35543
|
-
|
|
35544
|
-
|
|
35545
|
-
|
|
35546
|
-
|
|
35547
|
-
|
|
35548
|
-
|
|
35549
|
-
|
|
35787
|
+
const oauthStartSpinner = p26.spinner();
|
|
35788
|
+
oauthStartSpinner.start("Starting GitHub OAuth sign-in...");
|
|
35789
|
+
const result = await runOAuthFlow("copilot");
|
|
35790
|
+
oauthStartSpinner.stop(
|
|
35791
|
+
result ? "GitHub OAuth sign-in completed" : "GitHub OAuth sign-in cancelled"
|
|
35792
|
+
);
|
|
35793
|
+
if (!result) return false;
|
|
35794
|
+
}
|
|
35795
|
+
selectedAuthMethod = "oauth";
|
|
35796
|
+
} else {
|
|
35797
|
+
const tokenEnvVar = isGemini ? "GEMINI_OAUTH_TOKEN" : "OPENAI_CODEX_TOKEN";
|
|
35798
|
+
if (oauthConnected) {
|
|
35799
|
+
const refreshSpinner = p26.spinner();
|
|
35800
|
+
refreshSpinner.start("Refreshing existing OAuth session...");
|
|
35801
|
+
try {
|
|
35802
|
+
const tokenResult = await getOrRefreshOAuthToken(oauthProviderName);
|
|
35803
|
+
if (tokenResult) {
|
|
35804
|
+
process.env[tokenEnvVar] = tokenResult.accessToken;
|
|
35805
|
+
selectedAuthMethod = "oauth";
|
|
35806
|
+
if (!isGemini) internalProviderId = "codex";
|
|
35807
|
+
refreshSpinner.stop("OAuth session ready");
|
|
35808
|
+
console.log(chalk.dim(`
|
|
35550
35809
|
Using existing OAuth session...`));
|
|
35551
|
-
|
|
35552
|
-
|
|
35553
|
-
|
|
35554
|
-
|
|
35555
|
-
selectedAuthMethod = "oauth";
|
|
35556
|
-
if (!isGemini) internalProviderId = "codex";
|
|
35557
|
-
}
|
|
35558
|
-
} catch {
|
|
35810
|
+
} else {
|
|
35811
|
+
refreshSpinner.stop("OAuth refresh failed, re-authentication required");
|
|
35812
|
+
const oauthStartSpinner = p26.spinner();
|
|
35813
|
+
oauthStartSpinner.start("Starting OAuth sign-in...");
|
|
35559
35814
|
const result = await runOAuthFlow(newProvider.id);
|
|
35815
|
+
oauthStartSpinner.stop(
|
|
35816
|
+
result ? "OAuth sign-in completed" : "OAuth sign-in cancelled"
|
|
35817
|
+
);
|
|
35560
35818
|
if (!result) return false;
|
|
35561
35819
|
process.env[tokenEnvVar] = result.accessToken;
|
|
35562
35820
|
selectedAuthMethod = "oauth";
|
|
35563
35821
|
if (!isGemini) internalProviderId = "codex";
|
|
35564
35822
|
}
|
|
35565
|
-
}
|
|
35823
|
+
} catch {
|
|
35824
|
+
refreshSpinner.stop("OAuth refresh failed, re-authentication required");
|
|
35825
|
+
const oauthStartSpinner = p26.spinner();
|
|
35826
|
+
oauthStartSpinner.start("Starting OAuth sign-in...");
|
|
35566
35827
|
const result = await runOAuthFlow(newProvider.id);
|
|
35828
|
+
oauthStartSpinner.stop(result ? "OAuth sign-in completed" : "OAuth sign-in cancelled");
|
|
35567
35829
|
if (!result) return false;
|
|
35568
35830
|
process.env[tokenEnvVar] = result.accessToken;
|
|
35569
35831
|
selectedAuthMethod = "oauth";
|
|
35570
35832
|
if (!isGemini) internalProviderId = "codex";
|
|
35571
35833
|
}
|
|
35572
|
-
}
|
|
35573
|
-
} else if (authChoice === "gcloud") {
|
|
35574
|
-
const adcResult = await setupGcloudADCForProvider();
|
|
35575
|
-
if (!adcResult) return false;
|
|
35576
|
-
selectedAuthMethod = "gcloud";
|
|
35577
|
-
if (newProvider.id === "vertex") {
|
|
35578
|
-
const settings = await promptVertexSettings2({
|
|
35579
|
-
project: session.config.provider.project,
|
|
35580
|
-
location: session.config.provider.location
|
|
35581
|
-
});
|
|
35582
|
-
if (!settings) return false;
|
|
35583
|
-
vertexSettings = settings;
|
|
35584
|
-
}
|
|
35585
|
-
} else if (authChoice === "apikey") {
|
|
35586
|
-
if (apiKey) {
|
|
35587
|
-
selectedAuthMethod = "apikey";
|
|
35588
|
-
console.log(chalk.dim(`
|
|
35589
|
-
Using existing API key...`));
|
|
35590
35834
|
} else {
|
|
35591
|
-
const
|
|
35592
|
-
|
|
35593
|
-
|
|
35594
|
-
|
|
35595
|
-
if (
|
|
35596
|
-
|
|
35597
|
-
|
|
35598
|
-
|
|
35599
|
-
selectedAuthMethod = "apikey";
|
|
35600
|
-
newApiKeyForSaving = key;
|
|
35601
|
-
}
|
|
35602
|
-
if (newProvider.id === "vertex") {
|
|
35603
|
-
const settings = await promptVertexSettings2({
|
|
35604
|
-
project: session.config.provider.project,
|
|
35605
|
-
location: session.config.provider.location
|
|
35606
|
-
});
|
|
35607
|
-
if (!settings) return false;
|
|
35608
|
-
vertexSettings = settings;
|
|
35609
|
-
}
|
|
35610
|
-
} else if (authChoice === "remove") {
|
|
35611
|
-
const removeOptions = [];
|
|
35612
|
-
if (oauthConnected) {
|
|
35613
|
-
removeOptions.push({
|
|
35614
|
-
value: "oauth",
|
|
35615
|
-
label: "\u{1F510} Remove OAuth session"
|
|
35616
|
-
});
|
|
35617
|
-
}
|
|
35618
|
-
if (apiKey) {
|
|
35619
|
-
removeOptions.push({
|
|
35620
|
-
value: "apikey",
|
|
35621
|
-
label: "\u{1F511} Remove API key"
|
|
35622
|
-
});
|
|
35623
|
-
}
|
|
35624
|
-
if (oauthConnected && apiKey) {
|
|
35625
|
-
removeOptions.push({
|
|
35626
|
-
value: "all",
|
|
35627
|
-
label: "\u{1F5D1}\uFE0F Remove all credentials"
|
|
35628
|
-
});
|
|
35835
|
+
const oauthStartSpinner = p26.spinner();
|
|
35836
|
+
oauthStartSpinner.start("Starting OAuth sign-in...");
|
|
35837
|
+
const result = await runOAuthFlow(newProvider.id);
|
|
35838
|
+
oauthStartSpinner.stop(result ? "OAuth sign-in completed" : "OAuth sign-in cancelled");
|
|
35839
|
+
if (!result) return false;
|
|
35840
|
+
process.env[tokenEnvVar] = result.accessToken;
|
|
35841
|
+
selectedAuthMethod = "oauth";
|
|
35842
|
+
if (!isGemini) internalProviderId = "codex";
|
|
35629
35843
|
}
|
|
35630
|
-
|
|
35631
|
-
|
|
35632
|
-
|
|
35633
|
-
|
|
35634
|
-
|
|
35635
|
-
|
|
35636
|
-
|
|
35844
|
+
}
|
|
35845
|
+
} else if (authChoice === "gcloud") {
|
|
35846
|
+
const adcResult = await setupGcloudADCForProvider();
|
|
35847
|
+
if (!adcResult) return false;
|
|
35848
|
+
selectedAuthMethod = "gcloud";
|
|
35849
|
+
if (newProvider.id === "vertex") {
|
|
35850
|
+
const settings = await promptVertexSettings2({
|
|
35851
|
+
project: session.config.provider.project,
|
|
35852
|
+
location: session.config.provider.location
|
|
35637
35853
|
});
|
|
35638
|
-
if (
|
|
35639
|
-
|
|
35640
|
-
}
|
|
35641
|
-
if (removeChoice === "oauth" || removeChoice === "all") {
|
|
35642
|
-
if (oauthProviderName === "copilot") {
|
|
35643
|
-
await deleteCopilotCredentials();
|
|
35644
|
-
} else {
|
|
35645
|
-
await deleteTokens(oauthProviderName);
|
|
35646
|
-
}
|
|
35647
|
-
await clearAuthMethod(newProvider.id);
|
|
35648
|
-
console.log(chalk.green("\u2713 OAuth session removed"));
|
|
35649
|
-
}
|
|
35650
|
-
if (removeChoice === "apikey" || removeChoice === "all") {
|
|
35651
|
-
delete process.env[newProvider.envVar];
|
|
35652
|
-
console.log(chalk.green("\u2713 API key removed from session"));
|
|
35653
|
-
console.log(chalk.dim(` Note: If key is in ~/.coco/.env, remove it there too`));
|
|
35654
|
-
}
|
|
35655
|
-
console.log("");
|
|
35656
|
-
return false;
|
|
35854
|
+
if (!settings) return false;
|
|
35855
|
+
vertexSettings = settings;
|
|
35657
35856
|
}
|
|
35658
|
-
} else {
|
|
35659
|
-
|
|
35660
|
-
|
|
35661
|
-
|
|
35662
|
-
|
|
35663
|
-
if (!adcResult) return false;
|
|
35664
|
-
selectedAuthMethod = "gcloud";
|
|
35665
|
-
if (newProvider.id === "vertex") {
|
|
35666
|
-
const settings = await promptVertexSettings2({
|
|
35667
|
-
project: session.config.provider.project,
|
|
35668
|
-
location: session.config.provider.location
|
|
35669
|
-
});
|
|
35670
|
-
if (!settings) return false;
|
|
35671
|
-
vertexSettings = settings;
|
|
35672
|
-
}
|
|
35857
|
+
} else if (authChoice === "apikey") {
|
|
35858
|
+
if (apiKey) {
|
|
35859
|
+
selectedAuthMethod = "apikey";
|
|
35860
|
+
console.log(chalk.dim(`
|
|
35861
|
+
Using existing API key...`));
|
|
35673
35862
|
} else {
|
|
35674
35863
|
const key = await p26.password({
|
|
35675
35864
|
message: `Enter your ${newProvider.name} API key:`,
|
|
@@ -35682,18 +35871,93 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35682
35871
|
selectedAuthMethod = "apikey";
|
|
35683
35872
|
newApiKeyForSaving = key;
|
|
35684
35873
|
}
|
|
35874
|
+
if (newProvider.id === "vertex") {
|
|
35875
|
+
const settings = await promptVertexSettings2({
|
|
35876
|
+
project: session.config.provider.project,
|
|
35877
|
+
location: session.config.provider.location
|
|
35878
|
+
});
|
|
35879
|
+
if (!settings) return false;
|
|
35880
|
+
vertexSettings = settings;
|
|
35881
|
+
}
|
|
35882
|
+
} else if (authChoice === "remove") {
|
|
35883
|
+
const removeOptions = [];
|
|
35884
|
+
if (oauthConnected) {
|
|
35885
|
+
removeOptions.push({
|
|
35886
|
+
value: "oauth",
|
|
35887
|
+
label: "\u{1F510} Remove OAuth session"
|
|
35888
|
+
});
|
|
35889
|
+
}
|
|
35890
|
+
if (apiKey) {
|
|
35891
|
+
removeOptions.push({
|
|
35892
|
+
value: "apikey",
|
|
35893
|
+
label: "\u{1F511} Remove API key"
|
|
35894
|
+
});
|
|
35895
|
+
}
|
|
35896
|
+
if (adcConnected) {
|
|
35897
|
+
removeOptions.push({
|
|
35898
|
+
value: "gcloud",
|
|
35899
|
+
label: "\u2601\uFE0F Revoke gcloud ADC session"
|
|
35900
|
+
});
|
|
35901
|
+
}
|
|
35902
|
+
if (oauthConnected && apiKey || adcConnected && (oauthConnected || apiKey)) {
|
|
35903
|
+
removeOptions.push({
|
|
35904
|
+
value: "all",
|
|
35905
|
+
label: "\u{1F5D1}\uFE0F Remove all credentials"
|
|
35906
|
+
});
|
|
35907
|
+
}
|
|
35908
|
+
removeOptions.push({
|
|
35909
|
+
value: "cancel",
|
|
35910
|
+
label: "\u274C Cancel"
|
|
35911
|
+
});
|
|
35912
|
+
const removeChoice = await p26.select({
|
|
35913
|
+
message: "What would you like to remove?",
|
|
35914
|
+
options: removeOptions
|
|
35915
|
+
});
|
|
35916
|
+
if (p26.isCancel(removeChoice) || removeChoice === "cancel") {
|
|
35917
|
+
return false;
|
|
35918
|
+
}
|
|
35919
|
+
if (removeChoice === "oauth" || removeChoice === "all") {
|
|
35920
|
+
if (oauthProviderName === "copilot") {
|
|
35921
|
+
await deleteCopilotCredentials();
|
|
35922
|
+
} else {
|
|
35923
|
+
await deleteTokens(oauthProviderName);
|
|
35924
|
+
}
|
|
35925
|
+
await clearAuthMethod(newProvider.id);
|
|
35926
|
+
console.log(chalk.green("\u2713 OAuth session removed"));
|
|
35927
|
+
}
|
|
35928
|
+
if (removeChoice === "apikey" || removeChoice === "all") {
|
|
35929
|
+
delete process.env[newProvider.envVar];
|
|
35930
|
+
console.log(chalk.green("\u2713 API key removed from session"));
|
|
35931
|
+
console.log(chalk.dim(` Note: If key is in ~/.coco/.env, remove it there too`));
|
|
35932
|
+
}
|
|
35933
|
+
if (removeChoice === "gcloud" || removeChoice === "all") {
|
|
35934
|
+
const revokeSpinner = p26.spinner();
|
|
35935
|
+
revokeSpinner.start("Revoking gcloud ADC session...");
|
|
35936
|
+
const revoked = await runGcloudADCRevoke();
|
|
35937
|
+
revokeSpinner.stop(revoked ? "gcloud ADC session revoked" : "Failed to revoke gcloud ADC");
|
|
35938
|
+
if (!revoked) {
|
|
35939
|
+
console.log(chalk.yellow("\u26A0\uFE0F Could not revoke ADC from Coco."));
|
|
35940
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke"));
|
|
35941
|
+
} else {
|
|
35942
|
+
console.log(chalk.green("\u2713 gcloud ADC session revoked"));
|
|
35943
|
+
}
|
|
35944
|
+
}
|
|
35945
|
+
console.log("");
|
|
35946
|
+
return false;
|
|
35685
35947
|
}
|
|
35686
35948
|
}
|
|
35687
35949
|
const rememberedModel = await getLastUsedModel(newProvider.id);
|
|
35688
35950
|
const recommendedModel = getRecommendedModel(newProvider.id);
|
|
35689
35951
|
const newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
|
|
35952
|
+
const resolvedVertexProject = newProvider.id === "vertex" ? (vertexSettings?.project ?? session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "").trim() : void 0;
|
|
35953
|
+
const resolvedVertexLocation = newProvider.id === "vertex" ? (vertexSettings?.location ?? session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global").trim() : void 0;
|
|
35690
35954
|
const spinner18 = p26.spinner();
|
|
35691
35955
|
spinner18.start(`Connecting to ${newProvider.name}...`);
|
|
35692
35956
|
try {
|
|
35693
35957
|
const testProvider = await createProvider(internalProviderId, {
|
|
35694
35958
|
model: newModel,
|
|
35695
|
-
project:
|
|
35696
|
-
location:
|
|
35959
|
+
project: resolvedVertexProject,
|
|
35960
|
+
location: resolvedVertexLocation
|
|
35697
35961
|
});
|
|
35698
35962
|
const available = await testProvider.isAvailable();
|
|
35699
35963
|
if (!available) {
|
|
@@ -35707,8 +35971,14 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35707
35971
|
session.config.provider.type = userFacingProviderId;
|
|
35708
35972
|
session.config.provider.model = newModel;
|
|
35709
35973
|
if (userFacingProviderId === "vertex") {
|
|
35710
|
-
session.config.provider.project =
|
|
35711
|
-
session.config.provider.location =
|
|
35974
|
+
session.config.provider.project = resolvedVertexProject;
|
|
35975
|
+
session.config.provider.location = resolvedVertexLocation;
|
|
35976
|
+
if (resolvedVertexProject) {
|
|
35977
|
+
process.env["VERTEX_PROJECT"] = resolvedVertexProject;
|
|
35978
|
+
}
|
|
35979
|
+
if (resolvedVertexLocation) {
|
|
35980
|
+
process.env["VERTEX_LOCATION"] = resolvedVertexLocation;
|
|
35981
|
+
}
|
|
35712
35982
|
} else {
|
|
35713
35983
|
delete session.config.provider.project;
|
|
35714
35984
|
delete session.config.provider.location;
|
|
@@ -35718,13 +35988,13 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35718
35988
|
type: userFacingProviderId,
|
|
35719
35989
|
model: newModel,
|
|
35720
35990
|
apiKey: newApiKeyForSaving,
|
|
35721
|
-
project:
|
|
35722
|
-
location:
|
|
35991
|
+
project: resolvedVertexProject,
|
|
35992
|
+
location: resolvedVertexLocation
|
|
35723
35993
|
});
|
|
35724
35994
|
} else {
|
|
35725
35995
|
await saveProviderPreference(userFacingProviderId, newModel, {
|
|
35726
|
-
project:
|
|
35727
|
-
location:
|
|
35996
|
+
project: resolvedVertexProject,
|
|
35997
|
+
location: resolvedVertexLocation
|
|
35728
35998
|
});
|
|
35729
35999
|
}
|
|
35730
36000
|
console.log(chalk.green(`
|
|
@@ -35747,16 +36017,53 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35747
36017
|
return false;
|
|
35748
36018
|
}
|
|
35749
36019
|
async function setupGcloudADCForProvider(_provider) {
|
|
36020
|
+
const gcloudCheckSpinner = p26.spinner();
|
|
36021
|
+
gcloudCheckSpinner.start("Checking gcloud CLI...");
|
|
35750
36022
|
const gcloudInstalled = await isGcloudInstalled();
|
|
36023
|
+
gcloudCheckSpinner.stop(gcloudInstalled ? "gcloud CLI detected" : "gcloud CLI not detected");
|
|
35751
36024
|
if (!gcloudInstalled) {
|
|
35752
36025
|
p26.log.error("gcloud CLI is not installed");
|
|
35753
36026
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install\n"));
|
|
35754
36027
|
return false;
|
|
35755
36028
|
}
|
|
36029
|
+
const adcInspectSpinner = p26.spinner();
|
|
36030
|
+
adcInspectSpinner.start("Checking existing ADC credentials...");
|
|
35756
36031
|
const adc = await inspectADC();
|
|
36032
|
+
adcInspectSpinner.stop(
|
|
36033
|
+
adc.status === "ok" && adc.token ? "ADC credentials found" : "No reusable ADC credentials found"
|
|
36034
|
+
);
|
|
35757
36035
|
if (adc.status === "ok" && adc.token) {
|
|
35758
36036
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
35759
|
-
|
|
36037
|
+
const adcChoice = await p26.select({
|
|
36038
|
+
message: "ADC session detected. What do you want to do?",
|
|
36039
|
+
options: [
|
|
36040
|
+
{
|
|
36041
|
+
value: "use",
|
|
36042
|
+
label: "Use current ADC session"
|
|
36043
|
+
},
|
|
36044
|
+
{
|
|
36045
|
+
value: "switch",
|
|
36046
|
+
label: "Switch Google account (revoke and re-login)"
|
|
36047
|
+
},
|
|
36048
|
+
{
|
|
36049
|
+
value: "cancel",
|
|
36050
|
+
label: "Cancel"
|
|
36051
|
+
}
|
|
36052
|
+
]
|
|
36053
|
+
});
|
|
36054
|
+
if (p26.isCancel(adcChoice) || adcChoice === "cancel") return false;
|
|
36055
|
+
if (adcChoice === "use") return true;
|
|
36056
|
+
const revokeSpinner = p26.spinner();
|
|
36057
|
+
revokeSpinner.start("Revoking current gcloud ADC session...");
|
|
36058
|
+
const revoked = await runGcloudADCRevoke();
|
|
36059
|
+
revokeSpinner.stop(
|
|
36060
|
+
revoked ? "Current ADC session revoked" : "Could not revoke current ADC session"
|
|
36061
|
+
);
|
|
36062
|
+
if (!revoked) {
|
|
36063
|
+
console.log(chalk.yellow("\u26A0\uFE0F Could not revoke ADC from Coco."));
|
|
36064
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke\n"));
|
|
36065
|
+
return false;
|
|
36066
|
+
}
|
|
35760
36067
|
}
|
|
35761
36068
|
console.log(chalk.yellow("\n No reusable gcloud ADC session was found for Coco."));
|
|
35762
36069
|
console.log();
|
|
@@ -35769,9 +36076,17 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35769
36076
|
if (p26.isCancel(runLoginNow)) return false;
|
|
35770
36077
|
if (runLoginNow) {
|
|
35771
36078
|
p26.log.step("Running `gcloud auth application-default login`...");
|
|
36079
|
+
const loginSpinner = p26.spinner();
|
|
36080
|
+
loginSpinner.start("Launching gcloud login flow (browser may open)...");
|
|
35772
36081
|
const loginOk = await runGcloudADCLogin();
|
|
36082
|
+
loginSpinner.stop(loginOk ? "gcloud login flow completed" : "gcloud login flow failed");
|
|
35773
36083
|
if (loginOk) {
|
|
36084
|
+
const recheckSpinner = p26.spinner();
|
|
36085
|
+
recheckSpinner.start("Verifying ADC credentials after login...");
|
|
35774
36086
|
const refreshed = await inspectADC();
|
|
36087
|
+
recheckSpinner.stop(
|
|
36088
|
+
refreshed.status === "ok" && refreshed.token ? "ADC credentials verified" : "ADC verification failed after login"
|
|
36089
|
+
);
|
|
35775
36090
|
if (refreshed.status === "ok" && refreshed.token) {
|
|
35776
36091
|
console.log(chalk.green(" \u2713 gcloud ADC is now configured.\n"));
|
|
35777
36092
|
return true;
|
|
@@ -35794,6 +36109,19 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35794
36109
|
async function promptVertexSettings2(defaults) {
|
|
35795
36110
|
const projectDefault = defaults?.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35796
36111
|
const locationDefault = defaults?.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
36112
|
+
console.log(chalk.dim("\n Need help finding these values?"));
|
|
36113
|
+
console.log(chalk.cyan(" $ gcloud projects list"));
|
|
36114
|
+
console.log(chalk.cyan(" $ gcloud config set project <PROJECT_ID>"));
|
|
36115
|
+
console.log(chalk.cyan(" $ gcloud config get-value project"));
|
|
36116
|
+
console.log(chalk.cyan(" $ gcloud config get-value compute/region"));
|
|
36117
|
+
console.log(
|
|
36118
|
+
chalk.cyan(" $ gcloud config set compute/region <LOCATION> # e.g. global, europe-west1")
|
|
36119
|
+
);
|
|
36120
|
+
console.log(
|
|
36121
|
+
chalk.dim(
|
|
36122
|
+
" (If compute/region is unset, set it as above, then use that value for Vertex location)\n"
|
|
36123
|
+
)
|
|
36124
|
+
);
|
|
35797
36125
|
const project = await p26.text({
|
|
35798
36126
|
message: "Google Cloud project ID:",
|
|
35799
36127
|
placeholder: projectDefault || "my-gcp-project",
|
|
@@ -39044,10 +39372,8 @@ async function revokePath(dirPath, _session) {
|
|
|
39044
39372
|
|
|
39045
39373
|
// src/cli/repl/commands/permissions.ts
|
|
39046
39374
|
init_session();
|
|
39047
|
-
init_paths();
|
|
39048
39375
|
|
|
39049
39376
|
// src/cli/repl/recommended-permissions.ts
|
|
39050
|
-
init_paths();
|
|
39051
39377
|
init_session();
|
|
39052
39378
|
var RECOMMENDED_GLOBAL = [
|
|
39053
39379
|
// ── Coco native tools (read-only) ──
|
|
@@ -39383,100 +39709,94 @@ var RECOMMENDED_DENY = [
|
|
|
39383
39709
|
"bash:eval",
|
|
39384
39710
|
"bash:source"
|
|
39385
39711
|
];
|
|
39386
|
-
function
|
|
39387
|
-
return path39__default.
|
|
39712
|
+
function getProjectPermissionStatePath(projectPath) {
|
|
39713
|
+
return path39__default.join(projectPath, ".coco", "recommended-permissions.json");
|
|
39388
39714
|
}
|
|
39389
|
-
async function
|
|
39715
|
+
async function resolvePermissionScopePath(projectPath) {
|
|
39716
|
+
let resolved = path39__default.resolve(projectPath);
|
|
39390
39717
|
try {
|
|
39391
|
-
|
|
39392
|
-
const config = JSON.parse(content);
|
|
39393
|
-
return {
|
|
39394
|
-
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
39395
|
-
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed,
|
|
39396
|
-
recommendedAllowlistPrompted: config.recommendedAllowlistPrompted,
|
|
39397
|
-
recommendedAllowlistPromptedProjects: config.recommendedAllowlistPromptedProjects,
|
|
39398
|
-
recommendedAllowlistAppliedProjects: config.recommendedAllowlistAppliedProjects,
|
|
39399
|
-
recommendedAllowlistDismissedProjects: config.recommendedAllowlistDismissedProjects
|
|
39400
|
-
};
|
|
39718
|
+
resolved = await fs35__default.realpath(resolved);
|
|
39401
39719
|
} catch {
|
|
39402
|
-
return {};
|
|
39403
39720
|
}
|
|
39404
|
-
|
|
39405
|
-
|
|
39406
|
-
try {
|
|
39407
|
-
let config = {};
|
|
39721
|
+
let current = resolved;
|
|
39722
|
+
while (true) {
|
|
39408
39723
|
try {
|
|
39409
|
-
|
|
39410
|
-
|
|
39724
|
+
await fs35__default.access(path39__default.join(current, ".git"));
|
|
39725
|
+
return current;
|
|
39411
39726
|
} catch {
|
|
39412
39727
|
}
|
|
39413
|
-
|
|
39414
|
-
|
|
39415
|
-
|
|
39416
|
-
} catch {
|
|
39417
|
-
}
|
|
39418
|
-
}
|
|
39419
|
-
function isRecommendedAllowlistAppliedForProject(prefs, projectPath) {
|
|
39420
|
-
const projectKey = getProjectPreferenceKey(projectPath);
|
|
39421
|
-
if (prefs.recommendedAllowlistAppliedProjects?.[projectKey] === true) {
|
|
39422
|
-
return true;
|
|
39423
|
-
}
|
|
39424
|
-
if (prefs.recommendedAllowlistApplied === true && !prefs.recommendedAllowlistAppliedProjects) {
|
|
39425
|
-
return true;
|
|
39728
|
+
const parent = path39__default.dirname(current);
|
|
39729
|
+
if (parent === current) break;
|
|
39730
|
+
current = parent;
|
|
39426
39731
|
}
|
|
39427
|
-
return
|
|
39732
|
+
return resolved;
|
|
39428
39733
|
}
|
|
39429
|
-
function
|
|
39430
|
-
const
|
|
39431
|
-
|
|
39432
|
-
|
|
39433
|
-
|
|
39434
|
-
|
|
39435
|
-
|
|
39734
|
+
async function loadProjectPermissionState(projectPath) {
|
|
39735
|
+
const defaultState = {
|
|
39736
|
+
applied: false,
|
|
39737
|
+
dismissed: false,
|
|
39738
|
+
prompted: false,
|
|
39739
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39740
|
+
};
|
|
39741
|
+
try {
|
|
39742
|
+
const content = await fs35__default.readFile(getProjectPermissionStatePath(projectPath), "utf-8");
|
|
39743
|
+
const parsed = JSON.parse(content);
|
|
39744
|
+
return {
|
|
39745
|
+
applied: parsed.applied ?? defaultState.applied,
|
|
39746
|
+
dismissed: parsed.dismissed ?? defaultState.dismissed,
|
|
39747
|
+
prompted: parsed.prompted ?? defaultState.prompted,
|
|
39748
|
+
updatedAt: parsed.updatedAt ?? defaultState.updatedAt
|
|
39749
|
+
};
|
|
39750
|
+
} catch {
|
|
39751
|
+
return defaultState;
|
|
39436
39752
|
}
|
|
39437
|
-
return false;
|
|
39438
39753
|
}
|
|
39439
|
-
async function
|
|
39754
|
+
async function saveProjectPermissionState(projectPath, update) {
|
|
39440
39755
|
try {
|
|
39441
|
-
|
|
39442
|
-
|
|
39443
|
-
|
|
39444
|
-
|
|
39445
|
-
|
|
39446
|
-
}
|
|
39447
|
-
const projectKey = getProjectPreferenceKey(projectPath);
|
|
39448
|
-
const currentMap = config[key] ?? {};
|
|
39449
|
-
config[key] = {
|
|
39450
|
-
...currentMap,
|
|
39451
|
-
[projectKey]: value
|
|
39756
|
+
const current = await loadProjectPermissionState(projectPath);
|
|
39757
|
+
const next = {
|
|
39758
|
+
...current,
|
|
39759
|
+
...update,
|
|
39760
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39452
39761
|
};
|
|
39453
|
-
|
|
39454
|
-
await fs35__default.
|
|
39762
|
+
const filePath = getProjectPermissionStatePath(projectPath);
|
|
39763
|
+
await fs35__default.mkdir(path39__default.dirname(filePath), { recursive: true });
|
|
39764
|
+
await fs35__default.writeFile(filePath, JSON.stringify(next, null, 2), "utf-8");
|
|
39455
39765
|
} catch {
|
|
39456
39766
|
}
|
|
39457
39767
|
}
|
|
39768
|
+
async function getProjectPermissionState(projectPath) {
|
|
39769
|
+
const scopePath = await resolvePermissionScopePath(projectPath);
|
|
39770
|
+
return loadProjectPermissionState(scopePath);
|
|
39771
|
+
}
|
|
39772
|
+
async function saveProjectPermissionPreference(key, projectPath, value) {
|
|
39773
|
+
const scopePath = await resolvePermissionScopePath(projectPath);
|
|
39774
|
+
if (key === "recommendedAllowlistAppliedProjects") {
|
|
39775
|
+
await saveProjectPermissionState(scopePath, { applied: value });
|
|
39776
|
+
return;
|
|
39777
|
+
}
|
|
39778
|
+
await saveProjectPermissionState(scopePath, { dismissed: value });
|
|
39779
|
+
}
|
|
39458
39780
|
async function shouldShowPermissionSuggestion(projectPath = process.cwd()) {
|
|
39459
|
-
const
|
|
39460
|
-
if (
|
|
39781
|
+
const state = await getProjectPermissionState(projectPath);
|
|
39782
|
+
if (state.dismissed) {
|
|
39461
39783
|
return false;
|
|
39462
39784
|
}
|
|
39463
|
-
if (
|
|
39785
|
+
if (state.applied) {
|
|
39464
39786
|
return false;
|
|
39465
39787
|
}
|
|
39466
39788
|
return true;
|
|
39467
39789
|
}
|
|
39468
39790
|
async function applyRecommendedPermissions(projectPath = process.cwd()) {
|
|
39791
|
+
const scopePath = await resolvePermissionScopePath(projectPath);
|
|
39469
39792
|
for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
|
|
39470
39793
|
await saveTrustedTool(tool, projectPath, false);
|
|
39471
39794
|
}
|
|
39472
|
-
await saveProjectPermissionPreference("recommendedAllowlistAppliedProjects",
|
|
39473
|
-
await saveProjectPermissionPreference(
|
|
39474
|
-
"recommendedAllowlistDismissedProjects",
|
|
39475
|
-
projectPath,
|
|
39476
|
-
false
|
|
39477
|
-
);
|
|
39795
|
+
await saveProjectPermissionPreference("recommendedAllowlistAppliedProjects", scopePath, true);
|
|
39796
|
+
await saveProjectPermissionPreference("recommendedAllowlistDismissedProjects", scopePath, false);
|
|
39478
39797
|
}
|
|
39479
39798
|
async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
39799
|
+
const scopePath = await resolvePermissionScopePath(projectPath);
|
|
39480
39800
|
console.log();
|
|
39481
39801
|
console.log(chalk.magenta.bold(" \u{1F4CB} Recommended Permissions"));
|
|
39482
39802
|
console.log();
|
|
@@ -39487,7 +39807,7 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
|
39487
39807
|
);
|
|
39488
39808
|
console.log(chalk.dim(" \u2022 Deny: sudo, git push, docker push, inline code exec, DNS exfil..."));
|
|
39489
39809
|
console.log();
|
|
39490
|
-
console.log(chalk.dim(" Stored in
|
|
39810
|
+
console.log(chalk.dim(" Stored in .coco/trusted-tools.json \u2014 edit manually or let"));
|
|
39491
39811
|
console.log(chalk.dim(" Coco manage it when you approve actions from the prompt."));
|
|
39492
39812
|
console.log(chalk.dim(" Note: applying here affects only the current project."));
|
|
39493
39813
|
console.log();
|
|
@@ -39508,11 +39828,7 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
|
39508
39828
|
return;
|
|
39509
39829
|
}
|
|
39510
39830
|
if (action === "dismiss") {
|
|
39511
|
-
await saveProjectPermissionPreference(
|
|
39512
|
-
"recommendedAllowlistDismissedProjects",
|
|
39513
|
-
projectPath,
|
|
39514
|
-
true
|
|
39515
|
-
);
|
|
39831
|
+
await saveProjectPermissionPreference("recommendedAllowlistDismissedProjects", scopePath, true);
|
|
39516
39832
|
console.log(chalk.dim(" Won't show again. Use /permissions to apply later."));
|
|
39517
39833
|
return;
|
|
39518
39834
|
}
|
|
@@ -39612,12 +39928,12 @@ var permissionsCommand = {
|
|
|
39612
39928
|
};
|
|
39613
39929
|
async function showStatus(session) {
|
|
39614
39930
|
const tools = await getAllTrustedTools(session.projectPath);
|
|
39615
|
-
const
|
|
39931
|
+
const permissionState = await getProjectPermissionState(session.projectPath);
|
|
39616
39932
|
console.log();
|
|
39617
39933
|
console.log(chalk.magenta.bold(" \u{1F510} Tool Permissions"));
|
|
39618
39934
|
console.log();
|
|
39619
39935
|
const allowCount = RECOMMENDED_GLOBAL.length + RECOMMENDED_PROJECT.length;
|
|
39620
|
-
if (
|
|
39936
|
+
if (permissionState.applied) {
|
|
39621
39937
|
console.log(
|
|
39622
39938
|
chalk.green(" \u2713 Recommended allowlist applied") + chalk.dim(` (${allowCount} allow, ${RECOMMENDED_DENY.length} deny)`)
|
|
39623
39939
|
);
|
|
@@ -39698,25 +40014,26 @@ async function resetPermissions(session) {
|
|
|
39698
40014
|
return;
|
|
39699
40015
|
}
|
|
39700
40016
|
session.trustedTools.clear();
|
|
39701
|
-
const
|
|
39702
|
-
|
|
39703
|
-
|
|
39704
|
-
projectDenied: {},
|
|
40017
|
+
const emptyProjectSettings = {
|
|
40018
|
+
trusted: [],
|
|
40019
|
+
denied: [],
|
|
39705
40020
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39706
40021
|
};
|
|
39707
40022
|
try {
|
|
39708
|
-
|
|
40023
|
+
const projectTrustPath = `${session.projectPath}/.coco/trusted-tools.json`;
|
|
40024
|
+
await fs35__default.mkdir(`${session.projectPath}/.coco`, { recursive: true });
|
|
40025
|
+
await fs35__default.writeFile(projectTrustPath, JSON.stringify(emptyProjectSettings, null, 2), "utf-8");
|
|
39709
40026
|
} catch {
|
|
39710
40027
|
}
|
|
39711
|
-
|
|
40028
|
+
const permissionScopePath = session.projectPath;
|
|
39712
40029
|
await saveProjectPermissionPreference(
|
|
39713
40030
|
"recommendedAllowlistAppliedProjects",
|
|
39714
|
-
|
|
40031
|
+
permissionScopePath,
|
|
39715
40032
|
false
|
|
39716
40033
|
);
|
|
39717
40034
|
await saveProjectPermissionPreference(
|
|
39718
40035
|
"recommendedAllowlistDismissedProjects",
|
|
39719
|
-
|
|
40036
|
+
permissionScopePath,
|
|
39720
40037
|
false
|
|
39721
40038
|
);
|
|
39722
40039
|
console.log(chalk.green(" \u2713 All tool permissions reset."));
|
|
@@ -43258,7 +43575,8 @@ var AgentManager = class extends EventEmitter {
|
|
|
43258
43575
|
type: "tool_use",
|
|
43259
43576
|
id: tc.id,
|
|
43260
43577
|
name: tc.name,
|
|
43261
|
-
input: tc.input
|
|
43578
|
+
input: tc.input,
|
|
43579
|
+
geminiThoughtSignature: tc.geminiThoughtSignature
|
|
43262
43580
|
}));
|
|
43263
43581
|
const assistantContent = response.content ? [{ type: "text", text: response.content }, ...toolUses] : toolUses;
|
|
43264
43582
|
messages.push({ role: "assistant", content: assistantContent });
|
|
@@ -49171,7 +49489,7 @@ function buildProgressBar(pct) {
|
|
|
49171
49489
|
|
|
49172
49490
|
// src/cli/repl/worktree/manager.ts
|
|
49173
49491
|
init_logger();
|
|
49174
|
-
var
|
|
49492
|
+
var execFileAsync4 = promisify(execFile);
|
|
49175
49493
|
var WORKTREES_DIR = ".worktrees";
|
|
49176
49494
|
var WorktreeManager = class {
|
|
49177
49495
|
worktrees = /* @__PURE__ */ new Map();
|
|
@@ -49395,7 +49713,7 @@ var WorktreeManager = class {
|
|
|
49395
49713
|
try {
|
|
49396
49714
|
await this.git(["push", "-u", "origin", worktree.branch]);
|
|
49397
49715
|
const title = options.message ?? `Agent: ${worktree.name}`;
|
|
49398
|
-
const { stdout } = await
|
|
49716
|
+
const { stdout } = await execFileAsync4(
|
|
49399
49717
|
"gh",
|
|
49400
49718
|
[
|
|
49401
49719
|
"pr",
|
|
@@ -49421,10 +49739,10 @@ var WorktreeManager = class {
|
|
|
49421
49739
|
}
|
|
49422
49740
|
// ── Helpers ──────────────────────────────────────────────────────
|
|
49423
49741
|
async git(args) {
|
|
49424
|
-
return
|
|
49742
|
+
return execFileAsync4("git", args, { cwd: this.projectRoot });
|
|
49425
49743
|
}
|
|
49426
49744
|
async gitIn(cwd, args) {
|
|
49427
|
-
return
|
|
49745
|
+
return execFileAsync4("git", args, { cwd });
|
|
49428
49746
|
}
|
|
49429
49747
|
async countChangedFiles(branch) {
|
|
49430
49748
|
try {
|
|
@@ -53054,7 +53372,8 @@ ${tail}`;
|
|
|
53054
53372
|
toolCallBuilders.set(id, {
|
|
53055
53373
|
id,
|
|
53056
53374
|
name: toolName,
|
|
53057
|
-
input: {}
|
|
53375
|
+
input: {},
|
|
53376
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
|
|
53058
53377
|
});
|
|
53059
53378
|
if (toolName) {
|
|
53060
53379
|
options.onToolPreparing?.(toolName);
|
|
@@ -53067,14 +53386,16 @@ ${tail}`;
|
|
|
53067
53386
|
const finalToolCall = {
|
|
53068
53387
|
id: builder.id,
|
|
53069
53388
|
name: chunk.toolCall.name ?? builder.name,
|
|
53070
|
-
input: chunk.toolCall.input ?? builder.input
|
|
53389
|
+
input: chunk.toolCall.input ?? builder.input,
|
|
53390
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
|
|
53071
53391
|
};
|
|
53072
53392
|
collectedToolCalls.push(finalToolCall);
|
|
53073
53393
|
} else if (chunk.toolCall.id && chunk.toolCall.name) {
|
|
53074
53394
|
collectedToolCalls.push({
|
|
53075
53395
|
id: chunk.toolCall.id,
|
|
53076
53396
|
name: chunk.toolCall.name,
|
|
53077
|
-
input: chunk.toolCall.input ?? {}
|
|
53397
|
+
input: chunk.toolCall.input ?? {},
|
|
53398
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
|
|
53078
53399
|
});
|
|
53079
53400
|
}
|
|
53080
53401
|
}
|
|
@@ -53173,9 +53494,25 @@ ${tail}`;
|
|
|
53173
53494
|
break;
|
|
53174
53495
|
}
|
|
53175
53496
|
noToolRecoveryAttempts = 0;
|
|
53497
|
+
const dedupedToolCalls = [];
|
|
53498
|
+
const seenToolCallFingerprints = /* @__PURE__ */ new Set();
|
|
53499
|
+
for (const toolCall of collectedToolCalls) {
|
|
53500
|
+
let inputSerialized = "{}";
|
|
53501
|
+
try {
|
|
53502
|
+
inputSerialized = JSON.stringify(toolCall.input ?? {});
|
|
53503
|
+
} catch {
|
|
53504
|
+
inputSerialized = "{}";
|
|
53505
|
+
}
|
|
53506
|
+
const fingerprint = `${toolCall.name}:${inputSerialized}`;
|
|
53507
|
+
if (seenToolCallFingerprints.has(fingerprint)) {
|
|
53508
|
+
continue;
|
|
53509
|
+
}
|
|
53510
|
+
seenToolCallFingerprints.add(fingerprint);
|
|
53511
|
+
dedupedToolCalls.push(toolCall);
|
|
53512
|
+
}
|
|
53176
53513
|
const response = {
|
|
53177
53514
|
content: responseContent,
|
|
53178
|
-
toolCalls:
|
|
53515
|
+
toolCalls: dedupedToolCalls
|
|
53179
53516
|
};
|
|
53180
53517
|
const toolResults = [];
|
|
53181
53518
|
const toolUses = [];
|
|
@@ -53331,7 +53668,8 @@ ${tail}`;
|
|
|
53331
53668
|
type: "tool_use",
|
|
53332
53669
|
id: toolCall.id,
|
|
53333
53670
|
name: toolCall.name,
|
|
53334
|
-
input: toolCall.input
|
|
53671
|
+
input: toolCall.input,
|
|
53672
|
+
geminiThoughtSignature: toolCall.geminiThoughtSignature
|
|
53335
53673
|
});
|
|
53336
53674
|
const declineReason = declinedTools.get(toolCall.id);
|
|
53337
53675
|
if (declineReason) {
|
|
@@ -54115,11 +54453,15 @@ async function startRepl(options = {}) {
|
|
|
54115
54453
|
}
|
|
54116
54454
|
session.config = configured;
|
|
54117
54455
|
const internalProviderId = getInternalProviderId(session.config.provider.type);
|
|
54456
|
+
const initialVertexProject = session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"];
|
|
54457
|
+
const initialVertexLocation = session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"];
|
|
54118
54458
|
let provider;
|
|
54119
54459
|
try {
|
|
54120
54460
|
provider = await createProvider(internalProviderId, {
|
|
54121
54461
|
model: session.config.provider.model || void 0,
|
|
54122
|
-
maxTokens: session.config.provider.maxTokens
|
|
54462
|
+
maxTokens: session.config.provider.maxTokens,
|
|
54463
|
+
project: initialVertexProject,
|
|
54464
|
+
location: initialVertexLocation
|
|
54123
54465
|
});
|
|
54124
54466
|
} catch (error) {
|
|
54125
54467
|
p26.log.error(
|
|
@@ -54504,7 +54846,9 @@ async function startRepl(options = {}) {
|
|
|
54504
54846
|
const newInternalId = getInternalProviderId(session.config.provider.type);
|
|
54505
54847
|
provider = await createProvider(newInternalId, {
|
|
54506
54848
|
model: session.config.provider.model || void 0,
|
|
54507
|
-
maxTokens: session.config.provider.maxTokens
|
|
54849
|
+
maxTokens: session.config.provider.maxTokens,
|
|
54850
|
+
project: session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"],
|
|
54851
|
+
location: session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"]
|
|
54508
54852
|
});
|
|
54509
54853
|
setAgentProvider(provider);
|
|
54510
54854
|
initializeContextManager(session, provider);
|