@corbat-tech/coco 2.25.8 → 2.25.10
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 +179 -39
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +42 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -121,6 +121,7 @@ function createDefaultConfigObject(projectName, language = "typescript") {
|
|
|
121
121
|
temperature: 0,
|
|
122
122
|
timeout: 12e4
|
|
123
123
|
},
|
|
124
|
+
providerModels: {},
|
|
124
125
|
quality: {
|
|
125
126
|
minScore: 85,
|
|
126
127
|
minCoverage: 80,
|
|
@@ -300,6 +301,7 @@ var init_schema = __esm({
|
|
|
300
301
|
temperature: 0,
|
|
301
302
|
timeout: 12e4
|
|
302
303
|
}),
|
|
304
|
+
providerModels: z.record(z.string(), z.string()).optional(),
|
|
303
305
|
quality: QualityConfigSchema.default({
|
|
304
306
|
minScore: 85,
|
|
305
307
|
minCoverage: 80,
|
|
@@ -597,6 +599,7 @@ function deepMergeConfig(base, override) {
|
|
|
597
599
|
...override,
|
|
598
600
|
project: { ...base.project, ...override.project },
|
|
599
601
|
provider: { ...base.provider, ...override.provider },
|
|
602
|
+
providerModels: { ...base.providerModels, ...override.providerModels },
|
|
600
603
|
quality: { ...base.quality, ...override.quality },
|
|
601
604
|
persistence: { ...base.persistence, ...override.persistence },
|
|
602
605
|
// Merge optional sections only if present in either base or override
|
|
@@ -2543,7 +2546,7 @@ function getDefaultModel(provider) {
|
|
|
2543
2546
|
case "codex":
|
|
2544
2547
|
return process.env["CODEX_MODEL"] ?? "codex-mini-latest";
|
|
2545
2548
|
case "copilot":
|
|
2546
|
-
return process.env["COPILOT_MODEL"] ?? "
|
|
2549
|
+
return process.env["COPILOT_MODEL"] ?? "claude-sonnet-4.6";
|
|
2547
2550
|
case "groq":
|
|
2548
2551
|
return process.env["GROQ_MODEL"] ?? "llama-3.3-70b-versatile";
|
|
2549
2552
|
case "openrouter":
|
|
@@ -2562,6 +2565,11 @@ function getDefaultModel(provider) {
|
|
|
2562
2565
|
return "claude-sonnet-4-6";
|
|
2563
2566
|
}
|
|
2564
2567
|
}
|
|
2568
|
+
function normalizeConfiguredModel(model) {
|
|
2569
|
+
if (typeof model !== "string") return void 0;
|
|
2570
|
+
const trimmed = model.trim();
|
|
2571
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
2572
|
+
}
|
|
2565
2573
|
function getDefaultProvider() {
|
|
2566
2574
|
const envProvider = process.env["COCO_PROVIDER"]?.toLowerCase();
|
|
2567
2575
|
if (envProvider && VALID_PROVIDERS.includes(envProvider)) {
|
|
@@ -2583,8 +2591,12 @@ async function getLastUsedProvider() {
|
|
|
2583
2591
|
async function getLastUsedModel(provider) {
|
|
2584
2592
|
try {
|
|
2585
2593
|
const config = await loadConfig(CONFIG_PATHS.config);
|
|
2594
|
+
const perProviderModel = normalizeConfiguredModel(config.providerModels?.[provider]);
|
|
2595
|
+
if (perProviderModel) {
|
|
2596
|
+
return perProviderModel;
|
|
2597
|
+
}
|
|
2586
2598
|
if (config.provider.type === provider) {
|
|
2587
|
-
return config.provider.model;
|
|
2599
|
+
return normalizeConfiguredModel(config.provider.model);
|
|
2588
2600
|
}
|
|
2589
2601
|
} catch {
|
|
2590
2602
|
}
|
|
@@ -2621,8 +2633,14 @@ async function saveProviderPreference(provider, model) {
|
|
|
2621
2633
|
};
|
|
2622
2634
|
}
|
|
2623
2635
|
config.provider.type = provider;
|
|
2624
|
-
|
|
2625
|
-
|
|
2636
|
+
const normalizedModel = normalizeConfiguredModel(model);
|
|
2637
|
+
const persistedModel = normalizedModel ?? getDefaultModel(provider);
|
|
2638
|
+
config.providerModels = {
|
|
2639
|
+
...config.providerModels,
|
|
2640
|
+
[provider]: persistedModel
|
|
2641
|
+
};
|
|
2642
|
+
if (normalizedModel) {
|
|
2643
|
+
config.provider.model = normalizedModel;
|
|
2626
2644
|
} else {
|
|
2627
2645
|
config.provider.model = getDefaultModel(provider);
|
|
2628
2646
|
}
|
|
@@ -2719,11 +2737,25 @@ async function migrateOldPreferences() {
|
|
|
2719
2737
|
}
|
|
2720
2738
|
if (oldPrefs.provider && VALID_PROVIDERS.includes(oldPrefs.provider)) {
|
|
2721
2739
|
config.provider.type = oldPrefs.provider;
|
|
2740
|
+
config.providerModels = {
|
|
2741
|
+
...config.providerModels
|
|
2742
|
+
};
|
|
2743
|
+
for (const [providerName, modelName] of Object.entries(oldPrefs.models ?? {})) {
|
|
2744
|
+
if (VALID_PROVIDERS.includes(providerName)) {
|
|
2745
|
+
const normalized = normalizeConfiguredModel(modelName);
|
|
2746
|
+
if (normalized) {
|
|
2747
|
+
config.providerModels[providerName] = normalized;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2722
2751
|
const modelForProvider = oldPrefs.provider ? oldPrefs.models?.[oldPrefs.provider] : void 0;
|
|
2723
|
-
|
|
2724
|
-
|
|
2752
|
+
const normalizedMigratedModel = normalizeConfiguredModel(modelForProvider);
|
|
2753
|
+
if (normalizedMigratedModel) {
|
|
2754
|
+
config.provider.model = normalizedMigratedModel;
|
|
2755
|
+
config.providerModels[oldPrefs.provider] = normalizedMigratedModel;
|
|
2725
2756
|
} else {
|
|
2726
2757
|
config.provider.model = getDefaultModel(oldPrefs.provider);
|
|
2758
|
+
config.providerModels[oldPrefs.provider] = config.provider.model;
|
|
2727
2759
|
}
|
|
2728
2760
|
await saveConfig(config, void 0, true);
|
|
2729
2761
|
}
|
|
@@ -5474,6 +5506,11 @@ var init_codex = __esm({
|
|
|
5474
5506
|
};
|
|
5475
5507
|
}
|
|
5476
5508
|
});
|
|
5509
|
+
function normalizeModel(model) {
|
|
5510
|
+
if (typeof model !== "string") return void 0;
|
|
5511
|
+
const trimmed = model.trim();
|
|
5512
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
5513
|
+
}
|
|
5477
5514
|
function createCopilotProvider() {
|
|
5478
5515
|
return new CopilotProvider();
|
|
5479
5516
|
}
|
|
@@ -5528,7 +5565,7 @@ var init_copilot2 = __esm({
|
|
|
5528
5565
|
async initialize(config) {
|
|
5529
5566
|
this.config = {
|
|
5530
5567
|
...config,
|
|
5531
|
-
model: config.model ?? DEFAULT_MODEL4
|
|
5568
|
+
model: normalizeModel(config.model) ?? DEFAULT_MODEL4
|
|
5532
5569
|
};
|
|
5533
5570
|
const tokenResult = await getValidCopilotToken();
|
|
5534
5571
|
if (tokenResult) {
|
|
@@ -6855,12 +6892,17 @@ __export(providers_exports, {
|
|
|
6855
6892
|
listProviders: () => listProviders,
|
|
6856
6893
|
withRetry: () => withRetry
|
|
6857
6894
|
});
|
|
6895
|
+
function normalizeProviderModel(model) {
|
|
6896
|
+
if (typeof model !== "string") return void 0;
|
|
6897
|
+
const trimmed = model.trim();
|
|
6898
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
6899
|
+
}
|
|
6858
6900
|
async function createProvider(type, config = {}) {
|
|
6859
6901
|
let provider;
|
|
6860
6902
|
const mergedConfig = {
|
|
6861
6903
|
apiKey: config.apiKey ?? getApiKey(type),
|
|
6862
6904
|
baseUrl: config.baseUrl ?? getBaseUrl(type),
|
|
6863
|
-
model: config.model ?? getDefaultModel(type),
|
|
6905
|
+
model: normalizeProviderModel(config.model) ?? getDefaultModel(type),
|
|
6864
6906
|
maxTokens: config.maxTokens,
|
|
6865
6907
|
temperature: config.temperature,
|
|
6866
6908
|
timeout: config.timeout
|
|
@@ -9783,7 +9825,7 @@ function generateToolCatalog(registry) {
|
|
|
9783
9825
|
}
|
|
9784
9826
|
async function createDefaultReplConfig() {
|
|
9785
9827
|
const providerType = await getLastUsedProvider();
|
|
9786
|
-
const model = await getLastUsedModel(providerType)
|
|
9828
|
+
const model = await getLastUsedModel(providerType) || getDefaultModel(providerType);
|
|
9787
9829
|
return {
|
|
9788
9830
|
provider: {
|
|
9789
9831
|
type: providerType,
|
|
@@ -34598,8 +34640,9 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34598
34640
|
newApiKeyForSaving = key;
|
|
34599
34641
|
}
|
|
34600
34642
|
}
|
|
34643
|
+
const rememberedModel = await getLastUsedModel(newProvider.id);
|
|
34601
34644
|
const recommendedModel = getRecommendedModel(newProvider.id);
|
|
34602
|
-
const newModel = recommendedModel?.id || newProvider.models[0]?.id || "";
|
|
34645
|
+
const newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
|
|
34603
34646
|
const spinner18 = p26.spinner();
|
|
34604
34647
|
spinner18.start(`Connecting to ${newProvider.name}...`);
|
|
34605
34648
|
try {
|
|
@@ -40566,9 +40609,20 @@ function hasNullByte2(str) {
|
|
|
40566
40609
|
}
|
|
40567
40610
|
function normalizePath2(filePath) {
|
|
40568
40611
|
let normalized = filePath.replace(/\0/g, "");
|
|
40612
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
40613
|
+
if (home && normalized.startsWith("~")) {
|
|
40614
|
+
if (normalized === "~") {
|
|
40615
|
+
normalized = home;
|
|
40616
|
+
} else if (normalized.startsWith("~/") || normalized.startsWith(`~${path39__default.sep}`)) {
|
|
40617
|
+
normalized = path39__default.join(home, normalized.slice(2));
|
|
40618
|
+
}
|
|
40619
|
+
}
|
|
40569
40620
|
normalized = path39__default.normalize(normalized);
|
|
40570
40621
|
return normalized;
|
|
40571
40622
|
}
|
|
40623
|
+
function resolveUserPath(filePath) {
|
|
40624
|
+
return path39__default.resolve(normalizePath2(filePath));
|
|
40625
|
+
}
|
|
40572
40626
|
function isWithinDirectory(targetPath, baseDir) {
|
|
40573
40627
|
const normalizedTarget = path39__default.normalize(targetPath);
|
|
40574
40628
|
const normalizedBase = path39__default.normalize(baseDir);
|
|
@@ -40601,7 +40655,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
40601
40655
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
40602
40656
|
}
|
|
40603
40657
|
const normalized = normalizePath2(filePath);
|
|
40604
|
-
const absolute =
|
|
40658
|
+
const absolute = resolveUserPath(normalized);
|
|
40605
40659
|
const cwd = process.cwd();
|
|
40606
40660
|
for (const blocked of BLOCKED_PATHS2) {
|
|
40607
40661
|
const normalizedBlocked = path39__default.normalize(blocked);
|
|
@@ -40660,7 +40714,7 @@ function isENOENT(error) {
|
|
|
40660
40714
|
return error.code === "ENOENT";
|
|
40661
40715
|
}
|
|
40662
40716
|
async function enrichENOENT(filePath, operation) {
|
|
40663
|
-
const absPath =
|
|
40717
|
+
const absPath = resolveUserPath(filePath);
|
|
40664
40718
|
const suggestions = await suggestSimilarFilesDeep(absPath, process.cwd());
|
|
40665
40719
|
const hint = formatSuggestions(suggestions, path39__default.dirname(absPath));
|
|
40666
40720
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
@@ -40668,7 +40722,7 @@ async function enrichENOENT(filePath, operation) {
|
|
|
40668
40722
|
${action}`;
|
|
40669
40723
|
}
|
|
40670
40724
|
async function enrichDirENOENT(dirPath) {
|
|
40671
|
-
const absPath =
|
|
40725
|
+
const absPath = resolveUserPath(dirPath);
|
|
40672
40726
|
const suggestions = await suggestSimilarDirsDeep(absPath, process.cwd());
|
|
40673
40727
|
const hint = formatSuggestions(suggestions, path39__default.dirname(absPath));
|
|
40674
40728
|
return `Directory not found: ${dirPath}${hint}
|
|
@@ -40691,7 +40745,7 @@ Examples:
|
|
|
40691
40745
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
40692
40746
|
validatePath(filePath, "read");
|
|
40693
40747
|
try {
|
|
40694
|
-
const absolutePath =
|
|
40748
|
+
const absolutePath = resolveUserPath(filePath);
|
|
40695
40749
|
const stats = await fs35__default.stat(absolutePath);
|
|
40696
40750
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
40697
40751
|
let truncated = false;
|
|
@@ -40750,7 +40804,7 @@ Examples:
|
|
|
40750
40804
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
40751
40805
|
validatePath(filePath, "write");
|
|
40752
40806
|
try {
|
|
40753
|
-
const absolutePath =
|
|
40807
|
+
const absolutePath = resolveUserPath(filePath);
|
|
40754
40808
|
let wouldCreate = false;
|
|
40755
40809
|
try {
|
|
40756
40810
|
await fs35__default.access(absolutePath);
|
|
@@ -40812,7 +40866,7 @@ Examples:
|
|
|
40812
40866
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
40813
40867
|
validatePath(filePath, "write");
|
|
40814
40868
|
try {
|
|
40815
|
-
const absolutePath =
|
|
40869
|
+
const absolutePath = resolveUserPath(filePath);
|
|
40816
40870
|
let content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
40817
40871
|
let replacements = 0;
|
|
40818
40872
|
if (all) {
|
|
@@ -40933,7 +40987,7 @@ Examples:
|
|
|
40933
40987
|
}),
|
|
40934
40988
|
async execute({ path: filePath }) {
|
|
40935
40989
|
try {
|
|
40936
|
-
const absolutePath =
|
|
40990
|
+
const absolutePath = resolveUserPath(filePath);
|
|
40937
40991
|
const stats = await fs35__default.stat(absolutePath);
|
|
40938
40992
|
return {
|
|
40939
40993
|
exists: true,
|
|
@@ -40964,7 +41018,7 @@ Examples:
|
|
|
40964
41018
|
}),
|
|
40965
41019
|
async execute({ path: dirPath, recursive }) {
|
|
40966
41020
|
try {
|
|
40967
|
-
const absolutePath =
|
|
41021
|
+
const absolutePath = resolveUserPath(dirPath);
|
|
40968
41022
|
const entries = [];
|
|
40969
41023
|
async function listDir(dir, prefix = "") {
|
|
40970
41024
|
const items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
@@ -41024,7 +41078,7 @@ Examples:
|
|
|
41024
41078
|
}
|
|
41025
41079
|
validatePath(filePath, "delete");
|
|
41026
41080
|
try {
|
|
41027
|
-
const absolutePath =
|
|
41081
|
+
const absolutePath = resolveUserPath(filePath);
|
|
41028
41082
|
const stats = await fs35__default.stat(absolutePath);
|
|
41029
41083
|
if (stats.isDirectory()) {
|
|
41030
41084
|
if (!recursive) {
|
|
@@ -41040,7 +41094,7 @@ Examples:
|
|
|
41040
41094
|
} catch (error) {
|
|
41041
41095
|
if (error instanceof ToolError) throw error;
|
|
41042
41096
|
if (error.code === "ENOENT") {
|
|
41043
|
-
return { deleted: false, path:
|
|
41097
|
+
return { deleted: false, path: resolveUserPath(filePath) };
|
|
41044
41098
|
}
|
|
41045
41099
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
41046
41100
|
path: filePath,
|
|
@@ -41068,8 +41122,8 @@ Examples:
|
|
|
41068
41122
|
validatePath(source, "read");
|
|
41069
41123
|
validatePath(destination, "write");
|
|
41070
41124
|
try {
|
|
41071
|
-
const srcPath =
|
|
41072
|
-
const destPath =
|
|
41125
|
+
const srcPath = resolveUserPath(source);
|
|
41126
|
+
const destPath = resolveUserPath(destination);
|
|
41073
41127
|
if (!overwrite) {
|
|
41074
41128
|
try {
|
|
41075
41129
|
await fs35__default.access(destPath);
|
|
@@ -41129,8 +41183,8 @@ Examples:
|
|
|
41129
41183
|
validatePath(source, "delete");
|
|
41130
41184
|
validatePath(destination, "write");
|
|
41131
41185
|
try {
|
|
41132
|
-
const srcPath =
|
|
41133
|
-
const destPath =
|
|
41186
|
+
const srcPath = resolveUserPath(source);
|
|
41187
|
+
const destPath = resolveUserPath(destination);
|
|
41134
41188
|
if (!overwrite) {
|
|
41135
41189
|
try {
|
|
41136
41190
|
await fs35__default.access(destPath);
|
|
@@ -41216,7 +41270,7 @@ Examples:
|
|
|
41216
41270
|
}),
|
|
41217
41271
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
41218
41272
|
try {
|
|
41219
|
-
const absolutePath =
|
|
41273
|
+
const absolutePath = resolveUserPath(dirPath ?? ".");
|
|
41220
41274
|
let totalFiles = 0;
|
|
41221
41275
|
let totalDirs = 0;
|
|
41222
41276
|
const lines = [path39__default.basename(absolutePath) + "/"];
|
|
@@ -49682,6 +49736,43 @@ function getAllCommands() {
|
|
|
49682
49736
|
|
|
49683
49737
|
// src/cli/repl/input/handler.ts
|
|
49684
49738
|
var HISTORY_FILE = path39.join(os4.homedir(), ".coco", "history");
|
|
49739
|
+
function navigateHistory(direction, state) {
|
|
49740
|
+
const { currentLine, historyIndex, sessionHistory, tempLine } = state;
|
|
49741
|
+
if (direction === "up") {
|
|
49742
|
+
if (sessionHistory.length === 0) return null;
|
|
49743
|
+
let nextIndex = historyIndex;
|
|
49744
|
+
let nextTempLine = tempLine;
|
|
49745
|
+
if (nextIndex === -1) {
|
|
49746
|
+
nextTempLine = currentLine;
|
|
49747
|
+
nextIndex = sessionHistory.length - 1;
|
|
49748
|
+
} else if (nextIndex > 0) {
|
|
49749
|
+
nextIndex--;
|
|
49750
|
+
}
|
|
49751
|
+
return {
|
|
49752
|
+
currentLine: sessionHistory[nextIndex] ?? "",
|
|
49753
|
+
cursorPos: 0,
|
|
49754
|
+
historyIndex: nextIndex,
|
|
49755
|
+
tempLine: nextTempLine
|
|
49756
|
+
};
|
|
49757
|
+
}
|
|
49758
|
+
if (historyIndex === -1) return null;
|
|
49759
|
+
if (historyIndex < sessionHistory.length - 1) {
|
|
49760
|
+
const nextIndex = historyIndex + 1;
|
|
49761
|
+
const nextLine = sessionHistory[nextIndex] ?? "";
|
|
49762
|
+
return {
|
|
49763
|
+
currentLine: nextLine,
|
|
49764
|
+
cursorPos: nextLine.length,
|
|
49765
|
+
historyIndex: nextIndex,
|
|
49766
|
+
tempLine
|
|
49767
|
+
};
|
|
49768
|
+
}
|
|
49769
|
+
return {
|
|
49770
|
+
currentLine: tempLine,
|
|
49771
|
+
cursorPos: tempLine.length,
|
|
49772
|
+
historyIndex: -1,
|
|
49773
|
+
tempLine
|
|
49774
|
+
};
|
|
49775
|
+
}
|
|
49685
49776
|
async function handleOptionC(copyFn = copyToClipboard, getLastBlockFn = getLastBlock) {
|
|
49686
49777
|
const block = getLastBlockFn();
|
|
49687
49778
|
if (!block) return null;
|
|
@@ -50255,14 +50346,18 @@ function createInputHandler(_session) {
|
|
|
50255
50346
|
cursorPos = 0;
|
|
50256
50347
|
render();
|
|
50257
50348
|
} else if (sessionHistory.length > 0) {
|
|
50258
|
-
|
|
50259
|
-
|
|
50260
|
-
historyIndex
|
|
50261
|
-
|
|
50262
|
-
|
|
50349
|
+
const nextState = navigateHistory("up", {
|
|
50350
|
+
currentLine,
|
|
50351
|
+
historyIndex,
|
|
50352
|
+
sessionHistory,
|
|
50353
|
+
tempLine
|
|
50354
|
+
});
|
|
50355
|
+
if (nextState) {
|
|
50356
|
+
currentLine = nextState.currentLine;
|
|
50357
|
+
cursorPos = nextState.cursorPos;
|
|
50358
|
+
historyIndex = nextState.historyIndex;
|
|
50359
|
+
tempLine = nextState.tempLine;
|
|
50263
50360
|
}
|
|
50264
|
-
currentLine = sessionHistory[historyIndex] ?? "";
|
|
50265
|
-
cursorPos = currentLine.length;
|
|
50266
50361
|
render();
|
|
50267
50362
|
}
|
|
50268
50363
|
return;
|
|
@@ -50284,14 +50379,18 @@ function createInputHandler(_session) {
|
|
|
50284
50379
|
cursorPos = currentLine.length;
|
|
50285
50380
|
render();
|
|
50286
50381
|
} else if (historyIndex !== -1) {
|
|
50287
|
-
|
|
50288
|
-
|
|
50289
|
-
|
|
50290
|
-
|
|
50291
|
-
|
|
50292
|
-
|
|
50382
|
+
const nextState = navigateHistory("down", {
|
|
50383
|
+
currentLine,
|
|
50384
|
+
historyIndex,
|
|
50385
|
+
sessionHistory,
|
|
50386
|
+
tempLine
|
|
50387
|
+
});
|
|
50388
|
+
if (nextState) {
|
|
50389
|
+
currentLine = nextState.currentLine;
|
|
50390
|
+
cursorPos = nextState.cursorPos;
|
|
50391
|
+
historyIndex = nextState.historyIndex;
|
|
50392
|
+
tempLine = nextState.tempLine;
|
|
50293
50393
|
}
|
|
50294
|
-
cursorPos = currentLine.length;
|
|
50295
50394
|
render();
|
|
50296
50395
|
}
|
|
50297
50396
|
return;
|
|
@@ -53002,6 +53101,8 @@ async function startRepl(options = {}) {
|
|
|
53002
53101
|
);
|
|
53003
53102
|
}
|
|
53004
53103
|
let mcpManager = null;
|
|
53104
|
+
let configuredMcpServers = [];
|
|
53105
|
+
const registeredMcpServers = /* @__PURE__ */ new Set();
|
|
53005
53106
|
const logger2 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
53006
53107
|
try {
|
|
53007
53108
|
const { getMCPServerManager: getMCPServerManager2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
|
|
@@ -53018,6 +53119,7 @@ async function startRepl(options = {}) {
|
|
|
53018
53119
|
cocoConfigServers.filter((s) => s.enabled !== false),
|
|
53019
53120
|
projectServers.filter((s) => s.enabled !== false)
|
|
53020
53121
|
);
|
|
53122
|
+
configuredMcpServers = enabledServers;
|
|
53021
53123
|
if (enabledServers.length > 0) {
|
|
53022
53124
|
mcpManager = getMCPServerManager2();
|
|
53023
53125
|
let connections;
|
|
@@ -53037,6 +53139,7 @@ async function startRepl(options = {}) {
|
|
|
53037
53139
|
for (const connection of connections.values()) {
|
|
53038
53140
|
try {
|
|
53039
53141
|
const wrapped = await registerMCPTools2(toolRegistry, connection.name, connection.client);
|
|
53142
|
+
registeredMcpServers.add(connection.name);
|
|
53040
53143
|
if (wrapped.length === 0) {
|
|
53041
53144
|
logger2.warn(
|
|
53042
53145
|
`[MCP] Server '${connection.name}' connected but exposed 0 tools (check server auth/scopes).`
|
|
@@ -53065,6 +53168,42 @@ async function startRepl(options = {}) {
|
|
|
53065
53168
|
`[MCP] Initialization failed: ${mcpError instanceof Error ? mcpError.message : String(mcpError)}`
|
|
53066
53169
|
);
|
|
53067
53170
|
}
|
|
53171
|
+
async function ensureRequestedMcpConnections(message) {
|
|
53172
|
+
if (!mcpManager || configuredMcpServers.length === 0) return;
|
|
53173
|
+
const normalizedMessage = message.toLowerCase();
|
|
53174
|
+
const explicitlyRequestsMcp = /\bmcp\b/.test(normalizedMessage) || /\b(use|using|usa|usar|utiliza|utilizar)\b.{0,24}\bmcp\b/.test(normalizedMessage);
|
|
53175
|
+
const matchingServers = configuredMcpServers.filter((server) => {
|
|
53176
|
+
if (mcpManager?.getConnection(server.name)) return false;
|
|
53177
|
+
if (explicitlyRequestsMcp) return true;
|
|
53178
|
+
const loweredName = server.name.toLowerCase();
|
|
53179
|
+
if (normalizedMessage.includes(loweredName)) return true;
|
|
53180
|
+
if (loweredName.includes("atlassian")) {
|
|
53181
|
+
return /\b(atlassian|jira|confluence)\b/.test(normalizedMessage);
|
|
53182
|
+
}
|
|
53183
|
+
return false;
|
|
53184
|
+
});
|
|
53185
|
+
for (const server of matchingServers) {
|
|
53186
|
+
try {
|
|
53187
|
+
const connection = await mcpManager.startServer(server);
|
|
53188
|
+
if (!registeredMcpServers.has(connection.name)) {
|
|
53189
|
+
await (await Promise.resolve().then(() => (init_tools(), tools_exports))).registerMCPTools(
|
|
53190
|
+
toolRegistry,
|
|
53191
|
+
connection.name,
|
|
53192
|
+
connection.client
|
|
53193
|
+
);
|
|
53194
|
+
registeredMcpServers.add(connection.name);
|
|
53195
|
+
}
|
|
53196
|
+
} catch (error) {
|
|
53197
|
+
logger2.warn(
|
|
53198
|
+
`[MCP] On-demand connect failed for '${server.name}': ${error instanceof Error ? error.message : String(error)}`
|
|
53199
|
+
);
|
|
53200
|
+
}
|
|
53201
|
+
}
|
|
53202
|
+
}
|
|
53203
|
+
function extractMessageText(content) {
|
|
53204
|
+
if (typeof content === "string") return content;
|
|
53205
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join(" ");
|
|
53206
|
+
}
|
|
53068
53207
|
let hookRegistry;
|
|
53069
53208
|
let hookExecutor;
|
|
53070
53209
|
try {
|
|
@@ -53512,6 +53651,7 @@ ${imagePrompts}`.trim() : imagePrompts;
|
|
|
53512
53651
|
let streamStarted = false;
|
|
53513
53652
|
let llmCallCount = 0;
|
|
53514
53653
|
let lastToolGroup = null;
|
|
53654
|
+
await ensureRequestedMcpConnections(extractMessageText(effectiveMessage));
|
|
53515
53655
|
const result = await executeAgentTurn(session, effectiveMessage, provider, toolRegistry, {
|
|
53516
53656
|
onStream: (chunk) => {
|
|
53517
53657
|
if (!streamStarted) {
|