@corbat-tech/coco 2.27.1 → 2.27.3
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 +887 -696
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +28 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -791,8 +791,8 @@ async function requestDeviceCode(provider) {
|
|
|
791
791
|
}
|
|
792
792
|
const contentType = response.headers.get("content-type") || "";
|
|
793
793
|
if (!contentType.includes("application/json")) {
|
|
794
|
-
const
|
|
795
|
-
if (
|
|
794
|
+
const text15 = await response.text();
|
|
795
|
+
if (text15.includes("<!DOCTYPE") || text15.includes("<html")) {
|
|
796
796
|
throw new Error(
|
|
797
797
|
"OAuth service returned HTML instead of JSON.\n The service may be temporarily unavailable.\n Please use an API key instead, or try again later."
|
|
798
798
|
);
|
|
@@ -2324,13 +2324,20 @@ async function isADCConfigured() {
|
|
|
2324
2324
|
}
|
|
2325
2325
|
async function runGcloudADCLogin() {
|
|
2326
2326
|
try {
|
|
2327
|
-
await execAsync(
|
|
2328
|
-
timeout:
|
|
2329
|
-
//
|
|
2327
|
+
await execAsync(ADC_LOGIN_COMMAND, {
|
|
2328
|
+
timeout: 3e5
|
|
2329
|
+
// 5 minutes for interactive auth
|
|
2330
2330
|
});
|
|
2331
2331
|
return true;
|
|
2332
2332
|
} catch {
|
|
2333
|
-
|
|
2333
|
+
try {
|
|
2334
|
+
await execAsync(`${ADC_LOGIN_COMMAND} --no-launch-browser`, {
|
|
2335
|
+
timeout: 3e5
|
|
2336
|
+
});
|
|
2337
|
+
return true;
|
|
2338
|
+
} catch {
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2334
2341
|
}
|
|
2335
2342
|
}
|
|
2336
2343
|
async function getGeminiADCKey() {
|
|
@@ -2504,7 +2511,7 @@ function getApiKey(provider) {
|
|
|
2504
2511
|
case "gemini":
|
|
2505
2512
|
return process.env["GEMINI_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
2506
2513
|
case "vertex":
|
|
2507
|
-
return
|
|
2514
|
+
return process.env["VERTEX_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
2508
2515
|
case "kimi":
|
|
2509
2516
|
return process.env["KIMI_API_KEY"] ?? process.env["MOONSHOT_API_KEY"];
|
|
2510
2517
|
case "kimi-code":
|
|
@@ -3370,25 +3377,25 @@ var init_anthropic = __esm({
|
|
|
3370
3377
|
*
|
|
3371
3378
|
* This heuristic analyzes the text to provide a better estimate.
|
|
3372
3379
|
*/
|
|
3373
|
-
countTokens(
|
|
3374
|
-
if (!
|
|
3380
|
+
countTokens(text15) {
|
|
3381
|
+
if (!text15) return 0;
|
|
3375
3382
|
const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
|
|
3376
3383
|
const whitespacePattern = /\s/g;
|
|
3377
3384
|
const wordPattern = /\b\w+\b/g;
|
|
3378
|
-
const codeChars = (
|
|
3379
|
-
const whitespace = (
|
|
3380
|
-
const words = (
|
|
3381
|
-
const isCodeLike = codeChars >
|
|
3385
|
+
const codeChars = (text15.match(codePatterns) || []).length;
|
|
3386
|
+
const whitespace = (text15.match(whitespacePattern) || []).length;
|
|
3387
|
+
const words = (text15.match(wordPattern) || []).length;
|
|
3388
|
+
const isCodeLike = codeChars > text15.length * 0.05;
|
|
3382
3389
|
let charsPerToken;
|
|
3383
3390
|
if (isCodeLike) {
|
|
3384
3391
|
charsPerToken = 3.5;
|
|
3385
|
-
} else if (whitespace >
|
|
3392
|
+
} else if (whitespace > text15.length * 0.3) {
|
|
3386
3393
|
charsPerToken = 5;
|
|
3387
3394
|
} else {
|
|
3388
3395
|
charsPerToken = 4.5;
|
|
3389
3396
|
}
|
|
3390
3397
|
const wordBasedEstimate = words * 1.3;
|
|
3391
|
-
const charBasedEstimate =
|
|
3398
|
+
const charBasedEstimate = text15.length / charsPerToken;
|
|
3392
3399
|
return Math.ceil((wordBasedEstimate + charBasedEstimate) / 2);
|
|
3393
3400
|
}
|
|
3394
3401
|
/**
|
|
@@ -3437,8 +3444,8 @@ var init_anthropic = __esm({
|
|
|
3437
3444
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
3438
3445
|
if (!systemMsg) return void 0;
|
|
3439
3446
|
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
3440
|
-
const
|
|
3441
|
-
return
|
|
3447
|
+
const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
3448
|
+
return text15 || void 0;
|
|
3442
3449
|
}
|
|
3443
3450
|
/**
|
|
3444
3451
|
* Convert messages to Anthropic format
|
|
@@ -3626,15 +3633,15 @@ var init_tool_call_normalizer = __esm({
|
|
|
3626
3633
|
if (delta.function?.name) {
|
|
3627
3634
|
builder.name = delta.function.name;
|
|
3628
3635
|
}
|
|
3629
|
-
const
|
|
3630
|
-
if (!
|
|
3631
|
-
builder.arguments +=
|
|
3636
|
+
const text15 = delta.function?.arguments ?? "";
|
|
3637
|
+
if (!text15) return { started };
|
|
3638
|
+
builder.arguments += text15;
|
|
3632
3639
|
return {
|
|
3633
3640
|
started,
|
|
3634
3641
|
argumentDelta: {
|
|
3635
3642
|
id: builder.id,
|
|
3636
3643
|
name: builder.name,
|
|
3637
|
-
text:
|
|
3644
|
+
text: text15
|
|
3638
3645
|
}
|
|
3639
3646
|
};
|
|
3640
3647
|
}
|
|
@@ -4223,23 +4230,23 @@ var init_openai = __esm({
|
|
|
4223
4230
|
* For accurate counting, use the model's native tokenizer.
|
|
4224
4231
|
* This heuristic provides a reasonable estimate without dependencies.
|
|
4225
4232
|
*/
|
|
4226
|
-
countTokens(
|
|
4227
|
-
if (!
|
|
4233
|
+
countTokens(text15) {
|
|
4234
|
+
if (!text15) return 0;
|
|
4228
4235
|
const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
|
|
4229
4236
|
const whitespacePattern = /\s/g;
|
|
4230
4237
|
const wordPattern = /\b\w+\b/g;
|
|
4231
4238
|
const nonAsciiPattern = /[^\x00-\x7F]/g;
|
|
4232
|
-
const codeChars = (
|
|
4233
|
-
const whitespace = (
|
|
4234
|
-
const words = (
|
|
4235
|
-
const nonAscii = (
|
|
4236
|
-
const isCodeLike = codeChars >
|
|
4239
|
+
const codeChars = (text15.match(codePatterns) || []).length;
|
|
4240
|
+
const whitespace = (text15.match(whitespacePattern) || []).length;
|
|
4241
|
+
const words = (text15.match(wordPattern) || []).length;
|
|
4242
|
+
const nonAscii = (text15.match(nonAsciiPattern) || []).length;
|
|
4243
|
+
const isCodeLike = codeChars > text15.length * 0.05;
|
|
4237
4244
|
const isLocal = this.isLocalModel();
|
|
4238
4245
|
let charsPerToken;
|
|
4239
4246
|
if (isLocal) {
|
|
4240
4247
|
if (isCodeLike) {
|
|
4241
4248
|
charsPerToken = 3.2;
|
|
4242
|
-
} else if (nonAscii >
|
|
4249
|
+
} else if (nonAscii > text15.length * 0.1) {
|
|
4243
4250
|
charsPerToken = 2;
|
|
4244
4251
|
} else {
|
|
4245
4252
|
charsPerToken = 3.5;
|
|
@@ -4247,7 +4254,7 @@ var init_openai = __esm({
|
|
|
4247
4254
|
} else {
|
|
4248
4255
|
if (isCodeLike) {
|
|
4249
4256
|
charsPerToken = 3.3;
|
|
4250
|
-
} else if (whitespace >
|
|
4257
|
+
} else if (whitespace > text15.length * 0.3) {
|
|
4251
4258
|
charsPerToken = 4.5;
|
|
4252
4259
|
} else {
|
|
4253
4260
|
charsPerToken = 4;
|
|
@@ -4255,7 +4262,7 @@ var init_openai = __esm({
|
|
|
4255
4262
|
}
|
|
4256
4263
|
const tokensPerWord = isLocal ? 1.4 : 1.3;
|
|
4257
4264
|
const wordBasedEstimate = words * tokensPerWord;
|
|
4258
|
-
const charBasedEstimate =
|
|
4265
|
+
const charBasedEstimate = text15.length / charsPerToken;
|
|
4259
4266
|
const weight = isCodeLike ? 0.7 : 0.5;
|
|
4260
4267
|
return Math.ceil(charBasedEstimate * weight + wordBasedEstimate * (1 - weight));
|
|
4261
4268
|
}
|
|
@@ -5036,8 +5043,8 @@ var init_codex = __esm({
|
|
|
5036
5043
|
* Count tokens in text (approximate)
|
|
5037
5044
|
* Uses GPT-4 approximation: ~4 chars per token
|
|
5038
5045
|
*/
|
|
5039
|
-
countTokens(
|
|
5040
|
-
return Math.ceil(
|
|
5046
|
+
countTokens(text15) {
|
|
5047
|
+
return Math.ceil(text15.length / 4);
|
|
5041
5048
|
}
|
|
5042
5049
|
/**
|
|
5043
5050
|
* Check if provider is available (has valid OAuth tokens)
|
|
@@ -5705,9 +5712,9 @@ var init_copilot2 = __esm({
|
|
|
5705
5712
|
/**
|
|
5706
5713
|
* Count tokens (approximate — Copilot models vary in tokenizer)
|
|
5707
5714
|
*/
|
|
5708
|
-
countTokens(
|
|
5709
|
-
if (!
|
|
5710
|
-
return Math.ceil(
|
|
5715
|
+
countTokens(text15) {
|
|
5716
|
+
if (!text15) return 0;
|
|
5717
|
+
return Math.ceil(text15.length / 3.5);
|
|
5711
5718
|
}
|
|
5712
5719
|
/**
|
|
5713
5720
|
* Get context window for the current model
|
|
@@ -5805,9 +5812,9 @@ var init_gemini = __esm({
|
|
|
5805
5812
|
});
|
|
5806
5813
|
let streamStopReason = "end_turn";
|
|
5807
5814
|
for await (const chunk of stream) {
|
|
5808
|
-
const
|
|
5809
|
-
if (
|
|
5810
|
-
yield { type: "text", text:
|
|
5815
|
+
const text15 = chunk.text;
|
|
5816
|
+
if (text15) {
|
|
5817
|
+
yield { type: "text", text: text15 };
|
|
5811
5818
|
}
|
|
5812
5819
|
const finishReason = chunk.candidates?.[0]?.finishReason;
|
|
5813
5820
|
if (finishReason) {
|
|
@@ -5831,9 +5838,9 @@ var init_gemini = __esm({
|
|
|
5831
5838
|
let fallbackToolCounter = 0;
|
|
5832
5839
|
const emittedToolIds = /* @__PURE__ */ new Set();
|
|
5833
5840
|
for await (const chunk of stream) {
|
|
5834
|
-
const
|
|
5835
|
-
if (
|
|
5836
|
-
yield { type: "text", text:
|
|
5841
|
+
const text15 = chunk.text;
|
|
5842
|
+
if (text15) {
|
|
5843
|
+
yield { type: "text", text: text15 };
|
|
5837
5844
|
}
|
|
5838
5845
|
const functionCalls = this.extractFunctionCalls(chunk);
|
|
5839
5846
|
for (const functionCall of functionCalls) {
|
|
@@ -5869,9 +5876,9 @@ var init_gemini = __esm({
|
|
|
5869
5876
|
throw this.handleError(error);
|
|
5870
5877
|
}
|
|
5871
5878
|
}
|
|
5872
|
-
countTokens(
|
|
5873
|
-
if (!
|
|
5874
|
-
return Math.ceil(
|
|
5879
|
+
countTokens(text15) {
|
|
5880
|
+
if (!text15) return 0;
|
|
5881
|
+
return Math.ceil(text15.length / 3.5);
|
|
5875
5882
|
}
|
|
5876
5883
|
getContextWindow() {
|
|
5877
5884
|
const model = this.config.model ?? DEFAULT_MODEL5;
|
|
@@ -5919,8 +5926,8 @@ var init_gemini = __esm({
|
|
|
5919
5926
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
5920
5927
|
if (!systemMsg) return void 0;
|
|
5921
5928
|
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
5922
|
-
const
|
|
5923
|
-
return
|
|
5929
|
+
const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
5930
|
+
return text15 || void 0;
|
|
5924
5931
|
}
|
|
5925
5932
|
convertContents(messages) {
|
|
5926
5933
|
const toolNameByUseId = this.buildToolUseNameMap(messages);
|
|
@@ -6117,21 +6124,26 @@ var init_vertex = __esm({
|
|
|
6117
6124
|
config = {};
|
|
6118
6125
|
project = "";
|
|
6119
6126
|
location = DEFAULT_LOCATION;
|
|
6127
|
+
apiKey;
|
|
6120
6128
|
retryConfig = DEFAULT_RETRY_CONFIG;
|
|
6121
6129
|
async initialize(config) {
|
|
6122
6130
|
this.config = config;
|
|
6123
6131
|
this.project = config.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
6124
6132
|
this.location = config.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? DEFAULT_LOCATION;
|
|
6133
|
+
this.apiKey = config.apiKey ?? process.env["VERTEX_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
6125
6134
|
if (!this.project.trim()) {
|
|
6126
6135
|
throw new ProviderError(
|
|
6127
6136
|
"Vertex AI project not configured. Set provider.project, VERTEX_PROJECT, or GOOGLE_CLOUD_PROJECT.",
|
|
6128
6137
|
{ provider: this.id }
|
|
6129
6138
|
);
|
|
6130
6139
|
}
|
|
6140
|
+
if (this.apiKey?.trim()) {
|
|
6141
|
+
return;
|
|
6142
|
+
}
|
|
6131
6143
|
const token = await getCachedADCToken();
|
|
6132
6144
|
if (!token) {
|
|
6133
6145
|
throw new ProviderError(
|
|
6134
|
-
"Vertex AI
|
|
6146
|
+
"Vertex AI authentication is not configured. Set VERTEX_API_KEY (or GOOGLE_API_KEY), or run `gcloud auth application-default login`.",
|
|
6135
6147
|
{ provider: this.id }
|
|
6136
6148
|
);
|
|
6137
6149
|
}
|
|
@@ -6212,8 +6224,8 @@ var init_vertex = __esm({
|
|
|
6212
6224
|
}
|
|
6213
6225
|
yield { type: "done", stopReason };
|
|
6214
6226
|
}
|
|
6215
|
-
countTokens(
|
|
6216
|
-
return Math.ceil(
|
|
6227
|
+
countTokens(text15) {
|
|
6228
|
+
return Math.ceil(text15.length / 4);
|
|
6217
6229
|
}
|
|
6218
6230
|
getContextWindow() {
|
|
6219
6231
|
return CONTEXT_WINDOWS6[this.config.model ?? DEFAULT_MODEL6] ?? 1048576;
|
|
@@ -6250,10 +6262,17 @@ var init_vertex = __esm({
|
|
|
6250
6262
|
return `${this.getResolvedBaseUrl()}/projects/${encodeURIComponent(this.project)}/locations/${encodeURIComponent(this.location)}/publishers/google/models/${encodeURIComponent(this.getModel(model))}:${action}`;
|
|
6251
6263
|
}
|
|
6252
6264
|
async getHeaders() {
|
|
6265
|
+
if (this.apiKey?.trim()) {
|
|
6266
|
+
return {
|
|
6267
|
+
"Content-Type": "application/json",
|
|
6268
|
+
"x-goog-api-key": this.apiKey,
|
|
6269
|
+
"x-goog-user-project": this.project
|
|
6270
|
+
};
|
|
6271
|
+
}
|
|
6253
6272
|
const token = await getCachedADCToken();
|
|
6254
6273
|
if (!token) {
|
|
6255
6274
|
throw new ProviderError(
|
|
6256
|
-
"Vertex AI
|
|
6275
|
+
"Vertex AI token is unavailable. Re-authenticate with gcloud or configure VERTEX_API_KEY.",
|
|
6257
6276
|
{ provider: this.id }
|
|
6258
6277
|
);
|
|
6259
6278
|
}
|
|
@@ -6268,8 +6287,8 @@ var init_vertex = __esm({
|
|
|
6268
6287
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
6269
6288
|
if (!systemMsg) return void 0;
|
|
6270
6289
|
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
6271
|
-
const
|
|
6272
|
-
return
|
|
6290
|
+
const text15 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
6291
|
+
return text15 || void 0;
|
|
6273
6292
|
}
|
|
6274
6293
|
buildToolUseNameMap(messages) {
|
|
6275
6294
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -6446,10 +6465,10 @@ var init_vertex = __esm({
|
|
|
6446
6465
|
}
|
|
6447
6466
|
parseResponse(response, model) {
|
|
6448
6467
|
const candidate = response.candidates?.[0];
|
|
6449
|
-
const
|
|
6468
|
+
const text15 = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
|
|
6450
6469
|
return {
|
|
6451
6470
|
id: `vertex-${Date.now()}`,
|
|
6452
|
-
content:
|
|
6471
|
+
content: text15,
|
|
6453
6472
|
stopReason: this.mapFinishReason(candidate?.finishReason),
|
|
6454
6473
|
usage: {
|
|
6455
6474
|
inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
@@ -6835,7 +6854,7 @@ var init_fallback = __esm({
|
|
|
6835
6854
|
*/
|
|
6836
6855
|
async initialize(config) {
|
|
6837
6856
|
const results = await Promise.allSettled(
|
|
6838
|
-
this.providers.map((
|
|
6857
|
+
this.providers.map((p46) => p46.provider.initialize(config))
|
|
6839
6858
|
);
|
|
6840
6859
|
const anySuccess = results.some((r) => r.status === "fulfilled");
|
|
6841
6860
|
if (!anySuccess) {
|
|
@@ -6932,9 +6951,9 @@ var init_fallback = __esm({
|
|
|
6932
6951
|
* @param text - Text to count tokens for
|
|
6933
6952
|
* @returns Estimated token count
|
|
6934
6953
|
*/
|
|
6935
|
-
countTokens(
|
|
6954
|
+
countTokens(text15) {
|
|
6936
6955
|
const provider = this.getCurrentProvider();
|
|
6937
|
-
return provider.provider.countTokens(
|
|
6956
|
+
return provider.provider.countTokens(text15);
|
|
6938
6957
|
}
|
|
6939
6958
|
/**
|
|
6940
6959
|
* Get context window from current provider
|
|
@@ -6957,11 +6976,11 @@ var init_fallback = __esm({
|
|
|
6957
6976
|
*/
|
|
6958
6977
|
async isAvailable() {
|
|
6959
6978
|
const results = await Promise.all(
|
|
6960
|
-
this.providers.map(async (
|
|
6961
|
-
if (
|
|
6979
|
+
this.providers.map(async (p46) => {
|
|
6980
|
+
if (p46.breaker.isOpen()) {
|
|
6962
6981
|
return false;
|
|
6963
6982
|
}
|
|
6964
|
-
return
|
|
6983
|
+
return p46.provider.isAvailable();
|
|
6965
6984
|
})
|
|
6966
6985
|
);
|
|
6967
6986
|
return results.some((available) => available);
|
|
@@ -6992,10 +7011,10 @@ var init_fallback = __esm({
|
|
|
6992
7011
|
* @returns Array of provider status objects
|
|
6993
7012
|
*/
|
|
6994
7013
|
getCircuitStatus() {
|
|
6995
|
-
return this.providers.map((
|
|
6996
|
-
providerId:
|
|
6997
|
-
state:
|
|
6998
|
-
failureCount:
|
|
7014
|
+
return this.providers.map((p46) => ({
|
|
7015
|
+
providerId: p46.provider.id,
|
|
7016
|
+
state: p46.breaker.getState(),
|
|
7017
|
+
failureCount: p46.breaker.getFailureCount()
|
|
6999
7018
|
}));
|
|
7000
7019
|
}
|
|
7001
7020
|
/**
|
|
@@ -7005,8 +7024,8 @@ var init_fallback = __esm({
|
|
|
7005
7024
|
* previously failing providers to be tried again.
|
|
7006
7025
|
*/
|
|
7007
7026
|
resetCircuits() {
|
|
7008
|
-
for (const
|
|
7009
|
-
|
|
7027
|
+
for (const p46 of this.providers) {
|
|
7028
|
+
p46.breaker.reset();
|
|
7010
7029
|
}
|
|
7011
7030
|
}
|
|
7012
7031
|
/**
|
|
@@ -7150,8 +7169,8 @@ var init_resilient = __esm({
|
|
|
7150
7169
|
async *streamWithTools(messages, options) {
|
|
7151
7170
|
yield* this.streamWithPolicy(() => this.provider.streamWithTools(messages, options));
|
|
7152
7171
|
}
|
|
7153
|
-
countTokens(
|
|
7154
|
-
return this.provider.countTokens(
|
|
7172
|
+
countTokens(text15) {
|
|
7173
|
+
return this.provider.countTokens(text15);
|
|
7155
7174
|
}
|
|
7156
7175
|
getContextWindow() {
|
|
7157
7176
|
return this.provider.getContextWindow();
|
|
@@ -8464,8 +8483,8 @@ function tokenOverlap(queryTokens, targetTokens) {
|
|
|
8464
8483
|
}
|
|
8465
8484
|
return hits / queryTokens.length;
|
|
8466
8485
|
}
|
|
8467
|
-
function tokenize(
|
|
8468
|
-
return
|
|
8486
|
+
function tokenize(text15) {
|
|
8487
|
+
return text15.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/[\s-]+/).filter((word) => word.length > 1 && !STOP_WORDS.has(word)).map(stem);
|
|
8469
8488
|
}
|
|
8470
8489
|
function stem(word) {
|
|
8471
8490
|
if (word.length < 4) return word;
|
|
@@ -9562,8 +9581,8 @@ ${tail}`
|
|
|
9562
9581
|
estimateTokens(messages, provider) {
|
|
9563
9582
|
let total = 0;
|
|
9564
9583
|
for (const message of messages) {
|
|
9565
|
-
const
|
|
9566
|
-
total += provider.countTokens(
|
|
9584
|
+
const text15 = this.extractTextContent(message.content);
|
|
9585
|
+
total += provider.countTokens(text15);
|
|
9567
9586
|
}
|
|
9568
9587
|
return total;
|
|
9569
9588
|
}
|
|
@@ -11597,7 +11616,7 @@ function humanizeError(message, toolName) {
|
|
|
11597
11616
|
return msg;
|
|
11598
11617
|
}
|
|
11599
11618
|
function looksLikeTechnicalJargon(message) {
|
|
11600
|
-
return JARGON_PATTERNS.some((
|
|
11619
|
+
return JARGON_PATTERNS.some((p46) => p46.test(message));
|
|
11601
11620
|
}
|
|
11602
11621
|
async function humanizeWithLLM(errorMessage, toolName, provider) {
|
|
11603
11622
|
const prompt = [
|
|
@@ -12358,9 +12377,9 @@ function renderFileBlock(file, opts) {
|
|
|
12358
12377
|
);
|
|
12359
12378
|
}
|
|
12360
12379
|
const pairs = pairAdjacentLines(hunk.lines);
|
|
12361
|
-
const pairedDeleteIndices = new Set(pairs.map((
|
|
12362
|
-
const pairedAddIndices = new Set(pairs.map((
|
|
12363
|
-
const pairByAdd = new Map(pairs.map((
|
|
12380
|
+
const pairedDeleteIndices = new Set(pairs.map((p46) => p46.deleteIdx));
|
|
12381
|
+
const pairedAddIndices = new Set(pairs.map((p46) => p46.addIdx));
|
|
12382
|
+
const pairByAdd = new Map(pairs.map((p46) => [p46.addIdx, p46.deleteIdx]));
|
|
12364
12383
|
const wordHighlights = /* @__PURE__ */ new Map();
|
|
12365
12384
|
for (const pair of pairs) {
|
|
12366
12385
|
const delLine = hunk.lines[pair.deleteIdx];
|
|
@@ -12816,10 +12835,10 @@ var init_coverage = __esm({
|
|
|
12816
12835
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
12817
12836
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
12818
12837
|
];
|
|
12819
|
-
for (const
|
|
12838
|
+
for (const p46 of possiblePaths) {
|
|
12820
12839
|
try {
|
|
12821
|
-
await access(
|
|
12822
|
-
const content = await readFile(
|
|
12840
|
+
await access(p46, constants.R_OK);
|
|
12841
|
+
const content = await readFile(p46, "utf-8");
|
|
12823
12842
|
const report = JSON.parse(content);
|
|
12824
12843
|
return parseCoverageSummary(report);
|
|
12825
12844
|
} catch {
|
|
@@ -18653,15 +18672,15 @@ ${message}
|
|
|
18653
18672
|
let stdoutBuffer = "";
|
|
18654
18673
|
let stderrBuffer = "";
|
|
18655
18674
|
subprocess.stdout?.on("data", (chunk) => {
|
|
18656
|
-
const
|
|
18657
|
-
stdoutBuffer +=
|
|
18658
|
-
process.stdout.write(
|
|
18675
|
+
const text15 = chunk.toString();
|
|
18676
|
+
stdoutBuffer += text15;
|
|
18677
|
+
process.stdout.write(text15);
|
|
18659
18678
|
heartbeat.activity();
|
|
18660
18679
|
});
|
|
18661
18680
|
subprocess.stderr?.on("data", (chunk) => {
|
|
18662
|
-
const
|
|
18663
|
-
stderrBuffer +=
|
|
18664
|
-
process.stderr.write(
|
|
18681
|
+
const text15 = chunk.toString();
|
|
18682
|
+
stderrBuffer += text15;
|
|
18683
|
+
process.stderr.write(text15);
|
|
18665
18684
|
heartbeat.activity();
|
|
18666
18685
|
});
|
|
18667
18686
|
const result = await subprocess;
|
|
@@ -20329,11 +20348,11 @@ async function runMergeRelease(ctx) {
|
|
|
20329
20348
|
}
|
|
20330
20349
|
const tagName = ctx.newVersion ? `v${ctx.newVersion}` : void 0;
|
|
20331
20350
|
const mergeMsg = tagName ? `Merge PR #${ctx.prNumber} to ${ctx.profile.defaultBranch} and create release ${tagName}?` : `Merge PR #${ctx.prNumber} to ${ctx.profile.defaultBranch}?`;
|
|
20332
|
-
const
|
|
20351
|
+
const confirm23 = await p26.confirm({
|
|
20333
20352
|
message: mergeMsg,
|
|
20334
20353
|
initialValue: true
|
|
20335
20354
|
});
|
|
20336
|
-
if (p26.isCancel(
|
|
20355
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
20337
20356
|
return {
|
|
20338
20357
|
step: "merge-release",
|
|
20339
20358
|
status: "skipped",
|
|
@@ -20622,11 +20641,11 @@ function isBlockedPath(absolute) {
|
|
|
20622
20641
|
return void 0;
|
|
20623
20642
|
}
|
|
20624
20643
|
function isBlockedExecFile(filePath) {
|
|
20625
|
-
return BLOCKED_EXEC_PATTERNS.some((
|
|
20644
|
+
return BLOCKED_EXEC_PATTERNS.some((p46) => p46.test(filePath));
|
|
20626
20645
|
}
|
|
20627
20646
|
function hasDangerousArgs(args) {
|
|
20628
20647
|
const joined = args.join(" ");
|
|
20629
|
-
return DANGEROUS_ARG_PATTERNS.some((
|
|
20648
|
+
return DANGEROUS_ARG_PATTERNS.some((p46) => p46.test(joined));
|
|
20630
20649
|
}
|
|
20631
20650
|
function getInterpreter(ext) {
|
|
20632
20651
|
return INTERPRETER_MAP[ext.toLowerCase()];
|
|
@@ -22508,9 +22527,10 @@ var init_lifecycle = __esm({
|
|
|
22508
22527
|
init_errors2();
|
|
22509
22528
|
init_logger();
|
|
22510
22529
|
init_version();
|
|
22511
|
-
MCPServerManager = class {
|
|
22530
|
+
MCPServerManager = class _MCPServerManager {
|
|
22512
22531
|
connections = /* @__PURE__ */ new Map();
|
|
22513
22532
|
logger = getLogger();
|
|
22533
|
+
static STOP_TIMEOUT_MS = 5e3;
|
|
22514
22534
|
/**
|
|
22515
22535
|
* Create transport for a server config
|
|
22516
22536
|
*/
|
|
@@ -22597,7 +22617,15 @@ var init_lifecycle = __esm({
|
|
|
22597
22617
|
}
|
|
22598
22618
|
this.logger.info(`Stopping MCP server: ${name}`);
|
|
22599
22619
|
try {
|
|
22600
|
-
await
|
|
22620
|
+
await Promise.race([
|
|
22621
|
+
connection.transport.disconnect(),
|
|
22622
|
+
new Promise(
|
|
22623
|
+
(_, reject) => setTimeout(
|
|
22624
|
+
() => reject(new Error("MCP disconnect timeout")),
|
|
22625
|
+
_MCPServerManager.STOP_TIMEOUT_MS
|
|
22626
|
+
)
|
|
22627
|
+
)
|
|
22628
|
+
]);
|
|
22601
22629
|
} catch (error) {
|
|
22602
22630
|
this.logger.error(
|
|
22603
22631
|
`Error disconnecting server '${name}': ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -23118,22 +23146,22 @@ var init_types7 = __esm({
|
|
|
23118
23146
|
});
|
|
23119
23147
|
|
|
23120
23148
|
// src/cli/repl/interruptions/classifier.ts
|
|
23121
|
-
function matchPatterns(
|
|
23149
|
+
function matchPatterns(text15, patterns) {
|
|
23122
23150
|
for (let i = 0; i < patterns.length; i++) {
|
|
23123
|
-
if (patterns[i].test(
|
|
23151
|
+
if (patterns[i].test(text15)) {
|
|
23124
23152
|
return 1 - i * 0.1;
|
|
23125
23153
|
}
|
|
23126
23154
|
}
|
|
23127
23155
|
return 0;
|
|
23128
23156
|
}
|
|
23129
23157
|
function classifyInterruption(message) {
|
|
23130
|
-
const
|
|
23131
|
-
const abortConf = matchPatterns(
|
|
23132
|
-
const modifyConf = matchPatterns(
|
|
23133
|
-
const correctConf = matchPatterns(
|
|
23158
|
+
const text15 = message.text;
|
|
23159
|
+
const abortConf = matchPatterns(text15, ABORT_PATTERNS);
|
|
23160
|
+
const modifyConf = matchPatterns(text15, MODIFY_PATTERNS);
|
|
23161
|
+
const correctConf = matchPatterns(text15, CORRECT_PATTERNS);
|
|
23134
23162
|
if (abortConf > 0 && abortConf >= modifyConf && abortConf >= correctConf) {
|
|
23135
23163
|
return {
|
|
23136
|
-
text:
|
|
23164
|
+
text: text15,
|
|
23137
23165
|
type: "abort" /* Abort */,
|
|
23138
23166
|
confidence: Math.min(1, abortConf),
|
|
23139
23167
|
timestamp: message.timestamp
|
|
@@ -23141,7 +23169,7 @@ function classifyInterruption(message) {
|
|
|
23141
23169
|
}
|
|
23142
23170
|
if (modifyConf > 0 && modifyConf >= correctConf) {
|
|
23143
23171
|
return {
|
|
23144
|
-
text:
|
|
23172
|
+
text: text15,
|
|
23145
23173
|
type: "modify" /* Modify */,
|
|
23146
23174
|
confidence: Math.min(1, modifyConf),
|
|
23147
23175
|
timestamp: message.timestamp
|
|
@@ -23149,14 +23177,14 @@ function classifyInterruption(message) {
|
|
|
23149
23177
|
}
|
|
23150
23178
|
if (correctConf > 0) {
|
|
23151
23179
|
return {
|
|
23152
|
-
text:
|
|
23180
|
+
text: text15,
|
|
23153
23181
|
type: "correct" /* Correct */,
|
|
23154
23182
|
confidence: Math.min(1, correctConf),
|
|
23155
23183
|
timestamp: message.timestamp
|
|
23156
23184
|
};
|
|
23157
23185
|
}
|
|
23158
23186
|
return {
|
|
23159
|
-
text:
|
|
23187
|
+
text: text15,
|
|
23160
23188
|
type: "info" /* Info */,
|
|
23161
23189
|
confidence: 0.5,
|
|
23162
23190
|
timestamp: message.timestamp
|
|
@@ -25664,10 +25692,10 @@ function inferTargetUsers(session) {
|
|
|
25664
25692
|
/(?:for|by)\s+(developers?|users?|administrators?|customers?)/gi,
|
|
25665
25693
|
/(developers?|users?|administrators?|customers?)\s+(?:can|will|should)/gi
|
|
25666
25694
|
];
|
|
25667
|
-
const
|
|
25695
|
+
const text15 = session.requirements.map((r) => r.description).join(" ");
|
|
25668
25696
|
for (const pattern of userPatterns) {
|
|
25669
25697
|
let match;
|
|
25670
|
-
while ((match = pattern.exec(
|
|
25698
|
+
while ((match = pattern.exec(text15)) !== null) {
|
|
25671
25699
|
const user = match[1]?.toLowerCase();
|
|
25672
25700
|
if (user && !users.includes(user)) {
|
|
25673
25701
|
users.push(user);
|
|
@@ -25680,13 +25708,13 @@ function inferTargetUsers(session) {
|
|
|
25680
25708
|
return users;
|
|
25681
25709
|
}
|
|
25682
25710
|
function inferProjectType(session) {
|
|
25683
|
-
const
|
|
25684
|
-
if (
|
|
25685
|
-
if (
|
|
25686
|
-
if (
|
|
25687
|
-
if (
|
|
25688
|
-
if (
|
|
25689
|
-
if (
|
|
25711
|
+
const text15 = session.initialInput.toLowerCase();
|
|
25712
|
+
if (text15.includes("cli") || text15.includes("command line")) return "cli";
|
|
25713
|
+
if (text15.includes("api") || text15.includes("rest") || text15.includes("graphql")) return "api";
|
|
25714
|
+
if (text15.includes("web app") || text15.includes("frontend")) return "web_app";
|
|
25715
|
+
if (text15.includes("library") || text15.includes("package")) return "library";
|
|
25716
|
+
if (text15.includes("service") || text15.includes("daemon")) return "service";
|
|
25717
|
+
if (text15.includes("full stack") || text15.includes("fullstack")) return "full_stack";
|
|
25690
25718
|
return "unknown";
|
|
25691
25719
|
}
|
|
25692
25720
|
function assessComplexity(session) {
|
|
@@ -29186,13 +29214,14 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29186
29214
|
functionCalling: true,
|
|
29187
29215
|
vision: true
|
|
29188
29216
|
},
|
|
29189
|
-
// Updated:
|
|
29217
|
+
// Updated: April 2026 — from docs.github.com/en/copilot/reference/ai-models/supported-models
|
|
29218
|
+
// Premium request multipliers in descriptions are for paid Copilot plans.
|
|
29190
29219
|
models: [
|
|
29191
29220
|
// Anthropic models
|
|
29192
29221
|
{
|
|
29193
29222
|
id: "claude-sonnet-4.6",
|
|
29194
29223
|
name: "Claude Sonnet 4.6",
|
|
29195
|
-
description: "
|
|
29224
|
+
description: "Balanced Claude model via Copilot \u2014 Premium x1",
|
|
29196
29225
|
contextWindow: 2e5,
|
|
29197
29226
|
maxOutputTokens: 64e3,
|
|
29198
29227
|
recommended: true
|
|
@@ -29200,28 +29229,28 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29200
29229
|
{
|
|
29201
29230
|
id: "claude-opus-4.6",
|
|
29202
29231
|
name: "Claude Opus 4.6",
|
|
29203
|
-
description: "
|
|
29232
|
+
description: "Most capable Claude model via Copilot \u2014 Premium x3",
|
|
29204
29233
|
contextWindow: 2e5,
|
|
29205
29234
|
maxOutputTokens: 128e3
|
|
29206
29235
|
},
|
|
29207
29236
|
{
|
|
29208
29237
|
id: "claude-sonnet-4.5",
|
|
29209
29238
|
name: "Claude Sonnet 4.5",
|
|
29210
|
-
description: "Previous balanced Claude model via Copilot",
|
|
29239
|
+
description: "Previous balanced Claude model via Copilot \u2014 Premium x1",
|
|
29211
29240
|
contextWindow: 2e5,
|
|
29212
29241
|
maxOutputTokens: 64e3
|
|
29213
29242
|
},
|
|
29214
29243
|
{
|
|
29215
29244
|
id: "claude-opus-4.5",
|
|
29216
29245
|
name: "Claude Opus 4.5",
|
|
29217
|
-
description: "Previous flagship Claude model via Copilot",
|
|
29246
|
+
description: "Previous flagship Claude model via Copilot \u2014 Premium x3",
|
|
29218
29247
|
contextWindow: 2e5,
|
|
29219
29248
|
maxOutputTokens: 64e3
|
|
29220
29249
|
},
|
|
29221
29250
|
{
|
|
29222
29251
|
id: "claude-haiku-4.5",
|
|
29223
29252
|
name: "Claude Haiku 4.5",
|
|
29224
|
-
description: "Fast
|
|
29253
|
+
description: "Fast low-cost Claude model via Copilot \u2014 Premium x0.33",
|
|
29225
29254
|
contextWindow: 2e5,
|
|
29226
29255
|
maxOutputTokens: 64e3
|
|
29227
29256
|
},
|
|
@@ -29229,7 +29258,7 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29229
29258
|
{
|
|
29230
29259
|
id: "gpt-5.4-codex",
|
|
29231
29260
|
name: "GPT-5.4 Codex",
|
|
29232
|
-
description: "
|
|
29261
|
+
description: "Latest coding model via Copilot \u2014 Premium x1",
|
|
29233
29262
|
contextWindow: 4e5,
|
|
29234
29263
|
maxOutputTokens: 128e3,
|
|
29235
29264
|
recommended: true
|
|
@@ -29237,28 +29266,28 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29237
29266
|
{
|
|
29238
29267
|
id: "gpt-5.3-codex",
|
|
29239
29268
|
name: "GPT-5.3 Codex",
|
|
29240
|
-
description: "
|
|
29269
|
+
description: "Previous coding model via Copilot \u2014 Premium x1",
|
|
29241
29270
|
contextWindow: 4e5,
|
|
29242
29271
|
maxOutputTokens: 128e3
|
|
29243
29272
|
},
|
|
29244
29273
|
{
|
|
29245
29274
|
id: "gpt-5.2-codex",
|
|
29246
29275
|
name: "GPT-5.2 Codex",
|
|
29247
|
-
description: "
|
|
29276
|
+
description: "Previous coding model via Copilot \u2014 Premium x1",
|
|
29248
29277
|
contextWindow: 4e5,
|
|
29249
29278
|
maxOutputTokens: 128e3
|
|
29250
29279
|
},
|
|
29251
29280
|
{
|
|
29252
29281
|
id: "gpt-5.1-codex-max",
|
|
29253
29282
|
name: "GPT-5.1 Codex Max",
|
|
29254
|
-
description: "Frontier agentic coding model via Copilot",
|
|
29283
|
+
description: "Frontier agentic coding model via Copilot \u2014 Premium x1",
|
|
29255
29284
|
contextWindow: 4e5,
|
|
29256
29285
|
maxOutputTokens: 128e3
|
|
29257
29286
|
},
|
|
29258
29287
|
{
|
|
29259
29288
|
id: "gpt-4.1",
|
|
29260
29289
|
name: "GPT-4.1",
|
|
29261
|
-
description: "OpenAI long-context model via Copilot (1M)",
|
|
29290
|
+
description: "OpenAI long-context model via Copilot (1M) \u2014 Premium x0",
|
|
29262
29291
|
contextWindow: 1048576,
|
|
29263
29292
|
maxOutputTokens: 32768
|
|
29264
29293
|
},
|
|
@@ -29266,21 +29295,21 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29266
29295
|
{
|
|
29267
29296
|
id: "gemini-3.1-pro-preview",
|
|
29268
29297
|
name: "Gemini 3.1 Pro",
|
|
29269
|
-
description: "Google's latest model via Copilot (1M)",
|
|
29298
|
+
description: "Google's latest model via Copilot (1M) \u2014 Premium x1",
|
|
29270
29299
|
contextWindow: 1e6,
|
|
29271
29300
|
maxOutputTokens: 64e3
|
|
29272
29301
|
},
|
|
29273
29302
|
{
|
|
29274
29303
|
id: "gemini-3-flash-preview",
|
|
29275
29304
|
name: "Gemini 3 Flash",
|
|
29276
|
-
description: "Google's fast model via Copilot (1M)",
|
|
29305
|
+
description: "Google's fast model via Copilot (1M) \u2014 Premium x0.33",
|
|
29277
29306
|
contextWindow: 1e6,
|
|
29278
29307
|
maxOutputTokens: 64e3
|
|
29279
29308
|
},
|
|
29280
29309
|
{
|
|
29281
29310
|
id: "gemini-2.5-pro",
|
|
29282
29311
|
name: "Gemini 2.5 Pro",
|
|
29283
|
-
description: "Google stable model via Copilot (1M)",
|
|
29312
|
+
description: "Google stable model via Copilot (1M) \u2014 Premium x1",
|
|
29284
29313
|
contextWindow: 1048576,
|
|
29285
29314
|
maxOutputTokens: 65536
|
|
29286
29315
|
}
|
|
@@ -29419,8 +29448,8 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29419
29448
|
name: "Google Vertex AI Gemini",
|
|
29420
29449
|
emoji: "\u2601\uFE0F",
|
|
29421
29450
|
description: "Gemini on Vertex AI with GCP project, IAM and ADC",
|
|
29422
|
-
envVar: "
|
|
29423
|
-
apiKeyUrl: "https://
|
|
29451
|
+
envVar: "VERTEX_API_KEY",
|
|
29452
|
+
apiKeyUrl: "https://cloud.google.com/vertex-ai/generative-ai/docs/start/api-keys",
|
|
29424
29453
|
docsUrl: "https://cloud.google.com/vertex-ai/generative-ai/docs/start/quickstart",
|
|
29425
29454
|
baseUrl: "https://aiplatform.googleapis.com/v1",
|
|
29426
29455
|
supportsCustomModels: true,
|
|
@@ -30066,7 +30095,7 @@ function getProviderDefinition(type) {
|
|
|
30066
30095
|
return PROVIDER_DEFINITIONS[type];
|
|
30067
30096
|
}
|
|
30068
30097
|
function getAllProviders() {
|
|
30069
|
-
return Object.values(PROVIDER_DEFINITIONS).filter((
|
|
30098
|
+
return Object.values(PROVIDER_DEFINITIONS).filter((p46) => !p46.internal);
|
|
30070
30099
|
}
|
|
30071
30100
|
function getRecommendedModel(type) {
|
|
30072
30101
|
const provider = PROVIDER_DEFINITIONS[type];
|
|
@@ -30087,20 +30116,20 @@ function hasLocalProviderConfig(type) {
|
|
|
30087
30116
|
return process.env["COCO_PROVIDER"] === "ollama" || !!process.env["OLLAMA_MODEL"] || !!process.env["OLLAMA_BASE_URL"];
|
|
30088
30117
|
}
|
|
30089
30118
|
function getConfiguredProviders() {
|
|
30090
|
-
return getAllProviders().filter((
|
|
30091
|
-
if (
|
|
30119
|
+
return getAllProviders().filter((p46) => {
|
|
30120
|
+
if (p46.id === "copilot") {
|
|
30092
30121
|
return !!process.env["GITHUB_TOKEN"] || !!process.env["GH_TOKEN"] || hasCopilotCredentials();
|
|
30093
30122
|
}
|
|
30094
|
-
if (
|
|
30095
|
-
return !!process.env[
|
|
30123
|
+
if (p46.id === "openai") {
|
|
30124
|
+
return !!process.env[p46.envVar] || !!process.env["OPENAI_CODEX_TOKEN"] || !!process.env["OPENAI_ACCESS_TOKEN"];
|
|
30096
30125
|
}
|
|
30097
|
-
if (
|
|
30098
|
-
return hasLocalProviderConfig(
|
|
30126
|
+
if (p46.id === "lmstudio" || p46.id === "ollama") {
|
|
30127
|
+
return hasLocalProviderConfig(p46.id);
|
|
30099
30128
|
}
|
|
30100
|
-
if (
|
|
30101
|
-
return !!(process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]);
|
|
30129
|
+
if (p46.id === "vertex") {
|
|
30130
|
+
return !!(process.env["VERTEX_API_KEY"] ?? process.env["GOOGLE_API_KEY"] ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]);
|
|
30102
30131
|
}
|
|
30103
|
-
return !!process.env[
|
|
30132
|
+
return !!process.env[p46.envVar];
|
|
30104
30133
|
});
|
|
30105
30134
|
}
|
|
30106
30135
|
function isProviderConfigured(type) {
|
|
@@ -30451,11 +30480,11 @@ async function runRemoveServer(name, options) {
|
|
|
30451
30480
|
process.exit(1);
|
|
30452
30481
|
}
|
|
30453
30482
|
if (!options.yes) {
|
|
30454
|
-
const
|
|
30483
|
+
const confirm23 = await p26.confirm({
|
|
30455
30484
|
message: `Remove server '${name}'?`,
|
|
30456
30485
|
initialValue: false
|
|
30457
30486
|
});
|
|
30458
|
-
if (p26.isCancel(
|
|
30487
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
30459
30488
|
p26.outro("Cancelled");
|
|
30460
30489
|
return;
|
|
30461
30490
|
}
|
|
@@ -30727,10 +30756,10 @@ async function runRemove(name, options) {
|
|
|
30727
30756
|
return;
|
|
30728
30757
|
}
|
|
30729
30758
|
if (!options.yes) {
|
|
30730
|
-
const
|
|
30759
|
+
const confirm23 = await p26.confirm({
|
|
30731
30760
|
message: `Remove skill "${name}" from ${targetDir}?`
|
|
30732
30761
|
});
|
|
30733
|
-
if (p26.isCancel(
|
|
30762
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
30734
30763
|
p26.log.info("Cancelled.");
|
|
30735
30764
|
p26.outro("");
|
|
30736
30765
|
return;
|
|
@@ -31235,8 +31264,8 @@ ${suggestionsHtml}
|
|
|
31235
31264
|
return filePath;
|
|
31236
31265
|
}
|
|
31237
31266
|
// ── Private helpers ───────────────────────────────────────────────────────
|
|
31238
|
-
htmlEscape(
|
|
31239
|
-
return
|
|
31267
|
+
htmlEscape(text15) {
|
|
31268
|
+
return text15.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
31240
31269
|
}
|
|
31241
31270
|
markdownIssue(issue) {
|
|
31242
31271
|
const severity = issue.severity === "critical" ? "\u{1F534}" : issue.severity === "major" ? "\u{1F7E1}" : "\u{1F535}";
|
|
@@ -31758,12 +31787,12 @@ Return only JSON: { "score": <number 1-10>, "reasoning": "<brief explanation>" }
|
|
|
31758
31787
|
}
|
|
31759
31788
|
return classifyFeatureHeuristic(feature);
|
|
31760
31789
|
}
|
|
31761
|
-
function extractJsonScore(
|
|
31790
|
+
function extractJsonScore(text15) {
|
|
31762
31791
|
try {
|
|
31763
|
-
const stripped =
|
|
31792
|
+
const stripped = text15.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
31764
31793
|
return JSON.parse(stripped);
|
|
31765
31794
|
} catch {
|
|
31766
|
-
const match =
|
|
31795
|
+
const match = text15.match(/\{[\s\S]*?\}/);
|
|
31767
31796
|
if (match) {
|
|
31768
31797
|
try {
|
|
31769
31798
|
return JSON.parse(match[0]);
|
|
@@ -31987,25 +32016,25 @@ Rules:
|
|
|
31987
32016
|
}
|
|
31988
32017
|
}
|
|
31989
32018
|
async function defaultPromptHandler(q) {
|
|
31990
|
-
const
|
|
32019
|
+
const p46 = await import('@clack/prompts');
|
|
31991
32020
|
if (q.options && q.options.length > 0) {
|
|
31992
|
-
const result = await
|
|
32021
|
+
const result = await p46.select({
|
|
31993
32022
|
message: q.question,
|
|
31994
32023
|
options: [
|
|
31995
32024
|
...q.options.map((o) => ({ value: o, label: o })),
|
|
31996
32025
|
{ value: q.assumedAnswer, label: `${q.assumedAnswer} (default)` }
|
|
31997
32026
|
]
|
|
31998
32027
|
});
|
|
31999
|
-
if (
|
|
32028
|
+
if (p46.isCancel(result)) {
|
|
32000
32029
|
return q.assumedAnswer;
|
|
32001
32030
|
}
|
|
32002
32031
|
return result;
|
|
32003
32032
|
} else {
|
|
32004
|
-
const result = await
|
|
32033
|
+
const result = await p46.text({
|
|
32005
32034
|
message: q.question,
|
|
32006
32035
|
placeholder: q.assumedAnswer
|
|
32007
32036
|
});
|
|
32008
|
-
if (
|
|
32037
|
+
if (p46.isCancel(result) || !result) {
|
|
32009
32038
|
return q.assumedAnswer;
|
|
32010
32039
|
}
|
|
32011
32040
|
return result;
|
|
@@ -32976,12 +33005,12 @@ function computeGlobalScore(results) {
|
|
|
32976
33005
|
const total = results.reduce((sum, r) => sum + r.reviewScore, 0);
|
|
32977
33006
|
return Math.round(total / results.length);
|
|
32978
33007
|
}
|
|
32979
|
-
function extractJson(
|
|
33008
|
+
function extractJson(text15) {
|
|
32980
33009
|
try {
|
|
32981
|
-
const stripped =
|
|
33010
|
+
const stripped = text15.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
32982
33011
|
return JSON.parse(stripped);
|
|
32983
33012
|
} catch {
|
|
32984
|
-
const match =
|
|
33013
|
+
const match = text15.match(/\{[\s\S]*\}/);
|
|
32985
33014
|
if (match) {
|
|
32986
33015
|
try {
|
|
32987
33016
|
return JSON.parse(match[0]);
|
|
@@ -33282,6 +33311,302 @@ function showToolsHelp() {
|
|
|
33282
33311
|
|
|
33283
33312
|
// src/cli/repl/commands/clear.ts
|
|
33284
33313
|
init_session();
|
|
33314
|
+
async function getGitContext(projectPath) {
|
|
33315
|
+
const controller = new AbortController();
|
|
33316
|
+
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
33317
|
+
try {
|
|
33318
|
+
const git = simpleGit({ baseDir: projectPath, abort: controller.signal });
|
|
33319
|
+
const status = await git.status();
|
|
33320
|
+
clearTimeout(timer);
|
|
33321
|
+
return {
|
|
33322
|
+
branch: status.current ?? "HEAD",
|
|
33323
|
+
isDirty: !status.isClean(),
|
|
33324
|
+
staged: status.staged.length,
|
|
33325
|
+
modified: status.modified.length,
|
|
33326
|
+
untracked: status.not_added.length,
|
|
33327
|
+
ahead: status.ahead,
|
|
33328
|
+
behind: status.behind
|
|
33329
|
+
};
|
|
33330
|
+
} catch {
|
|
33331
|
+
clearTimeout(timer);
|
|
33332
|
+
return null;
|
|
33333
|
+
}
|
|
33334
|
+
}
|
|
33335
|
+
function formatGitLine(ctx) {
|
|
33336
|
+
const branchColor = ctx.isDirty ? chalk.yellow : chalk.green;
|
|
33337
|
+
const parts = [chalk.dim("\u{1F33F} ") + branchColor(ctx.branch)];
|
|
33338
|
+
const changes = [];
|
|
33339
|
+
if (ctx.staged > 0) changes.push(chalk.green(`+${ctx.staged}`));
|
|
33340
|
+
if (ctx.modified > 0) changes.push(chalk.yellow(`~${ctx.modified}`));
|
|
33341
|
+
if (ctx.untracked > 0) changes.push(chalk.dim(`?${ctx.untracked}`));
|
|
33342
|
+
if (ctx.ahead > 0) changes.push(chalk.cyan(`\u2191${ctx.ahead}`));
|
|
33343
|
+
if (ctx.behind > 0) changes.push(chalk.red(`\u2193${ctx.behind}`));
|
|
33344
|
+
if (changes.length > 0) parts.push(changes.join(" "));
|
|
33345
|
+
return parts.join(" \u2022 ");
|
|
33346
|
+
}
|
|
33347
|
+
function formatGitShort(ctx) {
|
|
33348
|
+
const branch = ctx.isDirty ? chalk.yellow(ctx.branch) : chalk.green(ctx.branch);
|
|
33349
|
+
const dirty = ctx.isDirty ? chalk.yellow(" \u25CF") : "";
|
|
33350
|
+
return chalk.dim("\u{1F33F} ") + branch + dirty;
|
|
33351
|
+
}
|
|
33352
|
+
|
|
33353
|
+
// src/cli/repl/startup-panel.ts
|
|
33354
|
+
init_version();
|
|
33355
|
+
init_trust_store();
|
|
33356
|
+
init_env();
|
|
33357
|
+
|
|
33358
|
+
// src/cli/repl/quality-loop.ts
|
|
33359
|
+
init_paths();
|
|
33360
|
+
var qualityLoopEnabled = false;
|
|
33361
|
+
var hintShown = false;
|
|
33362
|
+
function isQualityLoop() {
|
|
33363
|
+
return qualityLoopEnabled;
|
|
33364
|
+
}
|
|
33365
|
+
function setQualityLoop(enabled) {
|
|
33366
|
+
qualityLoopEnabled = enabled;
|
|
33367
|
+
}
|
|
33368
|
+
function wasHintShown() {
|
|
33369
|
+
return hintShown;
|
|
33370
|
+
}
|
|
33371
|
+
function markHintShown() {
|
|
33372
|
+
hintShown = true;
|
|
33373
|
+
}
|
|
33374
|
+
function looksLikeFeatureRequest(input) {
|
|
33375
|
+
const trimmed = input.trim();
|
|
33376
|
+
if (trimmed.length < 20) return false;
|
|
33377
|
+
if (trimmed.endsWith("?") && trimmed.length < 80) return false;
|
|
33378
|
+
const featureKeywords = [
|
|
33379
|
+
/\bimplement/i,
|
|
33380
|
+
/\bcreate\b/i,
|
|
33381
|
+
/\bbuild\b/i,
|
|
33382
|
+
/\badd\b.*\b(feature|function|component|endpoint|service|module|class)/i,
|
|
33383
|
+
/\brefactor/i,
|
|
33384
|
+
/\bmigrate/i,
|
|
33385
|
+
/\bsetup\b/i,
|
|
33386
|
+
/\bintegrate/i,
|
|
33387
|
+
/\bwrite\b.*\b(code|function|test|module)/i,
|
|
33388
|
+
/\bdevelop/i,
|
|
33389
|
+
/\bdesign\b/i,
|
|
33390
|
+
/\bfix\b.*\b(bug|issue|error|problem)/i,
|
|
33391
|
+
/\bupdate\b.*\b(function|component|service|module)/i,
|
|
33392
|
+
/\bgenerate\b/i,
|
|
33393
|
+
/\bconvert\b/i
|
|
33394
|
+
];
|
|
33395
|
+
return featureKeywords.some((re) => re.test(trimmed));
|
|
33396
|
+
}
|
|
33397
|
+
function formatQualityLoopHint() {
|
|
33398
|
+
return chalk.dim(" tip: ") + chalk.magenta("/quality on") + chalk.dim(" enables Coco quality mode: auto-test, self-review, and iterate until robust");
|
|
33399
|
+
}
|
|
33400
|
+
function formatQualityResult(result) {
|
|
33401
|
+
const lines = [];
|
|
33402
|
+
const scores = result.scoreHistory;
|
|
33403
|
+
const progressStr = scores.map((s) => String(s)).join(" \u2192 ");
|
|
33404
|
+
const convergedLabel = result.converged ? chalk.green("converged") : chalk.yellow("max iterations");
|
|
33405
|
+
lines.push("");
|
|
33406
|
+
lines.push(
|
|
33407
|
+
chalk.magenta("\u2500\u2500 Quality: ") + chalk.white(progressStr) + chalk.dim(` (${convergedLabel})`) + chalk.magenta(" \u2500\u2500")
|
|
33408
|
+
);
|
|
33409
|
+
const parts = [];
|
|
33410
|
+
if (result.testsPassed !== void 0 && result.testsTotal !== void 0) {
|
|
33411
|
+
const testsColor = result.testsPassed === result.testsTotal ? chalk.green : chalk.yellow;
|
|
33412
|
+
parts.push(testsColor(`Tests: ${result.testsPassed}/${result.testsTotal}`));
|
|
33413
|
+
}
|
|
33414
|
+
if (result.coverage !== void 0) {
|
|
33415
|
+
const covColor = result.coverage >= 80 ? chalk.green : chalk.yellow;
|
|
33416
|
+
parts.push(covColor(`Coverage: ${result.coverage}%`));
|
|
33417
|
+
}
|
|
33418
|
+
if (result.securityScore !== void 0) {
|
|
33419
|
+
const secColor = result.securityScore === 100 ? chalk.green : chalk.red;
|
|
33420
|
+
parts.push(secColor(`Security: ${result.securityScore}`));
|
|
33421
|
+
}
|
|
33422
|
+
parts.push(chalk.dim(`Iterations: ${result.iterations}`));
|
|
33423
|
+
if (result.durationMs !== void 0) {
|
|
33424
|
+
const secs = (result.durationMs / 1e3).toFixed(1);
|
|
33425
|
+
parts.push(chalk.dim(`Time: ${secs}s`));
|
|
33426
|
+
}
|
|
33427
|
+
lines.push(" " + parts.join(" "));
|
|
33428
|
+
lines.push("");
|
|
33429
|
+
return lines.join("\n");
|
|
33430
|
+
}
|
|
33431
|
+
async function loadQualityLoopPreference() {
|
|
33432
|
+
try {
|
|
33433
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
33434
|
+
const config = JSON.parse(content);
|
|
33435
|
+
const value = config.qualityLoop ?? config.cocoMode;
|
|
33436
|
+
if (typeof value === "boolean") {
|
|
33437
|
+
qualityLoopEnabled = value;
|
|
33438
|
+
return value;
|
|
33439
|
+
}
|
|
33440
|
+
} catch {
|
|
33441
|
+
}
|
|
33442
|
+
qualityLoopEnabled = false;
|
|
33443
|
+
return false;
|
|
33444
|
+
}
|
|
33445
|
+
async function saveQualityLoopPreference(enabled) {
|
|
33446
|
+
try {
|
|
33447
|
+
let config = {};
|
|
33448
|
+
try {
|
|
33449
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
33450
|
+
config = JSON.parse(content);
|
|
33451
|
+
} catch {
|
|
33452
|
+
}
|
|
33453
|
+
config.qualityLoop = enabled;
|
|
33454
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
33455
|
+
} catch {
|
|
33456
|
+
}
|
|
33457
|
+
}
|
|
33458
|
+
function parseQualityLoopReport(content) {
|
|
33459
|
+
const marker = "QUALITY_LOOP_REPORT";
|
|
33460
|
+
const idx = content.indexOf(marker);
|
|
33461
|
+
if (idx === -1) return null;
|
|
33462
|
+
const block = content.slice(idx);
|
|
33463
|
+
const getField = (name) => {
|
|
33464
|
+
const match = block.match(new RegExp(`${name}:\\s*(.+)`));
|
|
33465
|
+
return match?.[1]?.trim();
|
|
33466
|
+
};
|
|
33467
|
+
const scoreHistoryRaw = getField("score_history");
|
|
33468
|
+
if (!scoreHistoryRaw) return null;
|
|
33469
|
+
const scores = scoreHistoryRaw.replace(/[[\]]/g, "").split(",").map((s) => parseFloat(s.trim())).filter((n) => !isNaN(n));
|
|
33470
|
+
if (scores.length === 0) return null;
|
|
33471
|
+
const testsPassed = parseInt(getField("tests_passed") ?? "", 10);
|
|
33472
|
+
const testsTotal = parseInt(getField("tests_total") ?? "", 10);
|
|
33473
|
+
const coverage = parseInt(getField("coverage") ?? "", 10);
|
|
33474
|
+
const security = parseInt(getField("security") ?? "", 10);
|
|
33475
|
+
const iterations = parseInt(getField("iterations") ?? "", 10) || scores.length;
|
|
33476
|
+
const converged = getField("converged") === "true";
|
|
33477
|
+
return {
|
|
33478
|
+
converged,
|
|
33479
|
+
scoreHistory: scores,
|
|
33480
|
+
finalScore: scores[scores.length - 1] ?? 0,
|
|
33481
|
+
iterations,
|
|
33482
|
+
testsPassed: isNaN(testsPassed) ? void 0 : testsPassed,
|
|
33483
|
+
testsTotal: isNaN(testsTotal) ? void 0 : testsTotal,
|
|
33484
|
+
coverage: isNaN(coverage) ? void 0 : coverage,
|
|
33485
|
+
securityScore: isNaN(security) ? void 0 : security
|
|
33486
|
+
};
|
|
33487
|
+
}
|
|
33488
|
+
function getQualityLoopSystemPrompt() {
|
|
33489
|
+
return `
|
|
33490
|
+
## Quality Loop Mode (ACTIVE)
|
|
33491
|
+
|
|
33492
|
+
You are operating in quality loop mode. After implementing code changes, you MUST follow this iteration cycle:
|
|
33493
|
+
|
|
33494
|
+
1. **Implement** the requested changes (code + tests)
|
|
33495
|
+
2. **Run tests** using the run_tests or bash_exec tool
|
|
33496
|
+
3. **Self-review**: Analyze your code against these 12 quality dimensions:
|
|
33497
|
+
- Correctness, Completeness, Robustness, Readability
|
|
33498
|
+
- Maintainability, Complexity, Duplication, Test Coverage
|
|
33499
|
+
- Test Quality, Security, Documentation, Style
|
|
33500
|
+
4. **Score** your implementation 0-100 for each dimension
|
|
33501
|
+
5. **If issues found**: Fix them and go back to step 2
|
|
33502
|
+
6. **If quality is good** (overall \u2265 85 and improving < 2 points): Stop and report
|
|
33503
|
+
|
|
33504
|
+
After completing the cycle, output a quality summary in this exact format:
|
|
33505
|
+
|
|
33506
|
+
\`\`\`
|
|
33507
|
+
QUALITY_LOOP_REPORT
|
|
33508
|
+
score_history: [first_score, ..., final_score]
|
|
33509
|
+
tests_passed: X
|
|
33510
|
+
tests_total: Y
|
|
33511
|
+
coverage: Z
|
|
33512
|
+
security: 100
|
|
33513
|
+
iterations: N
|
|
33514
|
+
converged: true|false
|
|
33515
|
+
\`\`\`
|
|
33516
|
+
|
|
33517
|
+
Key rules:
|
|
33518
|
+
- Always write tests alongside code
|
|
33519
|
+
- Run tests after every change
|
|
33520
|
+
- Minimum 2 iterations before declaring convergence
|
|
33521
|
+
- Maximum 10 iterations
|
|
33522
|
+
- Fix critical issues before moving on
|
|
33523
|
+
- Report honestly - don't inflate scores`;
|
|
33524
|
+
}
|
|
33525
|
+
|
|
33526
|
+
// src/cli/repl/startup-panel.ts
|
|
33527
|
+
async function renderStartupPanel(session, gitCtx, mcpServers = []) {
|
|
33528
|
+
const trustStore = createTrustStore();
|
|
33529
|
+
await trustStore.init();
|
|
33530
|
+
const trustLevel = trustStore.getLevel(session.projectPath);
|
|
33531
|
+
const boxWidth = 41;
|
|
33532
|
+
const innerWidth = boxWidth - 2;
|
|
33533
|
+
const versionText = `v${VERSION}`;
|
|
33534
|
+
const subtitleText = "open source \u2022 corbat.tech";
|
|
33535
|
+
const boxLine = (content) => {
|
|
33536
|
+
const pad = Math.max(0, innerWidth - stringWidth2(content));
|
|
33537
|
+
return chalk.magenta("\u2502") + content + " ".repeat(pad) + chalk.magenta("\u2502");
|
|
33538
|
+
};
|
|
33539
|
+
const titleLeftRaw = " COCO";
|
|
33540
|
+
const titleRightRaw = versionText + " ";
|
|
33541
|
+
const titleLeftStyled = " " + chalk.bold.white("COCO");
|
|
33542
|
+
const titleGap = Math.max(1, innerWidth - stringWidth2(titleLeftRaw) - stringWidth2(titleRightRaw));
|
|
33543
|
+
const titleContent = titleLeftStyled + " ".repeat(titleGap) + chalk.dim(titleRightRaw);
|
|
33544
|
+
const taglineText = "code that converges to quality";
|
|
33545
|
+
const taglineContent = " " + chalk.magenta(taglineText) + " ";
|
|
33546
|
+
const subtitleContent = " " + chalk.dim(subtitleText) + " ";
|
|
33547
|
+
console.log();
|
|
33548
|
+
console.log(chalk.magenta(" \u256D" + "\u2500".repeat(boxWidth - 2) + "\u256E"));
|
|
33549
|
+
console.log(" " + boxLine(titleContent));
|
|
33550
|
+
console.log(" " + boxLine(taglineContent));
|
|
33551
|
+
console.log(" " + boxLine(subtitleContent));
|
|
33552
|
+
console.log(chalk.magenta(" \u2570" + "\u2500".repeat(boxWidth - 2) + "\u256F"));
|
|
33553
|
+
const maxPathLen = 50;
|
|
33554
|
+
let displayPath = session.projectPath;
|
|
33555
|
+
if (displayPath.length > maxPathLen) {
|
|
33556
|
+
displayPath = "..." + displayPath.slice(-maxPathLen + 3);
|
|
33557
|
+
}
|
|
33558
|
+
const lastSep = displayPath.lastIndexOf("/");
|
|
33559
|
+
const parentPath = lastSep > 0 ? displayPath.slice(0, lastSep + 1) : "";
|
|
33560
|
+
const projectName = lastSep > 0 ? displayPath.slice(lastSep + 1) : displayPath;
|
|
33561
|
+
const providerName = session.config.provider.type;
|
|
33562
|
+
const configuredModel = session.config.provider.model?.trim();
|
|
33563
|
+
const modelName = configuredModel && !["default", "none", "null", "undefined"].includes(configuredModel.toLowerCase()) ? configuredModel : getDefaultModel(session.config.provider.type);
|
|
33564
|
+
const trustText = trustLevel === "full" ? "full" : trustLevel === "write" ? "write" : trustLevel === "read" ? "read" : "";
|
|
33565
|
+
console.log();
|
|
33566
|
+
console.log(chalk.dim(` \u{1F4C1} ${parentPath}`) + chalk.magenta.bold(projectName));
|
|
33567
|
+
console.log(
|
|
33568
|
+
chalk.dim(` \u{1F916} ${providerName}/`) + chalk.magenta(modelName) + (trustText ? chalk.dim(` \u2022 \u{1F510} ${trustText}`) : "")
|
|
33569
|
+
);
|
|
33570
|
+
if (gitCtx) {
|
|
33571
|
+
console.log(` ${formatGitLine(gitCtx)}`);
|
|
33572
|
+
}
|
|
33573
|
+
const cocoStatus = isQualityLoop() ? chalk.magenta(" \u{1F504} quality mode: ") + chalk.green.bold("on") + chalk.dim(" \u2014 iterates until quality \u2265 85. /quality to disable") : chalk.dim(" \u{1F4A1} quality mode is Coco's edge for robust code. Enable with /quality on");
|
|
33574
|
+
console.log(cocoStatus);
|
|
33575
|
+
const skillTotal = session.skillRegistry?.size ?? 0;
|
|
33576
|
+
const hasSomething = skillTotal > 0 || mcpServers.length > 0;
|
|
33577
|
+
if (hasSomething) {
|
|
33578
|
+
if (skillTotal > 0) {
|
|
33579
|
+
const allMeta = session.skillRegistry.getAllMetadata();
|
|
33580
|
+
const builtinCount = allMeta.filter((s) => s.scope === "builtin").length;
|
|
33581
|
+
const projectCount = skillTotal - builtinCount;
|
|
33582
|
+
const parts = [];
|
|
33583
|
+
if (builtinCount > 0) parts.push(`${builtinCount} builtin`);
|
|
33584
|
+
if (projectCount > 0) parts.push(`${projectCount} project`);
|
|
33585
|
+
const detail = parts.length > 0 ? ` (${parts.join(" \xB7 ")})` : "";
|
|
33586
|
+
console.log(chalk.green(" \u2713") + chalk.dim(` Skills: ${skillTotal} loaded${detail}`));
|
|
33587
|
+
} else {
|
|
33588
|
+
console.log(chalk.dim(" \xB7 Skills: none loaded"));
|
|
33589
|
+
}
|
|
33590
|
+
if (mcpServers.length > 0) {
|
|
33591
|
+
const names = mcpServers.join(", ");
|
|
33592
|
+
console.log(
|
|
33593
|
+
chalk.green(" \u2713") + chalk.dim(
|
|
33594
|
+
` MCP: ${names} (${mcpServers.length} server${mcpServers.length === 1 ? "" : "s"} active)`
|
|
33595
|
+
)
|
|
33596
|
+
);
|
|
33597
|
+
}
|
|
33598
|
+
}
|
|
33599
|
+
console.log();
|
|
33600
|
+
console.log(
|
|
33601
|
+
chalk.dim(" Type your request or ") + chalk.magenta("/help") + chalk.dim(" for commands")
|
|
33602
|
+
);
|
|
33603
|
+
const pasteHint = process.platform === "darwin" ? chalk.dim(" \u{1F4CB} \u2318V paste text \u2022 \u2303V paste image") : chalk.dim(" \u{1F4CB} Ctrl+V paste image from clipboard");
|
|
33604
|
+
console.log(pasteHint);
|
|
33605
|
+
console.log();
|
|
33606
|
+
}
|
|
33607
|
+
|
|
33608
|
+
// src/cli/repl/commands/clear.ts
|
|
33609
|
+
init_env();
|
|
33285
33610
|
var clearCommand = {
|
|
33286
33611
|
name: "clear",
|
|
33287
33612
|
aliases: ["c"],
|
|
@@ -33289,7 +33614,22 @@ var clearCommand = {
|
|
|
33289
33614
|
usage: "/clear",
|
|
33290
33615
|
async execute(_args, session) {
|
|
33291
33616
|
clearSession(session);
|
|
33292
|
-
|
|
33617
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
33618
|
+
const projectPath = session.projectPath || process.cwd();
|
|
33619
|
+
const gitCtx = await getGitContext(projectPath);
|
|
33620
|
+
const panelSession = {
|
|
33621
|
+
...session,
|
|
33622
|
+
projectPath,
|
|
33623
|
+
config: session.config ?? {
|
|
33624
|
+
provider: {
|
|
33625
|
+
type: "anthropic",
|
|
33626
|
+
model: getDefaultModel("anthropic"),
|
|
33627
|
+
maxTokens: 8192
|
|
33628
|
+
}
|
|
33629
|
+
}
|
|
33630
|
+
};
|
|
33631
|
+
await renderStartupPanel(panelSession, gitCtx);
|
|
33632
|
+
console.log(chalk.dim("Context cleared.\n"));
|
|
33293
33633
|
return false;
|
|
33294
33634
|
}
|
|
33295
33635
|
};
|
|
@@ -33656,7 +33996,7 @@ async function runOnboardingV2() {
|
|
|
33656
33996
|
console.log(chalk.magenta(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
33657
33997
|
console.log();
|
|
33658
33998
|
p26.log.info(
|
|
33659
|
-
`Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((
|
|
33999
|
+
`Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((p46) => p46.emoji + " " + p46.name).join(", ")}`
|
|
33660
34000
|
);
|
|
33661
34001
|
const useExisting = await p26.confirm({
|
|
33662
34002
|
message: "Use an existing provider?",
|
|
@@ -33763,6 +34103,12 @@ async function setupProviderWithAuth(provider) {
|
|
|
33763
34103
|
showProviderInfo(provider);
|
|
33764
34104
|
const apiKey = await requestApiKey(provider);
|
|
33765
34105
|
if (!apiKey) return null;
|
|
34106
|
+
let vertexSettings;
|
|
34107
|
+
if (provider.id === "vertex") {
|
|
34108
|
+
const settings = await promptVertexSettings();
|
|
34109
|
+
if (!settings) return null;
|
|
34110
|
+
vertexSettings = settings;
|
|
34111
|
+
}
|
|
33766
34112
|
let baseUrl;
|
|
33767
34113
|
if (provider.askForCustomUrl) {
|
|
33768
34114
|
const wantsCustomUrl = await p26.confirm({
|
|
@@ -33786,7 +34132,7 @@ async function setupProviderWithAuth(provider) {
|
|
|
33786
34132
|
}
|
|
33787
34133
|
const model = await selectModel(provider);
|
|
33788
34134
|
if (!model) return null;
|
|
33789
|
-
const valid = await testConnection(provider, apiKey, model, baseUrl);
|
|
34135
|
+
const valid = await testConnection(provider, apiKey, model, baseUrl, vertexSettings);
|
|
33790
34136
|
if (!valid) {
|
|
33791
34137
|
const retry = await p26.confirm({
|
|
33792
34138
|
message: "Would you like to try again?",
|
|
@@ -33801,7 +34147,9 @@ async function setupProviderWithAuth(provider) {
|
|
|
33801
34147
|
type: provider.id,
|
|
33802
34148
|
model,
|
|
33803
34149
|
apiKey,
|
|
33804
|
-
baseUrl
|
|
34150
|
+
baseUrl,
|
|
34151
|
+
project: vertexSettings?.project,
|
|
34152
|
+
location: vertexSettings?.location
|
|
33805
34153
|
};
|
|
33806
34154
|
}
|
|
33807
34155
|
async function setupGcloudADC(provider) {
|
|
@@ -33817,11 +34165,6 @@ async function setupGcloudADC(provider) {
|
|
|
33817
34165
|
p26.log.error("gcloud CLI is not installed");
|
|
33818
34166
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install"));
|
|
33819
34167
|
console.log();
|
|
33820
|
-
if (provider.id === "vertex") {
|
|
33821
|
-
console.log(chalk.dim(" Vertex AI requires gcloud ADC plus a Google Cloud project."));
|
|
33822
|
-
console.log();
|
|
33823
|
-
return null;
|
|
33824
|
-
}
|
|
33825
34168
|
const useFallback2 = await p26.confirm({
|
|
33826
34169
|
message: "Use API key instead?",
|
|
33827
34170
|
initialValue: true
|
|
@@ -33832,25 +34175,37 @@ async function setupGcloudADC(provider) {
|
|
|
33832
34175
|
if (!apiKey2) return null;
|
|
33833
34176
|
const model2 = await selectModel(provider);
|
|
33834
34177
|
if (!model2) return null;
|
|
33835
|
-
|
|
34178
|
+
let vertexSettings2;
|
|
34179
|
+
if (provider.id === "vertex") {
|
|
34180
|
+
const settings = await promptVertexSettings();
|
|
34181
|
+
if (!settings) return null;
|
|
34182
|
+
vertexSettings2 = settings;
|
|
34183
|
+
}
|
|
34184
|
+
const valid2 = await testConnection(provider, apiKey2, model2, void 0, vertexSettings2);
|
|
33836
34185
|
if (!valid2) return null;
|
|
33837
|
-
return {
|
|
34186
|
+
return {
|
|
34187
|
+
type: provider.id,
|
|
34188
|
+
model: model2,
|
|
34189
|
+
apiKey: apiKey2,
|
|
34190
|
+
project: vertexSettings2?.project,
|
|
34191
|
+
location: vertexSettings2?.location
|
|
34192
|
+
};
|
|
33838
34193
|
}
|
|
33839
34194
|
let adc = await inspectADC();
|
|
33840
34195
|
if (adc.status === "ok" && adc.token) {
|
|
33841
34196
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!"));
|
|
33842
34197
|
console.log();
|
|
33843
34198
|
p26.log.success("Authentication verified");
|
|
33844
|
-
const
|
|
33845
|
-
if (provider.id === "vertex" && !
|
|
34199
|
+
const vertexSettings2 = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
34200
|
+
if (provider.id === "vertex" && !vertexSettings2) return null;
|
|
33846
34201
|
const model2 = await selectModel(provider);
|
|
33847
34202
|
if (!model2) return null;
|
|
33848
34203
|
return {
|
|
33849
34204
|
type: provider.id,
|
|
33850
34205
|
model: model2,
|
|
33851
34206
|
apiKey: "__gcloud_adc__",
|
|
33852
|
-
project:
|
|
33853
|
-
location:
|
|
34207
|
+
project: vertexSettings2?.project,
|
|
34208
|
+
location: vertexSettings2?.location
|
|
33854
34209
|
};
|
|
33855
34210
|
}
|
|
33856
34211
|
console.log(chalk.yellow(" No reusable gcloud ADC session was found for Coco."));
|
|
@@ -33873,16 +34228,16 @@ async function setupGcloudADC(provider) {
|
|
|
33873
34228
|
console.log(chalk.green(" \u2713 gcloud ADC is now configured."));
|
|
33874
34229
|
console.log();
|
|
33875
34230
|
p26.log.success("Authentication verified");
|
|
33876
|
-
const
|
|
33877
|
-
if (provider.id === "vertex" && !
|
|
34231
|
+
const vertexSettings2 = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
34232
|
+
if (provider.id === "vertex" && !vertexSettings2) return null;
|
|
33878
34233
|
const model2 = await selectModel(provider);
|
|
33879
34234
|
if (!model2) return null;
|
|
33880
34235
|
return {
|
|
33881
34236
|
type: provider.id,
|
|
33882
34237
|
model: model2,
|
|
33883
34238
|
apiKey: "__gcloud_adc__",
|
|
33884
|
-
project:
|
|
33885
|
-
location:
|
|
34239
|
+
project: vertexSettings2?.project,
|
|
34240
|
+
location: vertexSettings2?.location
|
|
33886
34241
|
};
|
|
33887
34242
|
}
|
|
33888
34243
|
}
|
|
@@ -33901,13 +34256,6 @@ async function setupGcloudADC(provider) {
|
|
|
33901
34256
|
}
|
|
33902
34257
|
console.log(chalk.dim(" Coco will reuse the login on the next attempt if ADC is valid."));
|
|
33903
34258
|
console.log();
|
|
33904
|
-
if (provider.id === "vertex") {
|
|
33905
|
-
console.log(
|
|
33906
|
-
chalk.dim(" Vertex AI does not use API keys in Coco. Configure ADC, then retry.")
|
|
33907
|
-
);
|
|
33908
|
-
console.log();
|
|
33909
|
-
return null;
|
|
33910
|
-
}
|
|
33911
34259
|
const useFallback = await p26.confirm({
|
|
33912
34260
|
message: "Use API key for now?",
|
|
33913
34261
|
initialValue: true
|
|
@@ -33918,9 +34266,21 @@ async function setupGcloudADC(provider) {
|
|
|
33918
34266
|
if (!apiKey) return null;
|
|
33919
34267
|
const model = await selectModel(provider);
|
|
33920
34268
|
if (!model) return null;
|
|
33921
|
-
|
|
34269
|
+
let vertexSettings;
|
|
34270
|
+
if (provider.id === "vertex") {
|
|
34271
|
+
const settings = await promptVertexSettings();
|
|
34272
|
+
if (!settings) return null;
|
|
34273
|
+
vertexSettings = settings;
|
|
34274
|
+
}
|
|
34275
|
+
const valid = await testConnection(provider, apiKey, model, void 0, vertexSettings);
|
|
33922
34276
|
if (!valid) return null;
|
|
33923
|
-
return {
|
|
34277
|
+
return {
|
|
34278
|
+
type: provider.id,
|
|
34279
|
+
model,
|
|
34280
|
+
apiKey,
|
|
34281
|
+
project: vertexSettings?.project,
|
|
34282
|
+
location: vertexSettings?.location
|
|
34283
|
+
};
|
|
33924
34284
|
}
|
|
33925
34285
|
async function promptVertexSettings() {
|
|
33926
34286
|
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
@@ -34321,9 +34681,9 @@ async function setupOllamaProvider(port) {
|
|
|
34321
34681
|
return setupLocalProvider("ollama", port);
|
|
34322
34682
|
}
|
|
34323
34683
|
async function selectExistingProvider(providers) {
|
|
34324
|
-
const options = providers.map((
|
|
34325
|
-
value:
|
|
34326
|
-
label: `${
|
|
34684
|
+
const options = providers.map((p46) => ({
|
|
34685
|
+
value: p46.id,
|
|
34686
|
+
label: `${p46.emoji} ${p46.name}`,
|
|
34327
34687
|
hint: "Configured"
|
|
34328
34688
|
}));
|
|
34329
34689
|
options.push({ value: "__new__", label: "\u2795 Setup new provider", hint: "" });
|
|
@@ -34454,8 +34814,8 @@ async function testConnection(provider, apiKey, model, baseUrl, vertexSettings)
|
|
|
34454
34814
|
process.env[`${provider.id.toUpperCase()}_BASE_URL`] = baseUrl;
|
|
34455
34815
|
}
|
|
34456
34816
|
if (provider.id === "vertex") {
|
|
34457
|
-
if (vertexSettings?.project) ;
|
|
34458
|
-
if (vertexSettings?.location) ;
|
|
34817
|
+
if (vertexSettings?.project) process.env["VERTEX_PROJECT"] = vertexSettings.project;
|
|
34818
|
+
if (vertexSettings?.location) process.env["VERTEX_LOCATION"] = vertexSettings.location;
|
|
34459
34819
|
}
|
|
34460
34820
|
const testProvider = await createProvider(provider.id, {
|
|
34461
34821
|
model,
|
|
@@ -34715,7 +35075,7 @@ async function ensureConfiguredV2(config) {
|
|
|
34715
35075
|
} catch {
|
|
34716
35076
|
}
|
|
34717
35077
|
}
|
|
34718
|
-
const preferredProviderDef = providers.find((
|
|
35078
|
+
const preferredProviderDef = providers.find((p46) => p46.id === config.provider.type);
|
|
34719
35079
|
const preferredIsLocal = preferredProviderDef?.requiresApiKey === false && preferredProviderDef?.id !== "copilot";
|
|
34720
35080
|
const preferredHasApiKey = preferredProviderDef ? !!process.env[preferredProviderDef.envVar] : false;
|
|
34721
35081
|
const preferredHasOpenAIOAuth = preferredProviderDef?.id === "openai" && hasOpenAIOAuthTokens;
|
|
@@ -34745,17 +35105,18 @@ async function ensureConfiguredV2(config) {
|
|
|
34745
35105
|
preferredUnavailableWasLocal = preferredIsLocal;
|
|
34746
35106
|
}
|
|
34747
35107
|
if (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal) {
|
|
34748
|
-
const configuredProviders = providers.filter((
|
|
34749
|
-
if (
|
|
34750
|
-
if (
|
|
34751
|
-
return hasOpenAIOAuthTokens || !!process.env[
|
|
35108
|
+
const configuredProviders = providers.filter((p46) => {
|
|
35109
|
+
if (p46.id === "copilot") return isProviderConfigured();
|
|
35110
|
+
if (p46.id === "openai") {
|
|
35111
|
+
return hasOpenAIOAuthTokens || !!process.env[p46.envVar];
|
|
34752
35112
|
}
|
|
34753
|
-
return
|
|
35113
|
+
return p46.requiresApiKey === false || !!process.env[p46.envVar];
|
|
34754
35114
|
});
|
|
34755
35115
|
for (const prov of configuredProviders) {
|
|
34756
35116
|
try {
|
|
35117
|
+
const rememberedModel = await getLastUsedModel(prov.id);
|
|
34757
35118
|
const recommended = getRecommendedModel(prov.id);
|
|
34758
|
-
const model = recommended?.id || prov.models[0]?.id || "";
|
|
35119
|
+
const model = rememberedModel || recommended?.id || prov.models[0]?.id || "";
|
|
34759
35120
|
let providerId = prov.id;
|
|
34760
35121
|
if (prov.id === "openai" && hasOpenAIOAuthTokens && !process.env[prov.envVar]) {
|
|
34761
35122
|
const tokenResult = await getOrRefreshOAuthToken("openai");
|
|
@@ -34822,7 +35183,7 @@ init_auth();
|
|
|
34822
35183
|
init_env();
|
|
34823
35184
|
async function selectProviderInteractively(providers, currentProviderId) {
|
|
34824
35185
|
return new Promise((resolve4) => {
|
|
34825
|
-
let selectedIndex = providers.findIndex((
|
|
35186
|
+
let selectedIndex = providers.findIndex((p46) => p46.id === currentProviderId);
|
|
34826
35187
|
if (selectedIndex === -1) selectedIndex = 0;
|
|
34827
35188
|
let lastTotalLines = 0;
|
|
34828
35189
|
const clearPrevious = () => {
|
|
@@ -34920,12 +35281,12 @@ var providerCommand = {
|
|
|
34920
35281
|
`));
|
|
34921
35282
|
const allProviders2 = getAllProviders();
|
|
34922
35283
|
const configuredProviders = getConfiguredProviders();
|
|
34923
|
-
const providerOptions = allProviders2.map((
|
|
34924
|
-
id:
|
|
34925
|
-
name:
|
|
34926
|
-
emoji:
|
|
34927
|
-
description:
|
|
34928
|
-
isConfigured: configuredProviders.some((cp) => cp.id ===
|
|
35284
|
+
const providerOptions = allProviders2.map((p46) => ({
|
|
35285
|
+
id: p46.id,
|
|
35286
|
+
name: p46.name,
|
|
35287
|
+
emoji: p46.emoji,
|
|
35288
|
+
description: p46.description,
|
|
35289
|
+
isConfigured: configuredProviders.some((cp) => cp.id === p46.id)
|
|
34929
35290
|
}));
|
|
34930
35291
|
const selectedProviderId = await selectProviderInteractively(
|
|
34931
35292
|
providerOptions,
|
|
@@ -34940,15 +35301,15 @@ var providerCommand = {
|
|
|
34940
35301
|
`));
|
|
34941
35302
|
return false;
|
|
34942
35303
|
}
|
|
34943
|
-
const newProvider2 = allProviders2.find((
|
|
35304
|
+
const newProvider2 = allProviders2.find((p46) => p46.id === selectedProviderId);
|
|
34944
35305
|
return await switchProvider(newProvider2, session);
|
|
34945
35306
|
}
|
|
34946
35307
|
const newProviderId = args[0]?.toLowerCase();
|
|
34947
35308
|
const allProviders = getAllProviders();
|
|
34948
|
-
const newProvider = allProviders.find((
|
|
35309
|
+
const newProvider = allProviders.find((p46) => p46.id === newProviderId);
|
|
34949
35310
|
if (!newProvider) {
|
|
34950
35311
|
console.log(chalk.red(`Unknown provider: ${newProviderId}`));
|
|
34951
|
-
console.log(chalk.dim(`Available: ${allProviders.map((
|
|
35312
|
+
console.log(chalk.dim(`Available: ${allProviders.map((p46) => p46.id).join(", ")}
|
|
34952
35313
|
`));
|
|
34953
35314
|
return false;
|
|
34954
35315
|
}
|
|
@@ -34983,7 +35344,7 @@ async function switchProvider(initialProvider, session) {
|
|
|
34983
35344
|
`));
|
|
34984
35345
|
return false;
|
|
34985
35346
|
}
|
|
34986
|
-
const supportsApiKey = newProvider.
|
|
35347
|
+
const supportsApiKey = newProvider.requiresApiKey !== false;
|
|
34987
35348
|
const apiKey = supportsApiKey ? process.env[newProvider.envVar] : void 0;
|
|
34988
35349
|
const hasOAuth = supportsOAuth(newProvider.id) || newProvider.supportsOAuth;
|
|
34989
35350
|
const hasGcloudADC = newProvider.supportsGcloudADC;
|
|
@@ -35117,7 +35478,10 @@ Using existing OAuth session...`));
|
|
|
35117
35478
|
if (!adcResult) return false;
|
|
35118
35479
|
selectedAuthMethod = "gcloud";
|
|
35119
35480
|
if (newProvider.id === "vertex") {
|
|
35120
|
-
const settings = await promptVertexSettings2(
|
|
35481
|
+
const settings = await promptVertexSettings2({
|
|
35482
|
+
project: session.config.provider.project,
|
|
35483
|
+
location: session.config.provider.location
|
|
35484
|
+
});
|
|
35121
35485
|
if (!settings) return false;
|
|
35122
35486
|
vertexSettings = settings;
|
|
35123
35487
|
}
|
|
@@ -35138,6 +35502,14 @@ Using existing API key...`));
|
|
|
35138
35502
|
selectedAuthMethod = "apikey";
|
|
35139
35503
|
newApiKeyForSaving = key;
|
|
35140
35504
|
}
|
|
35505
|
+
if (newProvider.id === "vertex") {
|
|
35506
|
+
const settings = await promptVertexSettings2({
|
|
35507
|
+
project: session.config.provider.project,
|
|
35508
|
+
location: session.config.provider.location
|
|
35509
|
+
});
|
|
35510
|
+
if (!settings) return false;
|
|
35511
|
+
vertexSettings = settings;
|
|
35512
|
+
}
|
|
35141
35513
|
} else if (authChoice === "remove") {
|
|
35142
35514
|
const removeOptions = [];
|
|
35143
35515
|
if (oauthConnected) {
|
|
@@ -35194,7 +35566,10 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35194
35566
|
if (!adcResult) return false;
|
|
35195
35567
|
selectedAuthMethod = "gcloud";
|
|
35196
35568
|
if (newProvider.id === "vertex") {
|
|
35197
|
-
const settings = await promptVertexSettings2(
|
|
35569
|
+
const settings = await promptVertexSettings2({
|
|
35570
|
+
project: session.config.provider.project,
|
|
35571
|
+
location: session.config.provider.location
|
|
35572
|
+
});
|
|
35198
35573
|
if (!settings) return false;
|
|
35199
35574
|
vertexSettings = settings;
|
|
35200
35575
|
}
|
|
@@ -35245,7 +35620,9 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
35245
35620
|
await saveConfiguration({
|
|
35246
35621
|
type: userFacingProviderId,
|
|
35247
35622
|
model: newModel,
|
|
35248
|
-
apiKey: newApiKeyForSaving
|
|
35623
|
+
apiKey: newApiKeyForSaving,
|
|
35624
|
+
project: vertexSettings?.project,
|
|
35625
|
+
location: vertexSettings?.location
|
|
35249
35626
|
});
|
|
35250
35627
|
} else {
|
|
35251
35628
|
await saveProviderPreference(userFacingProviderId, newModel, {
|
|
@@ -35285,8 +35662,26 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35285
35662
|
return true;
|
|
35286
35663
|
}
|
|
35287
35664
|
console.log(chalk.yellow("\n No reusable gcloud ADC session was found for Coco."));
|
|
35288
|
-
|
|
35289
|
-
|
|
35665
|
+
console.log();
|
|
35666
|
+
if (adc.message) console.log(chalk.dim(` ${adc.message}`));
|
|
35667
|
+
console.log();
|
|
35668
|
+
const runLoginNow = await p26.confirm({
|
|
35669
|
+
message: "Authenticate with gcloud now from Coco?",
|
|
35670
|
+
initialValue: true
|
|
35671
|
+
});
|
|
35672
|
+
if (p26.isCancel(runLoginNow)) return false;
|
|
35673
|
+
if (runLoginNow) {
|
|
35674
|
+
p26.log.step("Running `gcloud auth application-default login`...");
|
|
35675
|
+
const loginOk = await runGcloudADCLogin();
|
|
35676
|
+
if (loginOk) {
|
|
35677
|
+
const refreshed = await inspectADC();
|
|
35678
|
+
if (refreshed.status === "ok" && refreshed.token) {
|
|
35679
|
+
console.log(chalk.green(" \u2713 gcloud ADC is now configured.\n"));
|
|
35680
|
+
return true;
|
|
35681
|
+
}
|
|
35682
|
+
}
|
|
35683
|
+
p26.log.error("Could not complete gcloud ADC login from Coco.");
|
|
35684
|
+
console.log();
|
|
35290
35685
|
}
|
|
35291
35686
|
console.log(chalk.dim("\n Check the current ADC state with:"));
|
|
35292
35687
|
console.log(chalk.cyan(" $ gcloud auth application-default print-access-token"));
|
|
@@ -35299,9 +35694,9 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35299
35694
|
console.log();
|
|
35300
35695
|
return false;
|
|
35301
35696
|
}
|
|
35302
|
-
async function promptVertexSettings2() {
|
|
35303
|
-
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35304
|
-
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
35697
|
+
async function promptVertexSettings2(defaults) {
|
|
35698
|
+
const projectDefault = defaults?.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35699
|
+
const locationDefault = defaults?.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
35305
35700
|
const project = await p26.text({
|
|
35306
35701
|
message: "Google Cloud project ID:",
|
|
35307
35702
|
placeholder: projectDefault || "my-gcp-project",
|
|
@@ -35951,7 +36346,7 @@ async function showTrustStatus(session, trustStore) {
|
|
|
35951
36346
|
}
|
|
35952
36347
|
const level = trustStore.getLevel(projectPath);
|
|
35953
36348
|
const list = trustStore.list();
|
|
35954
|
-
const project = list.find((
|
|
36349
|
+
const project = list.find((p46) => p46.path === projectPath);
|
|
35955
36350
|
p26.log.message("");
|
|
35956
36351
|
p26.log.message(`\u{1F510} Project Trust Status`);
|
|
35957
36352
|
p26.log.message(` Path: ${projectPath}`);
|
|
@@ -36010,11 +36405,11 @@ async function revokeTrust(session, trustStore) {
|
|
|
36010
36405
|
p26.log.info("This project is not currently trusted");
|
|
36011
36406
|
return;
|
|
36012
36407
|
}
|
|
36013
|
-
const
|
|
36408
|
+
const confirm23 = await p26.confirm({
|
|
36014
36409
|
message: "Revoke all access to this project?",
|
|
36015
36410
|
initialValue: false
|
|
36016
36411
|
});
|
|
36017
|
-
if (p26.isCancel(
|
|
36412
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
36018
36413
|
p26.outro("Cancelled");
|
|
36019
36414
|
return;
|
|
36020
36415
|
}
|
|
@@ -36131,11 +36526,11 @@ var initCommand = {
|
|
|
36131
36526
|
p26.log.message(` Description: ${description}`);
|
|
36132
36527
|
}
|
|
36133
36528
|
p26.log.message("");
|
|
36134
|
-
const
|
|
36529
|
+
const confirm23 = await p26.confirm({
|
|
36135
36530
|
message: "Create project?",
|
|
36136
36531
|
initialValue: true
|
|
36137
36532
|
});
|
|
36138
|
-
if (p26.isCancel(
|
|
36533
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
36139
36534
|
p26.outro("Cancelled");
|
|
36140
36535
|
return false;
|
|
36141
36536
|
}
|
|
@@ -37361,11 +37756,11 @@ async function runInteractiveMode(session) {
|
|
|
37361
37756
|
);
|
|
37362
37757
|
}
|
|
37363
37758
|
console.log();
|
|
37364
|
-
const
|
|
37759
|
+
const confirm23 = await p26.confirm({
|
|
37365
37760
|
message: "Proceed with restoration?",
|
|
37366
37761
|
initialValue: true
|
|
37367
37762
|
});
|
|
37368
|
-
if (p26.isCancel(
|
|
37763
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
37369
37764
|
p26.outro("Cancelled");
|
|
37370
37765
|
return false;
|
|
37371
37766
|
}
|
|
@@ -37408,11 +37803,11 @@ async function runDirectMode(session, checkpointId) {
|
|
|
37408
37803
|
console.log(`${chalk.dim("Conversation:")} ${checkpoint.conversation?.messageCount} messages`);
|
|
37409
37804
|
}
|
|
37410
37805
|
console.log();
|
|
37411
|
-
const
|
|
37806
|
+
const confirm23 = await p26.confirm({
|
|
37412
37807
|
message: "Restore this checkpoint?",
|
|
37413
37808
|
initialValue: true
|
|
37414
37809
|
});
|
|
37415
|
-
if (p26.isCancel(
|
|
37810
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
37416
37811
|
p26.outro("Cancelled");
|
|
37417
37812
|
return false;
|
|
37418
37813
|
}
|
|
@@ -37863,11 +38258,11 @@ async function runInteractiveMode2(session) {
|
|
|
37863
38258
|
return false;
|
|
37864
38259
|
}
|
|
37865
38260
|
displaySessionDetails(selectedSession);
|
|
37866
|
-
const
|
|
38261
|
+
const confirm23 = await p26.confirm({
|
|
37867
38262
|
message: "Resume this session?",
|
|
37868
38263
|
initialValue: true
|
|
37869
38264
|
});
|
|
37870
|
-
if (p26.isCancel(
|
|
38265
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
37871
38266
|
p26.outro("Cancelled");
|
|
37872
38267
|
return false;
|
|
37873
38268
|
}
|
|
@@ -37885,11 +38280,11 @@ async function runDirectMode2(session, sessionId) {
|
|
|
37885
38280
|
return false;
|
|
37886
38281
|
}
|
|
37887
38282
|
displaySessionDetails(targetSession);
|
|
37888
|
-
const
|
|
38283
|
+
const confirm23 = await p26.confirm({
|
|
37889
38284
|
message: "Resume this session?",
|
|
37890
38285
|
initialValue: true
|
|
37891
38286
|
});
|
|
37892
|
-
if (p26.isCancel(
|
|
38287
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
37893
38288
|
p26.outro("Cancelled");
|
|
37894
38289
|
return false;
|
|
37895
38290
|
}
|
|
@@ -37918,8 +38313,8 @@ var STARTUP_TIMEOUT_MS = 5500;
|
|
|
37918
38313
|
var CACHE_DIR = path39__default.join(os4__default.homedir(), ".coco");
|
|
37919
38314
|
var CACHE_FILE = path39__default.join(CACHE_DIR, "version-check-cache.json");
|
|
37920
38315
|
function compareVersions(a, b) {
|
|
37921
|
-
const partsA = a.replace(/^v/, "").split(".").map((
|
|
37922
|
-
const partsB = b.replace(/^v/, "").split(".").map((
|
|
38316
|
+
const partsA = a.replace(/^v/, "").split(".").map((p46) => Number(p46.replace(/-.*$/, "")));
|
|
38317
|
+
const partsB = b.replace(/^v/, "").split(".").map((p46) => Number(p46.replace(/-.*$/, "")));
|
|
37923
38318
|
for (let i = 0; i < 3; i++) {
|
|
37924
38319
|
const numA = partsA[i] ?? 0;
|
|
37925
38320
|
const numB = partsB[i] ?? 0;
|
|
@@ -38043,13 +38438,13 @@ async function checkForUpdatesInteractive() {
|
|
|
38043
38438
|
]);
|
|
38044
38439
|
clearTimeout(startupTimerId);
|
|
38045
38440
|
if (!updateInfo) return;
|
|
38046
|
-
const
|
|
38441
|
+
const p46 = await import('@clack/prompts');
|
|
38047
38442
|
printUpdateBanner(updateInfo);
|
|
38048
|
-
const answer = await
|
|
38443
|
+
const answer = await p46.confirm({
|
|
38049
38444
|
message: "Exit now to update?",
|
|
38050
38445
|
initialValue: true
|
|
38051
38446
|
});
|
|
38052
|
-
if (!
|
|
38447
|
+
if (!p46.isCancel(answer) && answer) {
|
|
38053
38448
|
console.log();
|
|
38054
38449
|
console.log(chalk.dim(` Running: ${updateInfo.updateCommand}`));
|
|
38055
38450
|
console.log();
|
|
@@ -38178,7 +38573,7 @@ function getClipboardCommand() {
|
|
|
38178
38573
|
}
|
|
38179
38574
|
return null;
|
|
38180
38575
|
}
|
|
38181
|
-
async function copyToClipboard(
|
|
38576
|
+
async function copyToClipboard(text15) {
|
|
38182
38577
|
const clipboardCmd = getClipboardCommand();
|
|
38183
38578
|
if (!clipboardCmd) {
|
|
38184
38579
|
return false;
|
|
@@ -38199,7 +38594,7 @@ async function copyToClipboard(text14) {
|
|
|
38199
38594
|
});
|
|
38200
38595
|
xselProc.on("error", () => resolve4(false));
|
|
38201
38596
|
xselProc.on("close", (code) => resolve4(code === 0));
|
|
38202
|
-
xselProc.stdin.write(
|
|
38597
|
+
xselProc.stdin.write(text15);
|
|
38203
38598
|
xselProc.stdin.end();
|
|
38204
38599
|
} catch {
|
|
38205
38600
|
resolve4(false);
|
|
@@ -38215,7 +38610,7 @@ async function copyToClipboard(text14) {
|
|
|
38215
38610
|
});
|
|
38216
38611
|
proc.stdin.on("error", () => {
|
|
38217
38612
|
});
|
|
38218
|
-
proc.stdin.write(
|
|
38613
|
+
proc.stdin.write(text15);
|
|
38219
38614
|
proc.stdin.end();
|
|
38220
38615
|
} catch {
|
|
38221
38616
|
resolve4(false);
|
|
@@ -38902,7 +39297,9 @@ async function loadPermissionPreferences() {
|
|
|
38902
39297
|
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
38903
39298
|
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed,
|
|
38904
39299
|
recommendedAllowlistPrompted: config.recommendedAllowlistPrompted,
|
|
38905
|
-
recommendedAllowlistPromptedProjects: config.recommendedAllowlistPromptedProjects
|
|
39300
|
+
recommendedAllowlistPromptedProjects: config.recommendedAllowlistPromptedProjects,
|
|
39301
|
+
recommendedAllowlistAppliedProjects: config.recommendedAllowlistAppliedProjects,
|
|
39302
|
+
recommendedAllowlistDismissedProjects: config.recommendedAllowlistDismissedProjects
|
|
38906
39303
|
};
|
|
38907
39304
|
} catch {
|
|
38908
39305
|
return {};
|
|
@@ -38922,7 +39319,27 @@ async function savePermissionPreference(key, value) {
|
|
|
38922
39319
|
} catch {
|
|
38923
39320
|
}
|
|
38924
39321
|
}
|
|
38925
|
-
|
|
39322
|
+
function isRecommendedAllowlistAppliedForProject(prefs, projectPath) {
|
|
39323
|
+
const projectKey = getProjectPreferenceKey(projectPath);
|
|
39324
|
+
if (prefs.recommendedAllowlistAppliedProjects?.[projectKey] === true) {
|
|
39325
|
+
return true;
|
|
39326
|
+
}
|
|
39327
|
+
if (prefs.recommendedAllowlistApplied === true && !prefs.recommendedAllowlistAppliedProjects) {
|
|
39328
|
+
return true;
|
|
39329
|
+
}
|
|
39330
|
+
return false;
|
|
39331
|
+
}
|
|
39332
|
+
function isRecommendedAllowlistDismissedForProject(prefs, projectPath) {
|
|
39333
|
+
const projectKey = getProjectPreferenceKey(projectPath);
|
|
39334
|
+
if (prefs.recommendedAllowlistDismissedProjects?.[projectKey] === true) {
|
|
39335
|
+
return true;
|
|
39336
|
+
}
|
|
39337
|
+
if (prefs.recommendedAllowlistDismissed === true && !prefs.recommendedAllowlistDismissedProjects) {
|
|
39338
|
+
return true;
|
|
39339
|
+
}
|
|
39340
|
+
return false;
|
|
39341
|
+
}
|
|
39342
|
+
async function saveProjectPermissionPreference(key, projectPath, value) {
|
|
38926
39343
|
try {
|
|
38927
39344
|
let config = {};
|
|
38928
39345
|
try {
|
|
@@ -38930,12 +39347,12 @@ async function markPermissionSuggestionShownForProject(projectPath) {
|
|
|
38930
39347
|
config = JSON.parse(content);
|
|
38931
39348
|
} catch {
|
|
38932
39349
|
}
|
|
38933
|
-
const
|
|
38934
|
-
|
|
38935
|
-
|
|
39350
|
+
const projectKey = getProjectPreferenceKey(projectPath);
|
|
39351
|
+
const currentMap = config[key] ?? {};
|
|
39352
|
+
config[key] = {
|
|
39353
|
+
...currentMap,
|
|
39354
|
+
[projectKey]: value
|
|
38936
39355
|
};
|
|
38937
|
-
config.recommendedAllowlistPromptedProjects = promptedProjects;
|
|
38938
|
-
config.recommendedAllowlistPrompted = true;
|
|
38939
39356
|
await fs35__default.mkdir(path39__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
38940
39357
|
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
38941
39358
|
} catch {
|
|
@@ -38943,30 +39360,30 @@ async function markPermissionSuggestionShownForProject(projectPath) {
|
|
|
38943
39360
|
}
|
|
38944
39361
|
async function shouldShowPermissionSuggestion(projectPath = process.cwd()) {
|
|
38945
39362
|
const prefs = await loadPermissionPreferences();
|
|
38946
|
-
if (prefs
|
|
39363
|
+
if (isRecommendedAllowlistDismissedForProject(prefs, projectPath)) {
|
|
38947
39364
|
return false;
|
|
38948
39365
|
}
|
|
38949
|
-
if (prefs
|
|
38950
|
-
return false;
|
|
38951
|
-
}
|
|
38952
|
-
const projectKey = getProjectPreferenceKey(projectPath);
|
|
38953
|
-
if (prefs.recommendedAllowlistPromptedProjects?.[projectKey]) {
|
|
39366
|
+
if (isRecommendedAllowlistAppliedForProject(prefs, projectPath)) {
|
|
38954
39367
|
return false;
|
|
38955
39368
|
}
|
|
38956
39369
|
return true;
|
|
38957
39370
|
}
|
|
38958
|
-
async function applyRecommendedPermissions() {
|
|
39371
|
+
async function applyRecommendedPermissions(projectPath = process.cwd()) {
|
|
38959
39372
|
for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
|
|
38960
|
-
await saveTrustedTool(tool,
|
|
39373
|
+
await saveTrustedTool(tool, projectPath, false);
|
|
38961
39374
|
}
|
|
38962
|
-
await
|
|
39375
|
+
await saveProjectPermissionPreference("recommendedAllowlistAppliedProjects", projectPath, true);
|
|
39376
|
+
await saveProjectPermissionPreference(
|
|
39377
|
+
"recommendedAllowlistDismissedProjects",
|
|
39378
|
+
projectPath,
|
|
39379
|
+
false
|
|
39380
|
+
);
|
|
38963
39381
|
}
|
|
38964
39382
|
async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
38965
|
-
await markPermissionSuggestionShownForProject(projectPath);
|
|
38966
39383
|
console.log();
|
|
38967
39384
|
console.log(chalk.magenta.bold(" \u{1F4CB} Recommended Permissions"));
|
|
38968
39385
|
console.log();
|
|
38969
|
-
console.log(chalk.dim(" Coco has a curated set of tool permissions for
|
|
39386
|
+
console.log(chalk.dim(" Coco has a curated set of tool permissions for this project:"));
|
|
38970
39387
|
console.log(chalk.dim(" \u2022 Allow: file read/write, search, git staging, build, tests..."));
|
|
38971
39388
|
console.log(
|
|
38972
39389
|
chalk.dim(" \u2022 Ask each time: git commit, curl, rm, git pull, docker exec, cloud...")
|
|
@@ -38975,12 +39392,17 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
|
38975
39392
|
console.log();
|
|
38976
39393
|
console.log(chalk.dim(" Stored in ~/.coco/trusted-tools.json \u2014 edit manually or let"));
|
|
38977
39394
|
console.log(chalk.dim(" Coco manage it when you approve actions from the prompt."));
|
|
39395
|
+
console.log(chalk.dim(" Note: applying here affects only the current project."));
|
|
38978
39396
|
console.log();
|
|
38979
39397
|
const action = await p26.select({
|
|
38980
39398
|
message: "Apply recommended permissions?",
|
|
38981
39399
|
options: [
|
|
38982
39400
|
{ value: "view", label: "View details", hint: "See the full list before deciding" },
|
|
38983
|
-
{
|
|
39401
|
+
{
|
|
39402
|
+
value: "apply",
|
|
39403
|
+
label: "Apply",
|
|
39404
|
+
hint: "Apply recommended permissions for this project"
|
|
39405
|
+
},
|
|
38984
39406
|
{ value: "later", label: "Later", hint: "Remind me next time" },
|
|
38985
39407
|
{ value: "dismiss", label: "No thanks", hint: "Don't show again" }
|
|
38986
39408
|
]
|
|
@@ -38989,8 +39411,11 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
|
38989
39411
|
return;
|
|
38990
39412
|
}
|
|
38991
39413
|
if (action === "dismiss") {
|
|
38992
|
-
await
|
|
38993
|
-
|
|
39414
|
+
await saveProjectPermissionPreference(
|
|
39415
|
+
"recommendedAllowlistDismissedProjects",
|
|
39416
|
+
projectPath,
|
|
39417
|
+
true
|
|
39418
|
+
);
|
|
38994
39419
|
console.log(chalk.dim(" Won't show again. Use /permissions to apply later."));
|
|
38995
39420
|
return;
|
|
38996
39421
|
}
|
|
@@ -39004,8 +39429,7 @@ async function showPermissionSuggestion(projectPath = process.cwd()) {
|
|
|
39004
39429
|
return;
|
|
39005
39430
|
}
|
|
39006
39431
|
}
|
|
39007
|
-
await applyRecommendedPermissions();
|
|
39008
|
-
await savePermissionPreference("recommendedAllowlistPrompted", true);
|
|
39432
|
+
await applyRecommendedPermissions(projectPath);
|
|
39009
39433
|
console.log(chalk.green(" \u2713 Recommended permissions applied"));
|
|
39010
39434
|
console.log(chalk.dim(" Use /permissions to review or modify anytime."));
|
|
39011
39435
|
}
|
|
@@ -39096,7 +39520,7 @@ async function showStatus(session) {
|
|
|
39096
39520
|
console.log(chalk.magenta.bold(" \u{1F510} Tool Permissions"));
|
|
39097
39521
|
console.log();
|
|
39098
39522
|
const allowCount = RECOMMENDED_GLOBAL.length + RECOMMENDED_PROJECT.length;
|
|
39099
|
-
if (prefs.
|
|
39523
|
+
if (isRecommendedAllowlistAppliedForProject(prefs, session.projectPath)) {
|
|
39100
39524
|
console.log(
|
|
39101
39525
|
chalk.green(" \u2713 Recommended allowlist applied") + chalk.dim(` (${allowCount} allow, ${RECOMMENDED_DENY.length} deny)`)
|
|
39102
39526
|
);
|
|
@@ -39138,7 +39562,7 @@ async function showStatus(session) {
|
|
|
39138
39562
|
console.log();
|
|
39139
39563
|
}
|
|
39140
39564
|
async function applyRecommended(session) {
|
|
39141
|
-
await applyRecommendedPermissions();
|
|
39565
|
+
await applyRecommendedPermissions(session.projectPath);
|
|
39142
39566
|
for (const tool of RECOMMENDED_GLOBAL) {
|
|
39143
39567
|
session.trustedTools.add(tool);
|
|
39144
39568
|
}
|
|
@@ -39188,177 +39612,18 @@ async function resetPermissions(session) {
|
|
|
39188
39612
|
} catch {
|
|
39189
39613
|
}
|
|
39190
39614
|
await savePermissionPreference("recommendedAllowlistApplied", false);
|
|
39191
|
-
|
|
39192
|
-
|
|
39193
|
-
|
|
39194
|
-
|
|
39195
|
-
init_paths();
|
|
39196
|
-
var qualityLoopEnabled = true;
|
|
39197
|
-
var hintShown = false;
|
|
39198
|
-
function isQualityLoop() {
|
|
39199
|
-
return qualityLoopEnabled;
|
|
39200
|
-
}
|
|
39201
|
-
function setQualityLoop(enabled) {
|
|
39202
|
-
qualityLoopEnabled = enabled;
|
|
39203
|
-
}
|
|
39204
|
-
function wasHintShown() {
|
|
39205
|
-
return hintShown;
|
|
39206
|
-
}
|
|
39207
|
-
function markHintShown() {
|
|
39208
|
-
hintShown = true;
|
|
39209
|
-
}
|
|
39210
|
-
function looksLikeFeatureRequest(input) {
|
|
39211
|
-
const trimmed = input.trim();
|
|
39212
|
-
if (trimmed.length < 20) return false;
|
|
39213
|
-
if (trimmed.endsWith("?") && trimmed.length < 80) return false;
|
|
39214
|
-
const featureKeywords = [
|
|
39215
|
-
/\bimplement/i,
|
|
39216
|
-
/\bcreate\b/i,
|
|
39217
|
-
/\bbuild\b/i,
|
|
39218
|
-
/\badd\b.*\b(feature|function|component|endpoint|service|module|class)/i,
|
|
39219
|
-
/\brefactor/i,
|
|
39220
|
-
/\bmigrate/i,
|
|
39221
|
-
/\bsetup\b/i,
|
|
39222
|
-
/\bintegrate/i,
|
|
39223
|
-
/\bwrite\b.*\b(code|function|test|module)/i,
|
|
39224
|
-
/\bdevelop/i,
|
|
39225
|
-
/\bdesign\b/i,
|
|
39226
|
-
/\bfix\b.*\b(bug|issue|error|problem)/i,
|
|
39227
|
-
/\bupdate\b.*\b(function|component|service|module)/i,
|
|
39228
|
-
/\bgenerate\b/i,
|
|
39229
|
-
/\bconvert\b/i
|
|
39230
|
-
];
|
|
39231
|
-
return featureKeywords.some((re) => re.test(trimmed));
|
|
39232
|
-
}
|
|
39233
|
-
function formatQualityLoopHint() {
|
|
39234
|
-
return chalk.dim(" tip: ") + chalk.magenta("/quality") + chalk.dim(" enables auto-test & iterate until quality converges");
|
|
39235
|
-
}
|
|
39236
|
-
function formatQualityResult(result) {
|
|
39237
|
-
const lines = [];
|
|
39238
|
-
const scores = result.scoreHistory;
|
|
39239
|
-
const progressStr = scores.map((s) => String(s)).join(" \u2192 ");
|
|
39240
|
-
const convergedLabel = result.converged ? chalk.green("converged") : chalk.yellow("max iterations");
|
|
39241
|
-
lines.push("");
|
|
39242
|
-
lines.push(
|
|
39243
|
-
chalk.magenta("\u2500\u2500 Quality: ") + chalk.white(progressStr) + chalk.dim(` (${convergedLabel})`) + chalk.magenta(" \u2500\u2500")
|
|
39615
|
+
await saveProjectPermissionPreference(
|
|
39616
|
+
"recommendedAllowlistAppliedProjects",
|
|
39617
|
+
session.projectPath,
|
|
39618
|
+
false
|
|
39244
39619
|
);
|
|
39245
|
-
|
|
39246
|
-
|
|
39247
|
-
|
|
39248
|
-
|
|
39249
|
-
|
|
39250
|
-
|
|
39251
|
-
const covColor = result.coverage >= 80 ? chalk.green : chalk.yellow;
|
|
39252
|
-
parts.push(covColor(`Coverage: ${result.coverage}%`));
|
|
39253
|
-
}
|
|
39254
|
-
if (result.securityScore !== void 0) {
|
|
39255
|
-
const secColor = result.securityScore === 100 ? chalk.green : chalk.red;
|
|
39256
|
-
parts.push(secColor(`Security: ${result.securityScore}`));
|
|
39257
|
-
}
|
|
39258
|
-
parts.push(chalk.dim(`Iterations: ${result.iterations}`));
|
|
39259
|
-
if (result.durationMs !== void 0) {
|
|
39260
|
-
const secs = (result.durationMs / 1e3).toFixed(1);
|
|
39261
|
-
parts.push(chalk.dim(`Time: ${secs}s`));
|
|
39262
|
-
}
|
|
39263
|
-
lines.push(" " + parts.join(" "));
|
|
39264
|
-
lines.push("");
|
|
39265
|
-
return lines.join("\n");
|
|
39266
|
-
}
|
|
39267
|
-
async function loadQualityLoopPreference() {
|
|
39268
|
-
try {
|
|
39269
|
-
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
39270
|
-
const config = JSON.parse(content);
|
|
39271
|
-
const value = config.qualityLoop ?? config.cocoMode;
|
|
39272
|
-
if (typeof value === "boolean") {
|
|
39273
|
-
qualityLoopEnabled = value;
|
|
39274
|
-
return value;
|
|
39275
|
-
}
|
|
39276
|
-
} catch {
|
|
39277
|
-
}
|
|
39278
|
-
return true;
|
|
39279
|
-
}
|
|
39280
|
-
async function saveQualityLoopPreference(enabled) {
|
|
39281
|
-
try {
|
|
39282
|
-
let config = {};
|
|
39283
|
-
try {
|
|
39284
|
-
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
39285
|
-
config = JSON.parse(content);
|
|
39286
|
-
} catch {
|
|
39287
|
-
}
|
|
39288
|
-
config.qualityLoop = enabled;
|
|
39289
|
-
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
39290
|
-
} catch {
|
|
39291
|
-
}
|
|
39292
|
-
}
|
|
39293
|
-
function parseQualityLoopReport(content) {
|
|
39294
|
-
const marker = "QUALITY_LOOP_REPORT";
|
|
39295
|
-
const idx = content.indexOf(marker);
|
|
39296
|
-
if (idx === -1) return null;
|
|
39297
|
-
const block = content.slice(idx);
|
|
39298
|
-
const getField = (name) => {
|
|
39299
|
-
const match = block.match(new RegExp(`${name}:\\s*(.+)`));
|
|
39300
|
-
return match?.[1]?.trim();
|
|
39301
|
-
};
|
|
39302
|
-
const scoreHistoryRaw = getField("score_history");
|
|
39303
|
-
if (!scoreHistoryRaw) return null;
|
|
39304
|
-
const scores = scoreHistoryRaw.replace(/[[\]]/g, "").split(",").map((s) => parseFloat(s.trim())).filter((n) => !isNaN(n));
|
|
39305
|
-
if (scores.length === 0) return null;
|
|
39306
|
-
const testsPassed = parseInt(getField("tests_passed") ?? "", 10);
|
|
39307
|
-
const testsTotal = parseInt(getField("tests_total") ?? "", 10);
|
|
39308
|
-
const coverage = parseInt(getField("coverage") ?? "", 10);
|
|
39309
|
-
const security = parseInt(getField("security") ?? "", 10);
|
|
39310
|
-
const iterations = parseInt(getField("iterations") ?? "", 10) || scores.length;
|
|
39311
|
-
const converged = getField("converged") === "true";
|
|
39312
|
-
return {
|
|
39313
|
-
converged,
|
|
39314
|
-
scoreHistory: scores,
|
|
39315
|
-
finalScore: scores[scores.length - 1] ?? 0,
|
|
39316
|
-
iterations,
|
|
39317
|
-
testsPassed: isNaN(testsPassed) ? void 0 : testsPassed,
|
|
39318
|
-
testsTotal: isNaN(testsTotal) ? void 0 : testsTotal,
|
|
39319
|
-
coverage: isNaN(coverage) ? void 0 : coverage,
|
|
39320
|
-
securityScore: isNaN(security) ? void 0 : security
|
|
39321
|
-
};
|
|
39322
|
-
}
|
|
39323
|
-
function getQualityLoopSystemPrompt() {
|
|
39324
|
-
return `
|
|
39325
|
-
## Quality Loop Mode (ACTIVE)
|
|
39326
|
-
|
|
39327
|
-
You are operating in quality loop mode. After implementing code changes, you MUST follow this iteration cycle:
|
|
39328
|
-
|
|
39329
|
-
1. **Implement** the requested changes (code + tests)
|
|
39330
|
-
2. **Run tests** using the run_tests or bash_exec tool
|
|
39331
|
-
3. **Self-review**: Analyze your code against these 12 quality dimensions:
|
|
39332
|
-
- Correctness, Completeness, Robustness, Readability
|
|
39333
|
-
- Maintainability, Complexity, Duplication, Test Coverage
|
|
39334
|
-
- Test Quality, Security, Documentation, Style
|
|
39335
|
-
4. **Score** your implementation 0-100 for each dimension
|
|
39336
|
-
5. **If issues found**: Fix them and go back to step 2
|
|
39337
|
-
6. **If quality is good** (overall \u2265 85 and improving < 2 points): Stop and report
|
|
39338
|
-
|
|
39339
|
-
After completing the cycle, output a quality summary in this exact format:
|
|
39340
|
-
|
|
39341
|
-
\`\`\`
|
|
39342
|
-
QUALITY_LOOP_REPORT
|
|
39343
|
-
score_history: [first_score, ..., final_score]
|
|
39344
|
-
tests_passed: X
|
|
39345
|
-
tests_total: Y
|
|
39346
|
-
coverage: Z
|
|
39347
|
-
security: 100
|
|
39348
|
-
iterations: N
|
|
39349
|
-
converged: true|false
|
|
39350
|
-
\`\`\`
|
|
39351
|
-
|
|
39352
|
-
Key rules:
|
|
39353
|
-
- Always write tests alongside code
|
|
39354
|
-
- Run tests after every change
|
|
39355
|
-
- Minimum 2 iterations before declaring convergence
|
|
39356
|
-
- Maximum 10 iterations
|
|
39357
|
-
- Fix critical issues before moving on
|
|
39358
|
-
- Report honestly - don't inflate scores`;
|
|
39620
|
+
await saveProjectPermissionPreference(
|
|
39621
|
+
"recommendedAllowlistDismissedProjects",
|
|
39622
|
+
session.projectPath,
|
|
39623
|
+
false
|
|
39624
|
+
);
|
|
39625
|
+
console.log(chalk.green(" \u2713 All tool permissions reset."));
|
|
39359
39626
|
}
|
|
39360
|
-
|
|
39361
|
-
// src/cli/repl/commands/quality.ts
|
|
39362
39627
|
var qualityCommand = {
|
|
39363
39628
|
name: "quality",
|
|
39364
39629
|
aliases: ["coco"],
|
|
@@ -39949,9 +40214,9 @@ var UserCancelledError = class extends Error {
|
|
|
39949
40214
|
var SPEC_AGENT_SYSTEM = `You are a senior technical product manager specialising in rapid MVP delivery.
|
|
39950
40215
|
Your job is to help a developer plan a software project efficiently and honestly.
|
|
39951
40216
|
Always respond with valid JSON only \u2014 no markdown fences, no prose outside JSON.`;
|
|
39952
|
-
function extractJson2(
|
|
39953
|
-
const match =
|
|
39954
|
-
return match ? (match[1] ??
|
|
40217
|
+
function extractJson2(text15) {
|
|
40218
|
+
const match = text15.match(/```(?:json)?\s*([\s\S]*?)```/) ?? text15.match(/(\{[\s\S]*\})/);
|
|
40219
|
+
return match ? (match[1] ?? text15).trim() : text15.trim();
|
|
39955
40220
|
}
|
|
39956
40221
|
function validateBacklogSpec(raw) {
|
|
39957
40222
|
if (!raw.sprints || raw.sprints.length === 0) {
|
|
@@ -40129,11 +40394,11 @@ Response format (JSON only, no prose):
|
|
|
40129
40394
|
}
|
|
40130
40395
|
}
|
|
40131
40396
|
if (!options?.skipConfirmation) {
|
|
40132
|
-
const
|
|
40397
|
+
const confirm23 = await p26.confirm({
|
|
40133
40398
|
message: "Start building with this plan?",
|
|
40134
40399
|
initialValue: true
|
|
40135
40400
|
});
|
|
40136
|
-
if (p26.isCancel(
|
|
40401
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
40137
40402
|
cancel5("Build cancelled.");
|
|
40138
40403
|
}
|
|
40139
40404
|
}
|
|
@@ -41691,8 +41956,8 @@ Examples:
|
|
|
41691
41956
|
recursive: z.boolean().optional().default(false).describe("Delete directories recursively"),
|
|
41692
41957
|
confirm: z.boolean().optional().describe("Must be true to confirm deletion")
|
|
41693
41958
|
}),
|
|
41694
|
-
async execute({ path: filePath, recursive, confirm:
|
|
41695
|
-
if (
|
|
41959
|
+
async execute({ path: filePath, recursive, confirm: confirm23 }) {
|
|
41960
|
+
if (confirm23 !== true) {
|
|
41696
41961
|
throw new ToolError(
|
|
41697
41962
|
"Deletion requires explicit confirmation. Set confirm: true to proceed.",
|
|
41698
41963
|
{ tool: "delete_file" }
|
|
@@ -43592,15 +43857,15 @@ ${message}
|
|
|
43592
43857
|
let stdoutBuffer = "";
|
|
43593
43858
|
let stderrBuffer = "";
|
|
43594
43859
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43595
|
-
const
|
|
43596
|
-
stdoutBuffer +=
|
|
43597
|
-
process.stdout.write(
|
|
43860
|
+
const text15 = chunk.toString();
|
|
43861
|
+
stdoutBuffer += text15;
|
|
43862
|
+
process.stdout.write(text15);
|
|
43598
43863
|
heartbeat.activity();
|
|
43599
43864
|
});
|
|
43600
43865
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43601
|
-
const
|
|
43602
|
-
stderrBuffer +=
|
|
43603
|
-
process.stderr.write(
|
|
43866
|
+
const text15 = chunk.toString();
|
|
43867
|
+
stderrBuffer += text15;
|
|
43868
|
+
process.stderr.write(text15);
|
|
43604
43869
|
heartbeat.activity();
|
|
43605
43870
|
});
|
|
43606
43871
|
const result = await subprocess;
|
|
@@ -43717,15 +43982,15 @@ ${message}
|
|
|
43717
43982
|
let stdoutBuffer = "";
|
|
43718
43983
|
let stderrBuffer = "";
|
|
43719
43984
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43720
|
-
const
|
|
43721
|
-
stdoutBuffer +=
|
|
43722
|
-
process.stdout.write(
|
|
43985
|
+
const text15 = chunk.toString();
|
|
43986
|
+
stdoutBuffer += text15;
|
|
43987
|
+
process.stdout.write(text15);
|
|
43723
43988
|
heartbeat.activity();
|
|
43724
43989
|
});
|
|
43725
43990
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43726
|
-
const
|
|
43727
|
-
stderrBuffer +=
|
|
43728
|
-
process.stderr.write(
|
|
43991
|
+
const text15 = chunk.toString();
|
|
43992
|
+
stderrBuffer += text15;
|
|
43993
|
+
process.stderr.write(text15);
|
|
43729
43994
|
heartbeat.activity();
|
|
43730
43995
|
});
|
|
43731
43996
|
const result = await subprocess;
|
|
@@ -43819,15 +44084,15 @@ ${message}
|
|
|
43819
44084
|
let stdoutBuffer = "";
|
|
43820
44085
|
let stderrBuffer = "";
|
|
43821
44086
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43822
|
-
const
|
|
43823
|
-
stdoutBuffer +=
|
|
43824
|
-
process.stdout.write(
|
|
44087
|
+
const text15 = chunk.toString();
|
|
44088
|
+
stdoutBuffer += text15;
|
|
44089
|
+
process.stdout.write(text15);
|
|
43825
44090
|
heartbeat.activity();
|
|
43826
44091
|
});
|
|
43827
44092
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43828
|
-
const
|
|
43829
|
-
stderrBuffer +=
|
|
43830
|
-
process.stderr.write(
|
|
44093
|
+
const text15 = chunk.toString();
|
|
44094
|
+
stderrBuffer += text15;
|
|
44095
|
+
process.stderr.write(text15);
|
|
43831
44096
|
heartbeat.activity();
|
|
43832
44097
|
});
|
|
43833
44098
|
const result = await subprocess;
|
|
@@ -43922,15 +44187,15 @@ ${message}
|
|
|
43922
44187
|
let stdoutBuffer = "";
|
|
43923
44188
|
let stderrBuffer = "";
|
|
43924
44189
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43925
|
-
const
|
|
43926
|
-
stdoutBuffer +=
|
|
43927
|
-
process.stdout.write(
|
|
44190
|
+
const text15 = chunk.toString();
|
|
44191
|
+
stdoutBuffer += text15;
|
|
44192
|
+
process.stdout.write(text15);
|
|
43928
44193
|
heartbeat.activity();
|
|
43929
44194
|
});
|
|
43930
44195
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43931
|
-
const
|
|
43932
|
-
stderrBuffer +=
|
|
43933
|
-
process.stderr.write(
|
|
44196
|
+
const text15 = chunk.toString();
|
|
44197
|
+
stderrBuffer += text15;
|
|
44198
|
+
process.stderr.write(text15);
|
|
43934
44199
|
heartbeat.activity();
|
|
43935
44200
|
});
|
|
43936
44201
|
const result = await subprocess;
|
|
@@ -44026,15 +44291,15 @@ ${message}
|
|
|
44026
44291
|
let stdoutBuffer = "";
|
|
44027
44292
|
let stderrBuffer = "";
|
|
44028
44293
|
subprocess.stdout?.on("data", (chunk) => {
|
|
44029
|
-
const
|
|
44030
|
-
stdoutBuffer +=
|
|
44031
|
-
process.stdout.write(
|
|
44294
|
+
const text15 = chunk.toString();
|
|
44295
|
+
stdoutBuffer += text15;
|
|
44296
|
+
process.stdout.write(text15);
|
|
44032
44297
|
heartbeat.activity();
|
|
44033
44298
|
});
|
|
44034
44299
|
subprocess.stderr?.on("data", (chunk) => {
|
|
44035
|
-
const
|
|
44036
|
-
stderrBuffer +=
|
|
44037
|
-
process.stderr.write(
|
|
44300
|
+
const text15 = chunk.toString();
|
|
44301
|
+
stderrBuffer += text15;
|
|
44302
|
+
process.stderr.write(text15);
|
|
44038
44303
|
heartbeat.activity();
|
|
44039
44304
|
});
|
|
44040
44305
|
const result = await subprocess;
|
|
@@ -44113,15 +44378,15 @@ ${message}
|
|
|
44113
44378
|
let stdoutBuffer = "";
|
|
44114
44379
|
let stderrBuffer = "";
|
|
44115
44380
|
subprocess.stdout?.on("data", (chunk) => {
|
|
44116
|
-
const
|
|
44117
|
-
stdoutBuffer +=
|
|
44118
|
-
process.stdout.write(
|
|
44381
|
+
const text15 = chunk.toString();
|
|
44382
|
+
stdoutBuffer += text15;
|
|
44383
|
+
process.stdout.write(text15);
|
|
44119
44384
|
heartbeat.activity();
|
|
44120
44385
|
});
|
|
44121
44386
|
subprocess.stderr?.on("data", (chunk) => {
|
|
44122
|
-
const
|
|
44123
|
-
stderrBuffer +=
|
|
44124
|
-
process.stderr.write(
|
|
44387
|
+
const text15 = chunk.toString();
|
|
44388
|
+
stderrBuffer += text15;
|
|
44389
|
+
process.stderr.write(text15);
|
|
44125
44390
|
heartbeat.activity();
|
|
44126
44391
|
});
|
|
44127
44392
|
const result = await subprocess;
|
|
@@ -44612,16 +44877,16 @@ function htmlToMarkdown(html) {
|
|
|
44612
44877
|
const prefix = "#".repeat(i);
|
|
44613
44878
|
const regex = new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, "gi");
|
|
44614
44879
|
md = md.replace(regex, (_, content) => {
|
|
44615
|
-
const
|
|
44616
|
-
return
|
|
44880
|
+
const text15 = content.replace(/<[^>]*>/g, "").trim();
|
|
44881
|
+
return text15 ? `
|
|
44617
44882
|
|
|
44618
|
-
${prefix} ${
|
|
44883
|
+
${prefix} ${text15}
|
|
44619
44884
|
|
|
44620
44885
|
` : "";
|
|
44621
44886
|
});
|
|
44622
44887
|
}
|
|
44623
|
-
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href,
|
|
44624
|
-
const cleanText =
|
|
44888
|
+
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text15) => {
|
|
44889
|
+
const cleanText = text15.replace(/<[^>]*>/g, "").trim();
|
|
44625
44890
|
if (!cleanText) return "";
|
|
44626
44891
|
if (href.startsWith("#") || href.startsWith("javascript:")) return cleanText;
|
|
44627
44892
|
return `[${cleanText}](${href})`;
|
|
@@ -44648,8 +44913,8 @@ ${decoded.trim()}
|
|
|
44648
44913
|
});
|
|
44649
44914
|
md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, items) => {
|
|
44650
44915
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44651
|
-
const
|
|
44652
|
-
return
|
|
44916
|
+
const text15 = item.replace(/<[^>]*>/g, "").trim();
|
|
44917
|
+
return text15 ? `- ${text15}
|
|
44653
44918
|
` : "";
|
|
44654
44919
|
}) + "\n";
|
|
44655
44920
|
});
|
|
@@ -44657,29 +44922,29 @@ ${decoded.trim()}
|
|
|
44657
44922
|
let counter = 0;
|
|
44658
44923
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44659
44924
|
counter++;
|
|
44660
|
-
const
|
|
44661
|
-
return
|
|
44925
|
+
const text15 = item.replace(/<[^>]*>/g, "").trim();
|
|
44926
|
+
return text15 ? `${counter}. ${text15}
|
|
44662
44927
|
` : "";
|
|
44663
44928
|
}) + "\n";
|
|
44664
44929
|
});
|
|
44665
44930
|
md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
|
|
44666
|
-
const
|
|
44667
|
-
return
|
|
44931
|
+
const text15 = content.replace(/<[^>]*>/g, "").trim();
|
|
44932
|
+
return text15 ? "\n" + text15.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
|
|
44668
44933
|
});
|
|
44669
44934
|
md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => {
|
|
44670
|
-
const
|
|
44671
|
-
return
|
|
44935
|
+
const text15 = content.replace(/<[^>]*>/g, "").trim();
|
|
44936
|
+
return text15 ? `
|
|
44672
44937
|
|
|
44673
|
-
${
|
|
44938
|
+
${text15}
|
|
44674
44939
|
|
|
44675
44940
|
` : "";
|
|
44676
44941
|
});
|
|
44677
44942
|
md = md.replace(/<br\s*\/?>/gi, "\n");
|
|
44678
44943
|
md = md.replace(
|
|
44679
44944
|
/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,
|
|
44680
|
-
(_,
|
|
44945
|
+
(_, text15) => `**${text15.trim()}**`
|
|
44681
44946
|
);
|
|
44682
|
-
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_,
|
|
44947
|
+
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text15) => `*${text15.trim()}*`);
|
|
44683
44948
|
md = md.replace(/<hr\s*\/?>/gi, "\n---\n");
|
|
44684
44949
|
md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
44685
44950
|
const rows = [];
|
|
@@ -45809,10 +46074,10 @@ function chunkContent(content, chunkSize) {
|
|
|
45809
46074
|
const chunks = [];
|
|
45810
46075
|
for (let i = 0; i < lines.length; i += chunkSize) {
|
|
45811
46076
|
const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
|
|
45812
|
-
const
|
|
45813
|
-
if (
|
|
46077
|
+
const text15 = chunkLines.join("\n").trim();
|
|
46078
|
+
if (text15.length > 10) {
|
|
45814
46079
|
chunks.push({
|
|
45815
|
-
text:
|
|
46080
|
+
text: text15,
|
|
45816
46081
|
startLine: i + 1,
|
|
45817
46082
|
endLine: Math.min(i + chunkSize, lines.length)
|
|
45818
46083
|
});
|
|
@@ -45820,8 +46085,8 @@ function chunkContent(content, chunkSize) {
|
|
|
45820
46085
|
}
|
|
45821
46086
|
return chunks;
|
|
45822
46087
|
}
|
|
45823
|
-
function simpleEmbedding(
|
|
45824
|
-
const words =
|
|
46088
|
+
function simpleEmbedding(text15) {
|
|
46089
|
+
const words = text15.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
|
|
45825
46090
|
const freq = /* @__PURE__ */ new Map();
|
|
45826
46091
|
for (const word of words) {
|
|
45827
46092
|
freq.set(word, (freq.get(word) ?? 0) + 1);
|
|
@@ -45847,7 +46112,7 @@ function simpleEmbedding(text14) {
|
|
|
45847
46112
|
}
|
|
45848
46113
|
var embedFn = null;
|
|
45849
46114
|
var usingFallbackEmbedding = false;
|
|
45850
|
-
async function getEmbedding(
|
|
46115
|
+
async function getEmbedding(text15) {
|
|
45851
46116
|
if (!embedFn) {
|
|
45852
46117
|
try {
|
|
45853
46118
|
const transformers = await import('@xenova/transformers');
|
|
@@ -45864,7 +46129,7 @@ async function getEmbedding(text14) {
|
|
|
45864
46129
|
usingFallbackEmbedding = true;
|
|
45865
46130
|
}
|
|
45866
46131
|
}
|
|
45867
|
-
return embedFn(
|
|
46132
|
+
return embedFn(text15);
|
|
45868
46133
|
}
|
|
45869
46134
|
async function loadIndex2(indexDir) {
|
|
45870
46135
|
try {
|
|
@@ -46417,23 +46682,23 @@ Examples:
|
|
|
46417
46682
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
46418
46683
|
max: maxPages
|
|
46419
46684
|
});
|
|
46420
|
-
let
|
|
46685
|
+
let text15 = pdfData.text;
|
|
46421
46686
|
let truncated = false;
|
|
46422
46687
|
const totalPages = pdfData.numpages;
|
|
46423
46688
|
if (pages) {
|
|
46424
46689
|
const range = parsePageRange(pages, totalPages);
|
|
46425
|
-
const pageTexts =
|
|
46690
|
+
const pageTexts = text15.split(/\f/);
|
|
46426
46691
|
if (pageTexts.length > 1) {
|
|
46427
46692
|
const selectedPages = pageTexts.slice(range.start - 1, range.end);
|
|
46428
|
-
|
|
46693
|
+
text15 = selectedPages.join("\n\n--- Page Break ---\n\n");
|
|
46429
46694
|
}
|
|
46430
46695
|
}
|
|
46431
|
-
if (
|
|
46432
|
-
|
|
46696
|
+
if (text15.length > 5e5) {
|
|
46697
|
+
text15 = text15.slice(0, 5e5);
|
|
46433
46698
|
truncated = true;
|
|
46434
46699
|
}
|
|
46435
46700
|
return {
|
|
46436
|
-
text:
|
|
46701
|
+
text: text15,
|
|
46437
46702
|
pages: totalPages,
|
|
46438
46703
|
metadata: {
|
|
46439
46704
|
title: pdfData.info?.Title,
|
|
@@ -47447,7 +47712,8 @@ var SuggestImprovementsSchema = z.object({
|
|
|
47447
47712
|
context: z.string().optional().describe("Additional context about the code")
|
|
47448
47713
|
});
|
|
47449
47714
|
async function analyzeAndSuggest(filePath, _context) {
|
|
47450
|
-
const
|
|
47715
|
+
const rawContent = await fs46.readFile(filePath, "utf-8");
|
|
47716
|
+
const content = typeof rawContent === "string" ? rawContent : String(rawContent ?? "");
|
|
47451
47717
|
const lines = content.split("\n");
|
|
47452
47718
|
const suggestions = [];
|
|
47453
47719
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -47812,11 +48078,11 @@ var getLearnedPatternsTool = defineTool({
|
|
|
47812
48078
|
const patterns = store.getFrequentPatterns(typedInput.limit);
|
|
47813
48079
|
return {
|
|
47814
48080
|
totalPatterns: patterns.length,
|
|
47815
|
-
patterns: patterns.map((
|
|
47816
|
-
pattern:
|
|
47817
|
-
preference:
|
|
47818
|
-
frequency:
|
|
47819
|
-
lastUsed: new Date(
|
|
48081
|
+
patterns: patterns.map((p46) => ({
|
|
48082
|
+
pattern: p46.pattern,
|
|
48083
|
+
preference: p46.userPreference,
|
|
48084
|
+
frequency: p46.frequency,
|
|
48085
|
+
lastUsed: new Date(p46.lastUsed).toISOString()
|
|
47820
48086
|
}))
|
|
47821
48087
|
};
|
|
47822
48088
|
}
|
|
@@ -48675,11 +48941,11 @@ var buildAppCommand = {
|
|
|
48675
48941
|
return false;
|
|
48676
48942
|
}
|
|
48677
48943
|
if (!isAutonomous && !parsed.skipConfirmation) {
|
|
48678
|
-
const
|
|
48944
|
+
const confirm23 = await p26.confirm({
|
|
48679
48945
|
message: `Build "${spec.projectName}" with ${spec.sprints.length} sprints?`,
|
|
48680
48946
|
initialValue: true
|
|
48681
48947
|
});
|
|
48682
|
-
if (p26.isCancel(
|
|
48948
|
+
if (p26.isCancel(confirm23) || !confirm23) {
|
|
48683
48949
|
p26.cancel("Build cancelled.");
|
|
48684
48950
|
return false;
|
|
48685
48951
|
}
|
|
@@ -49860,24 +50126,24 @@ function formatHtmlLine(line) {
|
|
|
49860
50126
|
}
|
|
49861
50127
|
return null;
|
|
49862
50128
|
}
|
|
49863
|
-
function formatInlineMarkdown(
|
|
49864
|
-
|
|
49865
|
-
|
|
49866
|
-
|
|
49867
|
-
|
|
49868
|
-
|
|
49869
|
-
|
|
49870
|
-
|
|
49871
|
-
return
|
|
49872
|
-
}
|
|
49873
|
-
function wrapText(
|
|
49874
|
-
if (maxWidth <= 0) return [
|
|
49875
|
-
const plainText = stripAnsi(
|
|
50129
|
+
function formatInlineMarkdown(text15) {
|
|
50130
|
+
text15 = text15.replace(/\*\*\*(.+?)\*\*\*/g, (_, content) => chalk.bold.italic(content));
|
|
50131
|
+
text15 = text15.replace(/\*\*(.+?)\*\*/g, (_, content) => chalk.bold(content));
|
|
50132
|
+
text15 = text15.replace(/\*([^*]+)\*/g, (_, content) => chalk.italic(content));
|
|
50133
|
+
text15 = text15.replace(/_([^_]+)_/g, (_, content) => chalk.italic(content));
|
|
50134
|
+
text15 = text15.replace(/`([^`]+)`/g, (_, content) => chalk.cyan(content));
|
|
50135
|
+
text15 = text15.replace(/~~(.+?)~~/g, (_, content) => chalk.strikethrough(content));
|
|
50136
|
+
text15 = text15.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, linkText) => chalk.blue.underline(linkText));
|
|
50137
|
+
return text15;
|
|
50138
|
+
}
|
|
50139
|
+
function wrapText(text15, maxWidth) {
|
|
50140
|
+
if (maxWidth <= 0) return [text15];
|
|
50141
|
+
const plainText = stripAnsi(text15);
|
|
49876
50142
|
if (plainText.length <= maxWidth) {
|
|
49877
|
-
return [
|
|
50143
|
+
return [text15];
|
|
49878
50144
|
}
|
|
49879
50145
|
const lines = [];
|
|
49880
|
-
let remaining =
|
|
50146
|
+
let remaining = text15;
|
|
49881
50147
|
while (true) {
|
|
49882
50148
|
const plain = stripAnsi(remaining);
|
|
49883
50149
|
if (plain.length <= maxWidth) break;
|
|
@@ -49915,7 +50181,7 @@ function wrapText(text14, maxWidth) {
|
|
|
49915
50181
|
if (remaining) {
|
|
49916
50182
|
lines.push(remaining);
|
|
49917
50183
|
}
|
|
49918
|
-
return lines.length > 0 ? lines : [
|
|
50184
|
+
return lines.length > 0 ? lines : [text15];
|
|
49919
50185
|
}
|
|
49920
50186
|
function stripAnsi(str) {
|
|
49921
50187
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -50067,9 +50333,9 @@ function printEditDiff(oldStr, newStr) {
|
|
|
50067
50333
|
if (lines.length === 0) return;
|
|
50068
50334
|
const truncate4 = (s) => s.length > termWidth - 2 ? s.slice(0, termWidth - 3) + "\u2026" : s;
|
|
50069
50335
|
for (const l of lines) {
|
|
50070
|
-
const
|
|
50071
|
-
const pad = Math.max(0, termWidth - stripAnsi(
|
|
50072
|
-
console.log(" " + diffBgAdd(
|
|
50336
|
+
const text15 = `+ ${truncate4(l)}`;
|
|
50337
|
+
const pad = Math.max(0, termWidth - stripAnsi(text15).length + 2);
|
|
50338
|
+
console.log(" " + diffBgAdd(text15 + " ".repeat(pad)));
|
|
50073
50339
|
}
|
|
50074
50340
|
return;
|
|
50075
50341
|
}
|
|
@@ -50097,9 +50363,9 @@ function printEditDiff(oldStr, newStr) {
|
|
|
50097
50363
|
}
|
|
50098
50364
|
if (diffLineList.length === 0) return;
|
|
50099
50365
|
const pairs = pairAdjacentDiffLines(diffLineList);
|
|
50100
|
-
const pairedDeletes = new Set(pairs.map((
|
|
50101
|
-
const pairedAdds = new Set(pairs.map((
|
|
50102
|
-
const pairByAdd = new Map(pairs.map((
|
|
50366
|
+
const pairedDeletes = new Set(pairs.map((p46) => p46.deleteIdx));
|
|
50367
|
+
const pairedAdds = new Set(pairs.map((p46) => p46.addIdx));
|
|
50368
|
+
const pairByAdd = new Map(pairs.map((p46) => [p46.addIdx, p46.deleteIdx]));
|
|
50103
50369
|
const wordHighlights = /* @__PURE__ */ new Map();
|
|
50104
50370
|
for (const pair of pairs) {
|
|
50105
50371
|
const del = diffLineList[pair.deleteIdx];
|
|
@@ -50525,10 +50791,10 @@ function findNextWordBoundary(line, pos) {
|
|
|
50525
50791
|
while (i < line.length && line[i] === " ") i++;
|
|
50526
50792
|
return i;
|
|
50527
50793
|
}
|
|
50528
|
-
function countVisualRows(
|
|
50794
|
+
function countVisualRows(text15, startCol, termCols) {
|
|
50529
50795
|
let rows = 1;
|
|
50530
50796
|
let col = startCol;
|
|
50531
|
-
for (const char of
|
|
50797
|
+
for (const char of text15) {
|
|
50532
50798
|
if (char === "\n") {
|
|
50533
50799
|
if (col > 0) rows++;
|
|
50534
50800
|
col = 0;
|
|
@@ -50542,11 +50808,11 @@ function countVisualRows(text14, startCol, termCols) {
|
|
|
50542
50808
|
}
|
|
50543
50809
|
return rows;
|
|
50544
50810
|
}
|
|
50545
|
-
function getCursorVisualPos(
|
|
50811
|
+
function getCursorVisualPos(text15, cursorPos, promptLen, termCols) {
|
|
50546
50812
|
let row = 0;
|
|
50547
50813
|
let col = promptLen;
|
|
50548
50814
|
for (let i = 0; i < cursorPos; i++) {
|
|
50549
|
-
if (
|
|
50815
|
+
if (text15[i] === "\n") {
|
|
50550
50816
|
if (col > 0) row++;
|
|
50551
50817
|
col = 0;
|
|
50552
50818
|
} else {
|
|
@@ -50559,14 +50825,14 @@ function getCursorVisualPos(text14, cursorPos, promptLen, termCols) {
|
|
|
50559
50825
|
}
|
|
50560
50826
|
return { row, col };
|
|
50561
50827
|
}
|
|
50562
|
-
function computeWordWrap(
|
|
50828
|
+
function computeWordWrap(text15, startCol, termCols) {
|
|
50563
50829
|
const passthrough = {
|
|
50564
|
-
display:
|
|
50565
|
-
toDisplayPos: (
|
|
50566
|
-
toOrigPos: (
|
|
50830
|
+
display: text15,
|
|
50831
|
+
toDisplayPos: (p46) => p46,
|
|
50832
|
+
toOrigPos: (p46) => p46
|
|
50567
50833
|
};
|
|
50568
|
-
if (!
|
|
50569
|
-
const origToDisp = new Int32Array(
|
|
50834
|
+
if (!text15 || termCols <= 1) return passthrough;
|
|
50835
|
+
const origToDisp = new Int32Array(text15.length + 1);
|
|
50570
50836
|
const dispToOrig = [];
|
|
50571
50837
|
let display = "";
|
|
50572
50838
|
let col = startCol;
|
|
@@ -50582,15 +50848,15 @@ function computeWordWrap(text14, startCol, termCols) {
|
|
|
50582
50848
|
col = 0;
|
|
50583
50849
|
}
|
|
50584
50850
|
let i = 0;
|
|
50585
|
-
while (i <
|
|
50586
|
-
const ch =
|
|
50851
|
+
while (i < text15.length) {
|
|
50852
|
+
const ch = text15[i];
|
|
50587
50853
|
if (ch === "\n") {
|
|
50588
50854
|
emitChar("\n", i++);
|
|
50589
50855
|
continue;
|
|
50590
50856
|
}
|
|
50591
50857
|
if (ch !== " ") {
|
|
50592
50858
|
let wordEnd = i;
|
|
50593
|
-
while (wordEnd <
|
|
50859
|
+
while (wordEnd < text15.length && text15[wordEnd] !== " " && text15[wordEnd] !== "\n") {
|
|
50594
50860
|
wordEnd++;
|
|
50595
50861
|
}
|
|
50596
50862
|
const wordLen = wordEnd - i;
|
|
@@ -50598,7 +50864,7 @@ function computeWordWrap(text14, startCol, termCols) {
|
|
|
50598
50864
|
injectNewline();
|
|
50599
50865
|
}
|
|
50600
50866
|
for (let k = i; k < wordEnd; k++) {
|
|
50601
|
-
emitChar(
|
|
50867
|
+
emitChar(text15[k], k);
|
|
50602
50868
|
if (col >= termCols && k + 1 < wordEnd) {
|
|
50603
50869
|
injectNewline();
|
|
50604
50870
|
}
|
|
@@ -50610,7 +50876,7 @@ function computeWordWrap(text14, startCol, termCols) {
|
|
|
50610
50876
|
col = 0;
|
|
50611
50877
|
} else {
|
|
50612
50878
|
let nextWordEnd = i;
|
|
50613
|
-
while (nextWordEnd <
|
|
50879
|
+
while (nextWordEnd < text15.length && text15[nextWordEnd] !== " " && text15[nextWordEnd] !== "\n") {
|
|
50614
50880
|
nextWordEnd++;
|
|
50615
50881
|
}
|
|
50616
50882
|
const nextWordLen = nextWordEnd - i;
|
|
@@ -50620,10 +50886,10 @@ function computeWordWrap(text14, startCol, termCols) {
|
|
|
50620
50886
|
}
|
|
50621
50887
|
}
|
|
50622
50888
|
}
|
|
50623
|
-
origToDisp[
|
|
50889
|
+
origToDisp[text15.length] = display.length;
|
|
50624
50890
|
return {
|
|
50625
50891
|
display,
|
|
50626
|
-
toDisplayPos: (origPos) => origToDisp[Math.min(origPos,
|
|
50892
|
+
toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text15.length)] ?? display.length,
|
|
50627
50893
|
toOrigPos: (displayPos) => {
|
|
50628
50894
|
const dp = Math.max(0, Math.min(displayPos, dispToOrig.length - 1));
|
|
50629
50895
|
for (let d = dp; d >= 0; d--) {
|
|
@@ -50756,11 +51022,11 @@ function createInputHandler(_session) {
|
|
|
50756
51022
|
const item = visibleItems[itemIndex];
|
|
50757
51023
|
const actualIndex = startIndex + itemIndex;
|
|
50758
51024
|
const isSelected = actualIndex === selectedCompletion;
|
|
50759
|
-
const
|
|
51025
|
+
const text15 = ` ${item.cmd}`.padEnd(ITEM_WIDTH);
|
|
50760
51026
|
if (isSelected) {
|
|
50761
|
-
output += chalk.bgBlue.white(
|
|
51027
|
+
output += chalk.bgBlue.white(text15);
|
|
50762
51028
|
} else {
|
|
50763
|
-
output += chalk.cyan(
|
|
51029
|
+
output += chalk.cyan(text15);
|
|
50764
51030
|
}
|
|
50765
51031
|
}
|
|
50766
51032
|
}
|
|
@@ -50812,8 +51078,8 @@ function createInputHandler(_session) {
|
|
|
50812
51078
|
process.stdout.write("\r" + ansiEscapes.eraseDown);
|
|
50813
51079
|
lastMenuLines = 0;
|
|
50814
51080
|
}
|
|
50815
|
-
function insertTextAtCursor(
|
|
50816
|
-
const cleaned =
|
|
51081
|
+
function insertTextAtCursor(text15) {
|
|
51082
|
+
const cleaned = text15.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
50817
51083
|
const printable = cleaned.replace(/[^\n\x20-\x7E\u00A0-\uFFFF]/g, "");
|
|
50818
51084
|
if (printable.length === 0) return;
|
|
50819
51085
|
currentLine = currentLine.slice(0, cursorPos) + printable + currentLine.slice(cursorPos);
|
|
@@ -51716,10 +51982,10 @@ function formatWriteFilePreview(toolCall, maxLines = 10) {
|
|
|
51716
51982
|
const footer = truncated ? chalk.dim(` \u2514\u2500 ... ${lines.length - maxLines} more lines`) : "";
|
|
51717
51983
|
return formatted + (footer ? "\n" + footer : "");
|
|
51718
51984
|
}
|
|
51719
|
-
function wrapCommandText(
|
|
51720
|
-
if (
|
|
51985
|
+
function wrapCommandText(text15, maxWidth = 70, indent = " ") {
|
|
51986
|
+
if (text15.length <= maxWidth) return text15;
|
|
51721
51987
|
const lines = [];
|
|
51722
|
-
let remaining =
|
|
51988
|
+
let remaining = text15;
|
|
51723
51989
|
while (remaining.length > maxWidth) {
|
|
51724
51990
|
let breakAt = maxWidth;
|
|
51725
51991
|
const spaceIdx = remaining.lastIndexOf(" ", maxWidth);
|
|
@@ -51822,16 +52088,16 @@ function formatToolCallForConfirmation(toolCall, metadata) {
|
|
|
51822
52088
|
const reason = input.reason ? String(input.reason) : void 0;
|
|
51823
52089
|
const actionLabel = action === "allow" ? chalk.green.bold("ALLOW") : chalk.red.bold(action.toUpperCase());
|
|
51824
52090
|
const scopeLabel = scope === "global" ? chalk.blue("Global (all projects)") : chalk.magenta("Project (current only)");
|
|
51825
|
-
const patternList = patterns.map((
|
|
52091
|
+
const patternList = patterns.map((p46) => chalk.cyan(p46)).join(", ");
|
|
51826
52092
|
const lines = [`${actionLabel}: ${patternList}`];
|
|
51827
52093
|
lines.push(`${chalk.dim(" Scope:")} ${scopeLabel}`);
|
|
51828
52094
|
if (reason) {
|
|
51829
52095
|
lines.push(`${chalk.dim(" Reason:")} ${reason}`);
|
|
51830
52096
|
}
|
|
51831
|
-
for (const
|
|
51832
|
-
lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(
|
|
52097
|
+
for (const p46 of patterns) {
|
|
52098
|
+
lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(p46)}`);
|
|
51833
52099
|
lines.push(
|
|
51834
|
-
`${chalk.dim(" Effect:")} ${getEffectDescription(action,
|
|
52100
|
+
`${chalk.dim(" Effect:")} ${getEffectDescription(action, p46, scope)}`
|
|
51835
52101
|
);
|
|
51836
52102
|
}
|
|
51837
52103
|
description = lines.join("\n ");
|
|
@@ -52072,6 +52338,46 @@ async function confirmToolExecution(toolCall) {
|
|
|
52072
52338
|
process.stdin.on("data", onData);
|
|
52073
52339
|
});
|
|
52074
52340
|
}
|
|
52341
|
+
async function confirmToolExecutionFallback(toolCall) {
|
|
52342
|
+
const { description } = formatToolCallForConfirmation(toolCall);
|
|
52343
|
+
const isBashExec = toolCall.name === "bash_exec";
|
|
52344
|
+
console.log();
|
|
52345
|
+
console.log(chalk.yellow(" \u26A0 Interactive tool selector unavailable. Using safe fallback."));
|
|
52346
|
+
const options = [
|
|
52347
|
+
{ value: "yes", label: "yes", hint: "Allow once" },
|
|
52348
|
+
{ value: "no", label: "no", hint: "Skip this action" },
|
|
52349
|
+
{ value: "trust_project", label: "trust (project)", hint: "Always allow in this project" },
|
|
52350
|
+
{ value: "trust_global", label: "trust (global)", hint: "Always allow everywhere" }
|
|
52351
|
+
];
|
|
52352
|
+
if (isBashExec) {
|
|
52353
|
+
options.splice(2, 0, { value: "edit", label: "edit command", hint: "Modify before running" });
|
|
52354
|
+
}
|
|
52355
|
+
const choice = await p26.select({
|
|
52356
|
+
message: `Confirm tool action:
|
|
52357
|
+
${description}`,
|
|
52358
|
+
options
|
|
52359
|
+
});
|
|
52360
|
+
if (p26.isCancel(choice)) return "abort";
|
|
52361
|
+
if (choice === "edit") {
|
|
52362
|
+
const currentCommand = String(toolCall.input.command ?? "");
|
|
52363
|
+
const edited = await p26.text({
|
|
52364
|
+
message: "Edit command:",
|
|
52365
|
+
placeholder: currentCommand,
|
|
52366
|
+
initialValue: currentCommand,
|
|
52367
|
+
validate: (value) => !value?.trim() ? "Command is required" : void 0
|
|
52368
|
+
});
|
|
52369
|
+
if (p26.isCancel(edited)) return "abort";
|
|
52370
|
+
return { type: "edit", newCommand: edited.trim() };
|
|
52371
|
+
}
|
|
52372
|
+
return choice;
|
|
52373
|
+
}
|
|
52374
|
+
async function confirmToolExecutionWithFallback(toolCall) {
|
|
52375
|
+
try {
|
|
52376
|
+
return await confirmToolExecution(toolCall);
|
|
52377
|
+
} catch {
|
|
52378
|
+
return await confirmToolExecutionFallback(toolCall);
|
|
52379
|
+
}
|
|
52380
|
+
}
|
|
52075
52381
|
|
|
52076
52382
|
// src/cli/repl/parallel-executor.ts
|
|
52077
52383
|
init_error_resilience();
|
|
@@ -52801,14 +53107,15 @@ ${tail}`;
|
|
|
52801
53107
|
options.onBeforeConfirmation?.();
|
|
52802
53108
|
let confirmResult;
|
|
52803
53109
|
try {
|
|
52804
|
-
confirmResult = await
|
|
53110
|
+
confirmResult = await confirmToolExecutionWithFallback(toolCall);
|
|
52805
53111
|
} catch (confirmError) {
|
|
52806
53112
|
options.onAfterConfirmation?.();
|
|
52807
|
-
declinedTools.set(
|
|
52808
|
-
|
|
53113
|
+
declinedTools.set(toolCall.id, "Confirmation failed");
|
|
53114
|
+
options.onToolSkipped?.(
|
|
53115
|
+
toolCall,
|
|
52809
53116
|
`Confirmation failed: ${confirmError instanceof Error ? confirmError.message : String(confirmError)}`
|
|
52810
53117
|
);
|
|
52811
|
-
|
|
53118
|
+
turnAborted = true;
|
|
52812
53119
|
continue;
|
|
52813
53120
|
}
|
|
52814
53121
|
options.onAfterConfirmation?.();
|
|
@@ -52878,29 +53185,29 @@ ${tail}`;
|
|
|
52878
53185
|
const patterns = executed.input.patterns;
|
|
52879
53186
|
const scope = executed.input.scope || "project";
|
|
52880
53187
|
if (Array.isArray(patterns)) {
|
|
52881
|
-
for (const
|
|
53188
|
+
for (const p46 of patterns) {
|
|
52882
53189
|
if (action === "allow") {
|
|
52883
|
-
session.trustedTools.add(
|
|
53190
|
+
session.trustedTools.add(p46);
|
|
52884
53191
|
if (scope === "global") {
|
|
52885
|
-
saveTrustedTool(
|
|
53192
|
+
saveTrustedTool(p46, null, true).catch(() => {
|
|
52886
53193
|
});
|
|
52887
53194
|
} else {
|
|
52888
|
-
saveTrustedTool(
|
|
53195
|
+
saveTrustedTool(p46, session.projectPath, false).catch(() => {
|
|
52889
53196
|
});
|
|
52890
53197
|
}
|
|
52891
|
-
removeDeniedTool(
|
|
53198
|
+
removeDeniedTool(p46, session.projectPath).catch(() => {
|
|
52892
53199
|
});
|
|
52893
53200
|
} else if (action === "deny") {
|
|
52894
|
-
session.trustedTools.delete(
|
|
53201
|
+
session.trustedTools.delete(p46);
|
|
52895
53202
|
if (scope === "global") {
|
|
52896
|
-
removeTrustedTool(
|
|
53203
|
+
removeTrustedTool(p46, session.projectPath, true).catch(() => {
|
|
52897
53204
|
});
|
|
52898
53205
|
} else {
|
|
52899
|
-
saveDeniedTool(
|
|
53206
|
+
saveDeniedTool(p46, session.projectPath).catch(() => {
|
|
52900
53207
|
});
|
|
52901
53208
|
}
|
|
52902
53209
|
} else {
|
|
52903
|
-
session.trustedTools.delete(
|
|
53210
|
+
session.trustedTools.delete(p46);
|
|
52904
53211
|
}
|
|
52905
53212
|
}
|
|
52906
53213
|
}
|
|
@@ -53640,44 +53947,6 @@ function createIntentRecognizer(config = {}) {
|
|
|
53640
53947
|
// src/cli/repl/index.ts
|
|
53641
53948
|
init_env();
|
|
53642
53949
|
init_allowed_paths();
|
|
53643
|
-
async function getGitContext(projectPath) {
|
|
53644
|
-
const controller = new AbortController();
|
|
53645
|
-
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
53646
|
-
try {
|
|
53647
|
-
const git = simpleGit({ baseDir: projectPath, abort: controller.signal });
|
|
53648
|
-
const status = await git.status();
|
|
53649
|
-
clearTimeout(timer);
|
|
53650
|
-
return {
|
|
53651
|
-
branch: status.current ?? "HEAD",
|
|
53652
|
-
isDirty: !status.isClean(),
|
|
53653
|
-
staged: status.staged.length,
|
|
53654
|
-
modified: status.modified.length,
|
|
53655
|
-
untracked: status.not_added.length,
|
|
53656
|
-
ahead: status.ahead,
|
|
53657
|
-
behind: status.behind
|
|
53658
|
-
};
|
|
53659
|
-
} catch {
|
|
53660
|
-
clearTimeout(timer);
|
|
53661
|
-
return null;
|
|
53662
|
-
}
|
|
53663
|
-
}
|
|
53664
|
-
function formatGitLine(ctx) {
|
|
53665
|
-
const branchColor = ctx.isDirty ? chalk.yellow : chalk.green;
|
|
53666
|
-
const parts = [chalk.dim("\u{1F33F} ") + branchColor(ctx.branch)];
|
|
53667
|
-
const changes = [];
|
|
53668
|
-
if (ctx.staged > 0) changes.push(chalk.green(`+${ctx.staged}`));
|
|
53669
|
-
if (ctx.modified > 0) changes.push(chalk.yellow(`~${ctx.modified}`));
|
|
53670
|
-
if (ctx.untracked > 0) changes.push(chalk.dim(`?${ctx.untracked}`));
|
|
53671
|
-
if (ctx.ahead > 0) changes.push(chalk.cyan(`\u2191${ctx.ahead}`));
|
|
53672
|
-
if (ctx.behind > 0) changes.push(chalk.red(`\u2193${ctx.behind}`));
|
|
53673
|
-
if (changes.length > 0) parts.push(changes.join(" "));
|
|
53674
|
-
return parts.join(" \u2022 ");
|
|
53675
|
-
}
|
|
53676
|
-
function formatGitShort(ctx) {
|
|
53677
|
-
const branch = ctx.isDirty ? chalk.yellow(ctx.branch) : chalk.green(ctx.branch);
|
|
53678
|
-
const dirty = ctx.isDirty ? chalk.yellow(" \u25CF") : "";
|
|
53679
|
-
return chalk.dim("\u{1F33F} ") + branch + dirty;
|
|
53680
|
-
}
|
|
53681
53950
|
|
|
53682
53951
|
// src/cli/repl/status-bar.ts
|
|
53683
53952
|
init_env();
|
|
@@ -53986,14 +54255,14 @@ async function startRepl(options = {}) {
|
|
|
53986
54255
|
imageCount++;
|
|
53987
54256
|
}
|
|
53988
54257
|
}
|
|
53989
|
-
const
|
|
53990
|
-
if (
|
|
54258
|
+
const text15 = textParts.join("\n\n").trim();
|
|
54259
|
+
if (text15.length > 0) {
|
|
53991
54260
|
if (imageCount > 0) {
|
|
53992
|
-
return `${
|
|
54261
|
+
return `${text15}
|
|
53993
54262
|
|
|
53994
54263
|
[System: The original request included ${imageCount} image(s). Use the image context already provided in this conversation.]`;
|
|
53995
54264
|
}
|
|
53996
|
-
return
|
|
54265
|
+
return text15;
|
|
53997
54266
|
}
|
|
53998
54267
|
if (imageCount > 0) {
|
|
53999
54268
|
return `[System: Retry the previous image-based user request (${imageCount} image(s)). Use the existing image context in the conversation and do not repeat the same failed action.]`;
|
|
@@ -54012,8 +54281,8 @@ async function startRepl(options = {}) {
|
|
|
54012
54281
|
};
|
|
54013
54282
|
const getAutoSwitchCandidates = (current) => {
|
|
54014
54283
|
const ordered = [];
|
|
54015
|
-
const push = (
|
|
54016
|
-
if (
|
|
54284
|
+
const push = (p46) => {
|
|
54285
|
+
if (p46 !== current && !ordered.includes(p46)) ordered.push(p46);
|
|
54017
54286
|
};
|
|
54018
54287
|
if (current === "openai") {
|
|
54019
54288
|
push("codex");
|
|
@@ -54051,7 +54320,7 @@ async function startRepl(options = {}) {
|
|
|
54051
54320
|
"lmstudio",
|
|
54052
54321
|
"ollama"
|
|
54053
54322
|
];
|
|
54054
|
-
for (const
|
|
54323
|
+
for (const p46 of genericOrder) push(p46);
|
|
54055
54324
|
return ordered;
|
|
54056
54325
|
};
|
|
54057
54326
|
const attemptAutoProviderSwitch = async (reason, originalMessage) => {
|
|
@@ -54782,85 +55051,7 @@ ${imagePrompts}`.trim() : imagePrompts;
|
|
|
54782
55051
|
process.off("SIGTERM", sigtermHandler);
|
|
54783
55052
|
}
|
|
54784
55053
|
async function printWelcome(session, gitCtx, mcpManager) {
|
|
54785
|
-
|
|
54786
|
-
await trustStore.init();
|
|
54787
|
-
const trustLevel = trustStore.getLevel(session.projectPath);
|
|
54788
|
-
const boxWidth = 41;
|
|
54789
|
-
const innerWidth = boxWidth - 2;
|
|
54790
|
-
const versionText = `v${VERSION}`;
|
|
54791
|
-
const subtitleText = "open source \u2022 corbat.tech";
|
|
54792
|
-
const boxLine = (content) => {
|
|
54793
|
-
const pad = Math.max(0, innerWidth - stringWidth2(content));
|
|
54794
|
-
return chalk.magenta("\u2502") + content + " ".repeat(pad) + chalk.magenta("\u2502");
|
|
54795
|
-
};
|
|
54796
|
-
const titleLeftRaw = " COCO";
|
|
54797
|
-
const titleRightRaw = versionText + " ";
|
|
54798
|
-
const titleLeftStyled = " " + chalk.bold.white("COCO");
|
|
54799
|
-
const titleGap = Math.max(1, innerWidth - stringWidth2(titleLeftRaw) - stringWidth2(titleRightRaw));
|
|
54800
|
-
const titleContent = titleLeftStyled + " ".repeat(titleGap) + chalk.dim(titleRightRaw);
|
|
54801
|
-
const taglineText = "code that converges to quality";
|
|
54802
|
-
const taglineContent = " " + chalk.magenta(taglineText) + " ";
|
|
54803
|
-
const subtitleContent = " " + chalk.dim(subtitleText) + " ";
|
|
54804
|
-
console.log();
|
|
54805
|
-
console.log(chalk.magenta(" \u256D" + "\u2500".repeat(boxWidth - 2) + "\u256E"));
|
|
54806
|
-
console.log(" " + boxLine(titleContent));
|
|
54807
|
-
console.log(" " + boxLine(taglineContent));
|
|
54808
|
-
console.log(" " + boxLine(subtitleContent));
|
|
54809
|
-
console.log(chalk.magenta(" \u2570" + "\u2500".repeat(boxWidth - 2) + "\u256F"));
|
|
54810
|
-
const maxPathLen = 50;
|
|
54811
|
-
let displayPath = session.projectPath;
|
|
54812
|
-
if (displayPath.length > maxPathLen) {
|
|
54813
|
-
displayPath = "..." + displayPath.slice(-maxPathLen + 3);
|
|
54814
|
-
}
|
|
54815
|
-
const lastSep = displayPath.lastIndexOf("/");
|
|
54816
|
-
const parentPath = lastSep > 0 ? displayPath.slice(0, lastSep + 1) : "";
|
|
54817
|
-
const projectName = lastSep > 0 ? displayPath.slice(lastSep + 1) : displayPath;
|
|
54818
|
-
const providerName = session.config.provider.type;
|
|
54819
|
-
const configuredModel = session.config.provider.model?.trim();
|
|
54820
|
-
const modelName = configuredModel && !["default", "none", "null", "undefined"].includes(configuredModel.toLowerCase()) ? configuredModel : getDefaultModel(session.config.provider.type);
|
|
54821
|
-
const trustText = trustLevel === "full" ? "full" : trustLevel === "write" ? "write" : trustLevel === "read" ? "read" : "";
|
|
54822
|
-
console.log();
|
|
54823
|
-
console.log(chalk.dim(` \u{1F4C1} ${parentPath}`) + chalk.magenta.bold(projectName));
|
|
54824
|
-
console.log(
|
|
54825
|
-
chalk.dim(` \u{1F916} ${providerName}/`) + chalk.magenta(modelName) + (trustText ? chalk.dim(` \u2022 \u{1F510} ${trustText}`) : "")
|
|
54826
|
-
);
|
|
54827
|
-
if (gitCtx) {
|
|
54828
|
-
console.log(` ${formatGitLine(gitCtx)}`);
|
|
54829
|
-
}
|
|
54830
|
-
const cocoStatus = isQualityLoop() ? chalk.magenta(" \u{1F504} quality mode: ") + chalk.green.bold("on") + chalk.dim(" \u2014 iterates until quality \u2265 85. /quality to disable") : chalk.dim(" \u{1F4A1} /quality on \u2014 enable auto-test & quality iteration");
|
|
54831
|
-
console.log(cocoStatus);
|
|
54832
|
-
const skillTotal = session.skillRegistry?.size ?? 0;
|
|
54833
|
-
const mcpServers = mcpManager?.getConnectedServers() ?? [];
|
|
54834
|
-
const hasSomething = skillTotal > 0 || mcpServers.length > 0;
|
|
54835
|
-
if (hasSomething) {
|
|
54836
|
-
if (skillTotal > 0) {
|
|
54837
|
-
const allMeta = session.skillRegistry.getAllMetadata();
|
|
54838
|
-
const builtinCount = allMeta.filter((s) => s.scope === "builtin").length;
|
|
54839
|
-
const projectCount = skillTotal - builtinCount;
|
|
54840
|
-
const parts = [];
|
|
54841
|
-
if (builtinCount > 0) parts.push(`${builtinCount} builtin`);
|
|
54842
|
-
if (projectCount > 0) parts.push(`${projectCount} project`);
|
|
54843
|
-
const detail = parts.length > 0 ? ` (${parts.join(" \xB7 ")})` : "";
|
|
54844
|
-
console.log(chalk.green(" \u2713") + chalk.dim(` Skills: ${skillTotal} loaded${detail}`));
|
|
54845
|
-
} else {
|
|
54846
|
-
console.log(chalk.dim(" \xB7 Skills: none loaded"));
|
|
54847
|
-
}
|
|
54848
|
-
if (mcpServers.length > 0) {
|
|
54849
|
-
const names = mcpServers.join(", ");
|
|
54850
|
-
console.log(
|
|
54851
|
-
chalk.green(" \u2713") + chalk.dim(
|
|
54852
|
-
` MCP: ${names} (${mcpServers.length} server${mcpServers.length === 1 ? "" : "s"} active)`
|
|
54853
|
-
)
|
|
54854
|
-
);
|
|
54855
|
-
}
|
|
54856
|
-
}
|
|
54857
|
-
console.log();
|
|
54858
|
-
console.log(
|
|
54859
|
-
chalk.dim(" Type your request or ") + chalk.magenta("/help") + chalk.dim(" for commands")
|
|
54860
|
-
);
|
|
54861
|
-
const pasteHint = process.platform === "darwin" ? chalk.dim(" \u{1F4CB} \u2318V paste text \u2022 \u2303V paste image") : chalk.dim(" \u{1F4CB} Ctrl+V paste image from clipboard");
|
|
54862
|
-
console.log(pasteHint);
|
|
54863
|
-
console.log();
|
|
55054
|
+
await renderStartupPanel(session, gitCtx, mcpManager?.getConnectedServers() ?? []);
|
|
54864
55055
|
}
|
|
54865
55056
|
async function checkProjectTrust(projectPath) {
|
|
54866
55057
|
const trustStore = createTrustStore();
|