@corbat-tech/coco 2.25.9 → 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 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
@@ -2588,6 +2591,10 @@ async function getLastUsedProvider() {
2588
2591
  async function getLastUsedModel(provider) {
2589
2592
  try {
2590
2593
  const config = await loadConfig(CONFIG_PATHS.config);
2594
+ const perProviderModel = normalizeConfiguredModel(config.providerModels?.[provider]);
2595
+ if (perProviderModel) {
2596
+ return perProviderModel;
2597
+ }
2591
2598
  if (config.provider.type === provider) {
2592
2599
  return normalizeConfiguredModel(config.provider.model);
2593
2600
  }
@@ -2627,6 +2634,11 @@ async function saveProviderPreference(provider, model) {
2627
2634
  }
2628
2635
  config.provider.type = provider;
2629
2636
  const normalizedModel = normalizeConfiguredModel(model);
2637
+ const persistedModel = normalizedModel ?? getDefaultModel(provider);
2638
+ config.providerModels = {
2639
+ ...config.providerModels,
2640
+ [provider]: persistedModel
2641
+ };
2630
2642
  if (normalizedModel) {
2631
2643
  config.provider.model = normalizedModel;
2632
2644
  } else {
@@ -2725,11 +2737,25 @@ async function migrateOldPreferences() {
2725
2737
  }
2726
2738
  if (oldPrefs.provider && VALID_PROVIDERS.includes(oldPrefs.provider)) {
2727
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
+ }
2728
2751
  const modelForProvider = oldPrefs.provider ? oldPrefs.models?.[oldPrefs.provider] : void 0;
2729
- if (modelForProvider) {
2730
- config.provider.model = modelForProvider;
2752
+ const normalizedMigratedModel = normalizeConfiguredModel(modelForProvider);
2753
+ if (normalizedMigratedModel) {
2754
+ config.provider.model = normalizedMigratedModel;
2755
+ config.providerModels[oldPrefs.provider] = normalizedMigratedModel;
2731
2756
  } else {
2732
2757
  config.provider.model = getDefaultModel(oldPrefs.provider);
2758
+ config.providerModels[oldPrefs.provider] = config.provider.model;
2733
2759
  }
2734
2760
  await saveConfig(config, void 0, true);
2735
2761
  }
@@ -34614,8 +34640,9 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
34614
34640
  newApiKeyForSaving = key;
34615
34641
  }
34616
34642
  }
34643
+ const rememberedModel = await getLastUsedModel(newProvider.id);
34617
34644
  const recommendedModel = getRecommendedModel(newProvider.id);
34618
- const newModel = recommendedModel?.id || newProvider.models[0]?.id || "";
34645
+ const newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
34619
34646
  const spinner18 = p26.spinner();
34620
34647
  spinner18.start(`Connecting to ${newProvider.name}...`);
34621
34648
  try {
@@ -53074,6 +53101,8 @@ async function startRepl(options = {}) {
53074
53101
  );
53075
53102
  }
53076
53103
  let mcpManager = null;
53104
+ let configuredMcpServers = [];
53105
+ const registeredMcpServers = /* @__PURE__ */ new Set();
53077
53106
  const logger2 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
53078
53107
  try {
53079
53108
  const { getMCPServerManager: getMCPServerManager2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
@@ -53090,6 +53119,7 @@ async function startRepl(options = {}) {
53090
53119
  cocoConfigServers.filter((s) => s.enabled !== false),
53091
53120
  projectServers.filter((s) => s.enabled !== false)
53092
53121
  );
53122
+ configuredMcpServers = enabledServers;
53093
53123
  if (enabledServers.length > 0) {
53094
53124
  mcpManager = getMCPServerManager2();
53095
53125
  let connections;
@@ -53109,6 +53139,7 @@ async function startRepl(options = {}) {
53109
53139
  for (const connection of connections.values()) {
53110
53140
  try {
53111
53141
  const wrapped = await registerMCPTools2(toolRegistry, connection.name, connection.client);
53142
+ registeredMcpServers.add(connection.name);
53112
53143
  if (wrapped.length === 0) {
53113
53144
  logger2.warn(
53114
53145
  `[MCP] Server '${connection.name}' connected but exposed 0 tools (check server auth/scopes).`
@@ -53137,6 +53168,42 @@ async function startRepl(options = {}) {
53137
53168
  `[MCP] Initialization failed: ${mcpError instanceof Error ? mcpError.message : String(mcpError)}`
53138
53169
  );
53139
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
+ }
53140
53207
  let hookRegistry;
53141
53208
  let hookExecutor;
53142
53209
  try {
@@ -53584,6 +53651,7 @@ ${imagePrompts}`.trim() : imagePrompts;
53584
53651
  let streamStarted = false;
53585
53652
  let llmCallCount = 0;
53586
53653
  let lastToolGroup = null;
53654
+ await ensureRequestedMcpConnections(extractMessageText(effectiveMessage));
53587
53655
  const result = await executeAgentTurn(session, effectiveMessage, provider, toolRegistry, {
53588
53656
  onStream: (chunk) => {
53589
53657
  if (!streamStarted) {