cast-code 1.0.5 → 1.0.7

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.
Files changed (47) hide show
  1. package/dist/common/services/multi-llm.service.js +19 -0
  2. package/dist/common/services/multi-llm.service.js.map +1 -1
  3. package/dist/modules/config/services/config-commands.service.js +86 -6
  4. package/dist/modules/config/services/config-commands.service.js.map +1 -1
  5. package/dist/modules/config/types/config.types.js +5 -0
  6. package/dist/modules/config/types/config.types.js.map +1 -1
  7. package/dist/modules/config/types/config.types.spec.js +60 -0
  8. package/dist/modules/config/types/config.types.spec.js.map +1 -0
  9. package/dist/modules/core/services/deep-agent.service.js +40 -4
  10. package/dist/modules/core/services/deep-agent.service.js.map +1 -1
  11. package/dist/modules/git/git.module.js +5 -2
  12. package/dist/modules/git/git.module.js.map +1 -1
  13. package/dist/modules/git/git.module.spec.js +54 -0
  14. package/dist/modules/git/git.module.spec.js.map +1 -0
  15. package/dist/modules/git/services/pr-generator.service.js +70 -69
  16. package/dist/modules/git/services/pr-generator.service.js.map +1 -1
  17. package/dist/modules/git/services/unit-test-generator.service.js +557 -0
  18. package/dist/modules/git/services/unit-test-generator.service.js.map +1 -0
  19. package/dist/modules/git/services/unit-test-generator.service.spec.js +119 -0
  20. package/dist/modules/git/services/unit-test-generator.service.spec.js.map +1 -0
  21. package/dist/modules/repl/services/commands/git-commands.service.js +97 -2
  22. package/dist/modules/repl/services/commands/git-commands.service.js.map +1 -1
  23. package/dist/modules/repl/services/commands/repl-commands.service.js +1 -0
  24. package/dist/modules/repl/services/commands/repl-commands.service.js.map +1 -1
  25. package/dist/modules/repl/services/commands/repl-commands.service.spec.js +69 -0
  26. package/dist/modules/repl/services/commands/repl-commands.service.spec.js.map +1 -0
  27. package/dist/modules/repl/services/repl.service.js +11 -1
  28. package/dist/modules/repl/services/repl.service.js.map +1 -1
  29. package/dist/modules/repl/services/repl.service.spec.js +137 -0
  30. package/dist/modules/repl/services/repl.service.spec.js.map +1 -0
  31. package/package.json +1 -1
  32. package/dist/modules/agents/definitions/architect.md +0 -35
  33. package/dist/modules/agents/definitions/backend.md +0 -43
  34. package/dist/modules/agents/definitions/coder.md +0 -34
  35. package/dist/modules/agents/definitions/devops.md +0 -42
  36. package/dist/modules/agents/definitions/frontend.md +0 -46
  37. package/dist/modules/agents/definitions/reviewer.md +0 -35
  38. package/dist/modules/agents/definitions/tester.md +0 -41
  39. package/dist/modules/skills/definitions/general/file-operations.md +0 -60
  40. package/dist/modules/skills/definitions/general/git-operations.md +0 -59
  41. package/dist/modules/skills/definitions/general/planning.md +0 -86
  42. package/dist/modules/skills/definitions/general/search.md +0 -59
  43. package/dist/modules/skills/definitions/specialized/api-design.md +0 -85
  44. package/dist/modules/skills/definitions/specialized/database-operations.md +0 -78
  45. package/dist/modules/skills/definitions/specialized/frontend-bootstrap.md +0 -71
  46. package/dist/modules/skills/definitions/specialized/react-patterns.md +0 -77
  47. package/dist/modules/skills/definitions/specialized/testing-strategies.md +0 -79
@@ -42,6 +42,21 @@ let MultiLlmService = class MultiLlmService {
42
42
  createModelForProvider(provider, config, model, temperature, streaming) {
43
43
  switch(provider){
44
44
  case 'openai':
45
+ return new _openai.ChatOpenAI({
46
+ modelName: model,
47
+ ...temperature !== undefined ? {
48
+ temperature
49
+ } : {},
50
+ apiKey: config.apiKey,
51
+ configuration: {
52
+ baseURL: config.baseUrl
53
+ },
54
+ ...this.requiresResponsesApi(model) ? {
55
+ useResponsesApi: true
56
+ } : {},
57
+ streaming,
58
+ streamUsage: streaming
59
+ });
45
60
  case 'deepseek':
46
61
  case 'openrouter':
47
62
  return new _openai.ChatOpenAI({
@@ -100,6 +115,10 @@ let MultiLlmService = class MultiLlmService {
100
115
  throw new Error(`Unsupported provider: ${provider}`);
101
116
  }
102
117
  }
118
+ requiresResponsesApi(model) {
119
+ const normalized = (model || '').toLowerCase();
120
+ return normalized.startsWith('gpt-5') || normalized.includes('codex');
121
+ }
103
122
  constructor(configManager){
104
123
  this.configManager = configManager;
105
124
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/common/services/multi-llm.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { ChatOpenAI } from '@langchain/openai';\nimport { ChatOllama } from '@langchain/ollama';\nimport { ChatAnthropic } from '@langchain/anthropic';\nimport { ChatGoogleGenerativeAI } from '@langchain/google-genai';\nimport { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport { ConfigManagerService } from '../../modules/config/services/config-manager.service';\nimport {\n ModelPurpose,\n ProviderType,\n} from '../../modules/config/types/config.types';\n\n@Injectable()\nexport class MultiLlmService {\n constructor(private readonly configManager: ConfigManagerService) {}\n\n createModel(purpose: ModelPurpose = 'default', streaming = false): BaseChatModel {\n const modelConfig = this.configManager.getModelConfig(purpose);\n\n if (!modelConfig) {\n throw new Error(\n `No model configured for purpose \"${purpose}\". ` +\n 'Run \"cast config init\" to configure.'\n );\n }\n\n const { provider, model, temperature } = modelConfig;\n const providerConfig = this.configManager.getProviderConfig(provider);\n\n if (!providerConfig) {\n throw new Error(\n `Provider \"${provider}\" is not configured. ` +\n 'Run \"cast config init\" to configure.'\n );\n }\n\n return this.createModelForProvider(\n provider,\n providerConfig,\n model,\n temperature,\n streaming\n );\n }\n\n createStreamingModel(purpose: ModelPurpose = 'default'): BaseChatModel {\n return this.createModel(purpose, true);\n }\n\n private createModelForProvider(\n provider: ProviderType,\n config: { apiKey?: string; baseUrl?: string },\n model: string,\n temperature: number | undefined,\n streaming: boolean\n ): BaseChatModel {\n switch (provider) {\n case 'openai':\n case 'deepseek':\n case 'openrouter':\n return new ChatOpenAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n configuration: {\n baseURL: config.baseUrl,\n },\n streaming,\n streamUsage: streaming,\n });\n\n case 'anthropic':\n return new ChatAnthropic({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n anthropicApiKey: config.apiKey,\n anthropicApiUrl: config.baseUrl,\n streaming,\n });\n\n case 'gemini':\n return new ChatGoogleGenerativeAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n streaming,\n });\n\n case 'kimi':\n return new ChatOpenAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n configuration: {\n baseURL: config.baseUrl || 'https://api.moonshot.cn/v1',\n },\n streaming,\n streamUsage: streaming,\n });\n\n case 'ollama':\n return new ChatOllama({\n model,\n ...(temperature !== undefined ? { temperature } : {}),\n baseUrl: config.baseUrl || 'http://localhost:11434',\n });\n\n default:\n throw new Error(`Unsupported provider: ${provider}`);\n }\n }\n}\n"],"names":["MultiLlmService","createModel","purpose","streaming","modelConfig","configManager","getModelConfig","Error","provider","model","temperature","providerConfig","getProviderConfig","createModelForProvider","createStreamingModel","config","ChatOpenAI","modelName","undefined","apiKey","configuration","baseURL","baseUrl","streamUsage","ChatAnthropic","anthropicApiKey","anthropicApiUrl","ChatGoogleGenerativeAI","ChatOllama"],"mappings":";;;;+BAaaA;;;eAAAA;;;wBAbc;wBACA;wBACA;2BACG;6BACS;sCAEF;;;;;;;;;;AAO9B,IAAA,AAAMA,kBAAN,MAAMA;IAGXC,YAAYC,UAAwB,SAAS,EAAEC,YAAY,KAAK,EAAiB;QAC/E,MAAMC,cAAc,IAAI,CAACC,aAAa,CAACC,cAAc,CAACJ;QAEtD,IAAI,CAACE,aAAa;YAChB,MAAM,IAAIG,MACR,CAAC,iCAAiC,EAAEL,QAAQ,GAAG,CAAC,GAC9C;QAEN;QAEA,MAAM,EAAEM,QAAQ,EAAEC,KAAK,EAAEC,WAAW,EAAE,GAAGN;QACzC,MAAMO,iBAAiB,IAAI,CAACN,aAAa,CAACO,iBAAiB,CAACJ;QAE5D,IAAI,CAACG,gBAAgB;YACnB,MAAM,IAAIJ,MACR,CAAC,UAAU,EAAEC,SAAS,qBAAqB,CAAC,GAC1C;QAEN;QAEA,OAAO,IAAI,CAACK,sBAAsB,CAChCL,UACAG,gBACAF,OACAC,aACAP;IAEJ;IAEAW,qBAAqBZ,UAAwB,SAAS,EAAiB;QACrE,OAAO,IAAI,CAACD,WAAW,CAACC,SAAS;IACnC;IAEQW,uBACNL,QAAsB,EACtBO,MAA6C,EAC7CN,KAAa,EACbC,WAA+B,EAC/BP,SAAkB,EACH;QACf,OAAQK;YACN,KAAK;YACL,KAAK;YACL,KAAK;gBACH,OAAO,IAAIQ,kBAAU,CAAC;oBACpBC,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDS,QAAQJ,OAAOI,MAAM;oBACrBC,eAAe;wBACbC,SAASN,OAAOO,OAAO;oBACzB;oBACAnB;oBACAoB,aAAapB;gBACf;YAEF,KAAK;gBACH,OAAO,IAAIqB,wBAAa,CAAC;oBACvBP,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDe,iBAAiBV,OAAOI,MAAM;oBAC9BO,iBAAiBX,OAAOO,OAAO;oBAC/BnB;gBACF;YAEF,KAAK;gBACH,OAAO,IAAIwB,mCAAsB,CAAC;oBAChCV,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDS,QAAQJ,OAAOI,MAAM;oBACrBhB;gBACF;YAEF,KAAK;gBACH,OAAO,IAAIa,kBAAU,CAAC;oBACpBC,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDS,QAAQJ,OAAOI,MAAM;oBACrBC,eAAe;wBACbC,SAASN,OAAOO,OAAO,IAAI;oBAC7B;oBACAnB;oBACAoB,aAAapB;gBACf;YAEF,KAAK;gBACH,OAAO,IAAIyB,kBAAU,CAAC;oBACpBnB;oBACA,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDY,SAASP,OAAOO,OAAO,IAAI;gBAC7B;YAEF;gBACE,MAAM,IAAIf,MAAM,CAAC,sBAAsB,EAAEC,UAAU;QACvD;IACF;IAhGA,YAAY,AAAiBH,aAAmC,CAAE;aAArCA,gBAAAA;IAAsC;AAiGrE"}
1
+ {"version":3,"sources":["../../../src/common/services/multi-llm.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { ChatOpenAI } from '@langchain/openai';\nimport { ChatOllama } from '@langchain/ollama';\nimport { ChatAnthropic } from '@langchain/anthropic';\nimport { ChatGoogleGenerativeAI } from '@langchain/google-genai';\nimport { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport { ConfigManagerService } from '../../modules/config/services/config-manager.service';\nimport {\n ModelPurpose,\n ProviderType,\n} from '../../modules/config/types/config.types';\n\n@Injectable()\nexport class MultiLlmService {\n constructor(private readonly configManager: ConfigManagerService) {}\n\n createModel(purpose: ModelPurpose = 'default', streaming = false): BaseChatModel {\n const modelConfig = this.configManager.getModelConfig(purpose);\n\n if (!modelConfig) {\n throw new Error(\n `No model configured for purpose \"${purpose}\". ` +\n 'Run \"cast config init\" to configure.'\n );\n }\n\n const { provider, model, temperature } = modelConfig;\n const providerConfig = this.configManager.getProviderConfig(provider);\n\n if (!providerConfig) {\n throw new Error(\n `Provider \"${provider}\" is not configured. ` +\n 'Run \"cast config init\" to configure.'\n );\n }\n\n return this.createModelForProvider(\n provider,\n providerConfig,\n model,\n temperature,\n streaming\n );\n }\n\n createStreamingModel(purpose: ModelPurpose = 'default'): BaseChatModel {\n return this.createModel(purpose, true);\n }\n\n private createModelForProvider(\n provider: ProviderType,\n config: { apiKey?: string; baseUrl?: string },\n model: string,\n temperature: number | undefined,\n streaming: boolean\n ): BaseChatModel {\n switch (provider) {\n case 'openai':\n return new ChatOpenAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n configuration: {\n baseURL: config.baseUrl,\n },\n ...(this.requiresResponsesApi(model) ? { useResponsesApi: true } : {}),\n streaming,\n streamUsage: streaming,\n });\n\n case 'deepseek':\n case 'openrouter':\n return new ChatOpenAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n configuration: {\n baseURL: config.baseUrl,\n },\n streaming,\n streamUsage: streaming,\n });\n\n case 'anthropic':\n return new ChatAnthropic({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n anthropicApiKey: config.apiKey,\n anthropicApiUrl: config.baseUrl,\n streaming,\n });\n\n case 'gemini':\n return new ChatGoogleGenerativeAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n streaming,\n });\n\n case 'kimi':\n return new ChatOpenAI({\n modelName: model,\n ...(temperature !== undefined ? { temperature } : {}),\n apiKey: config.apiKey,\n configuration: {\n baseURL: config.baseUrl || 'https://api.moonshot.cn/v1',\n },\n streaming,\n streamUsage: streaming,\n });\n\n case 'ollama':\n return new ChatOllama({\n model,\n ...(temperature !== undefined ? { temperature } : {}),\n baseUrl: config.baseUrl || 'http://localhost:11434',\n });\n\n default:\n throw new Error(`Unsupported provider: ${provider}`);\n }\n }\n\n private requiresResponsesApi(model: string): boolean {\n const normalized = (model || '').toLowerCase();\n return normalized.startsWith('gpt-5') || normalized.includes('codex');\n }\n}\n"],"names":["MultiLlmService","createModel","purpose","streaming","modelConfig","configManager","getModelConfig","Error","provider","model","temperature","providerConfig","getProviderConfig","createModelForProvider","createStreamingModel","config","ChatOpenAI","modelName","undefined","apiKey","configuration","baseURL","baseUrl","requiresResponsesApi","useResponsesApi","streamUsage","ChatAnthropic","anthropicApiKey","anthropicApiUrl","ChatGoogleGenerativeAI","ChatOllama","normalized","toLowerCase","startsWith","includes"],"mappings":"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"}
@@ -36,6 +36,7 @@ let ConfigCommandsService = class ConfigCommandsService {
36
36
  'setup',
37
37
  'add-provider',
38
38
  'set-model',
39
+ 'set-api-key',
39
40
  'remove-provider'
40
41
  ].includes(subcommand || '');
41
42
  if (useInquirerFlow) {
@@ -56,6 +57,9 @@ let ConfigCommandsService = class ConfigCommandsService {
56
57
  case 'set-model':
57
58
  await this.withEscHandler(()=>this.setModelInteractive());
58
59
  break;
60
+ case 'set-api-key':
61
+ await this.withEscHandler(()=>this.setApiKeyInteractive());
62
+ break;
59
63
  case 'remove-provider':
60
64
  await this.withEscHandler(()=>this.removeProviderInteractive());
61
65
  break;
@@ -123,11 +127,16 @@ let ConfigCommandsService = class ConfigCommandsService {
123
127
  },
124
128
  {
125
129
  key: '6',
130
+ label: 'Alterar API key',
131
+ description: 'Atualizar credencial de um provedor'
132
+ },
133
+ {
134
+ key: '7',
126
135
  label: 'Ver caminho do arquivo',
127
136
  description: 'Local do config.yaml'
128
137
  },
129
138
  {
130
- key: '7',
139
+ key: '8',
131
140
  label: 'Sair',
132
141
  description: 'Voltar ao chat'
133
142
  }
@@ -141,25 +150,36 @@ let ConfigCommandsService = class ConfigCommandsService {
141
150
  await this.showConfig();
142
151
  break;
143
152
  case '2':
144
- await this.withEscHandler(()=>this.initService.runInitialSetup());
153
+ await this.runInquirerFlow(smartInput, ()=>this.initService.runInitialSetup());
145
154
  return;
146
155
  case '3':
147
- await this.withEscHandler(()=>this.addProviderInteractive());
156
+ await this.runInquirerFlow(smartInput, ()=>this.addProviderInteractive());
148
157
  break;
149
158
  case '4':
150
- await this.withEscHandler(()=>this.removeProviderInteractive());
159
+ await this.runInquirerFlow(smartInput, ()=>this.removeProviderInteractive());
151
160
  break;
152
161
  case '5':
153
- await this.withEscHandler(()=>this.setModelInteractive());
162
+ await this.runInquirerFlow(smartInput, ()=>this.setModelInteractive());
154
163
  break;
155
164
  case '6':
156
- console.log(`\n📁 ${this.configManager.getConfigPath()}\n`);
165
+ await this.runInquirerFlow(smartInput, ()=>this.setApiKeyInteractive());
157
166
  break;
158
167
  case '7':
168
+ console.log(`\n📁 ${this.configManager.getConfigPath()}\n`);
169
+ break;
170
+ case '8':
159
171
  return;
160
172
  }
161
173
  }
162
174
  }
175
+ async runInquirerFlow(smartInput, fn) {
176
+ smartInput.pause();
177
+ try {
178
+ await this.withEscHandler(fn);
179
+ } finally{
180
+ smartInput.resume();
181
+ }
182
+ }
163
183
  async showConfig() {
164
184
  await this.configManager.loadConfig();
165
185
  const config = this.configManager.getConfig();
@@ -394,6 +414,66 @@ let ConfigCommandsService = class ConfigCommandsService {
394
414
  const purposeLabel = _configtypes.MODEL_PURPOSES.find((p)=>p.value === purpose)?.label;
395
415
  console.log(_chalk.default.green(`\n✓ Modelo para "${purposeLabel}" configurado: ${model}\n`));
396
416
  }
417
+ async setApiKeyInteractive() {
418
+ await this.configManager.loadConfig();
419
+ const configuredProviders = this.configManager.getConfiguredProviders().filter((p)=>p !== 'ollama');
420
+ if (configuredProviders.length === 0) {
421
+ console.log(_chalk.default.yellow('\n⚠️ Nenhum provedor com API key configurável encontrado.\n'));
422
+ return;
423
+ }
424
+ console.log(_chalk.default.cyan('\n🔑 Alterar API Key'));
425
+ console.log(_chalk.default.gray('(pressione ESC para cancelar)\n'));
426
+ const provider = await (0, _promptswithesc.selectWithEsc)({
427
+ message: 'Qual provedor deseja atualizar?',
428
+ choices: configuredProviders.map((p)=>({
429
+ name: _configtypes.PROVIDER_METADATA[p].name,
430
+ value: p
431
+ }))
432
+ });
433
+ if (provider === null) {
434
+ console.log(_chalk.default.yellow('\n❌ Cancelado.\n'));
435
+ return;
436
+ }
437
+ const currentConfig = this.configManager.getProviderConfig(provider);
438
+ const apiKeyRaw = await (0, _promptswithesc.inputWithEsc)({
439
+ message: `Nova API key para ${_configtypes.PROVIDER_METADATA[provider].name}:`,
440
+ validate: (v)=>{
441
+ const clean = v.trim();
442
+ if (clean.length <= 5) return 'API key muito curta';
443
+ if (/[\s%]/.test(clean)) return 'API key contém caracteres inválidos (espaços ou %)';
444
+ return true;
445
+ }
446
+ });
447
+ if (apiKeyRaw === null) {
448
+ console.log(_chalk.default.yellow('\n❌ Cancelado.\n'));
449
+ return;
450
+ }
451
+ let baseUrl = currentConfig?.baseUrl;
452
+ const changeBaseUrl = await (0, _promptswithesc.confirmWithEsc)({
453
+ message: 'Deseja alterar a base URL também?',
454
+ default: false
455
+ });
456
+ if (changeBaseUrl === null) {
457
+ console.log(_chalk.default.yellow('\n❌ Cancelado.\n'));
458
+ return;
459
+ }
460
+ if (changeBaseUrl) {
461
+ const newBaseUrl = await (0, _promptswithesc.inputWithEsc)({
462
+ message: 'Nova base URL:',
463
+ default: baseUrl || _configtypes.PROVIDER_METADATA[provider].defaultBaseUrl
464
+ });
465
+ if (newBaseUrl === null) {
466
+ console.log(_chalk.default.yellow('\n❌ Cancelado.\n'));
467
+ return;
468
+ }
469
+ baseUrl = newBaseUrl;
470
+ }
471
+ await this.configManager.addProvider(provider, {
472
+ apiKey: apiKeyRaw.trim(),
473
+ baseUrl
474
+ });
475
+ console.log(_chalk.default.green(`\n✓ API key de ${_configtypes.PROVIDER_METADATA[provider].name} atualizada.\n`));
476
+ }
397
477
  constructor(configManager, initService){
398
478
  this.configManager = configManager;
399
479
  this.initService = initService;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/config/services/config-commands.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport chalk from 'chalk';\nimport { ConfigManagerService } from './config-manager.service';\nimport { InitConfigService } from './init-config.service';\nimport {\n ProviderType,\n PROVIDER_METADATA,\n MODEL_PURPOSES,\n ModelPurpose,\n} from '../types/config.types';\nimport {\n selectWithEsc,\n inputWithEsc,\n confirmWithEsc,\n CancelledPromptError,\n withEsc,\n} from '../../repl/utils/prompts-with-esc';\n\ninterface SmartInput {\n askChoice: (question: string, choices: { key: string; label: string; description: string }[]) => Promise<string>;\n question: (prompt: string) => Promise<string>;\n pause: () => void;\n resume: () => void;\n}\n\n@Injectable()\nexport class ConfigCommandsService {\n constructor(\n private readonly configManager: ConfigManagerService,\n private readonly initService: InitConfigService\n ) {}\n\n async handleConfigCommand(args: string[], smartInput?: SmartInput): Promise<void> {\n const subcommand = args[0];\n const useInquirerFlow = ['init', 'setup', 'add-provider', 'set-model', 'remove-provider'].includes(subcommand || '');\n\n if (useInquirerFlow) {\n smartInput?.pause();\n }\n\n try {\n switch (subcommand) {\n case 'init':\n case 'setup':\n await this.withEscHandler(() => this.initService.runInitialSetup());\n break;\n\n case 'show':\n await this.showConfig();\n break;\n\n case 'add-provider':\n await this.withEscHandler(() => this.addProviderInteractive());\n break;\n\n case 'set-model':\n await this.withEscHandler(() => this.setModelInteractive());\n break;\n\n case 'remove-provider':\n await this.withEscHandler(() => this.removeProviderInteractive());\n break;\n\n case 'path':\n console.log(this.configManager.getConfigPath());\n break;\n\n default:\n if (smartInput) {\n await this.showConfigMenu(smartInput);\n } else {\n await this.showConfig();\n }\n }\n } finally {\n if (useInquirerFlow) {\n smartInput?.resume();\n }\n }\n }\n\n private async withEscHandler<T>(fn: () => Promise<T>): Promise<void> {\n const result = await withEsc(fn);\n if (result === null) {\n console.log(chalk.yellow('\\n\\n❌ Cancelado. Voltando ao menu...\\n'));\n }\n }\n\n private async showConfigMenu(smartInput: SmartInput): Promise<void> {\n const w = (s: string) => process.stdout.write(s);\n const Colors = {\n cyan: '\\x1b[38;5;51m',\n green: '\\x1b[38;5;82m',\n yellow: '\\x1b[38;5;220m',\n gray: '\\x1b[38;5;245m',\n bold: '\\x1b[1m',\n reset: '\\x1b[0m',\n };\n\n await this.configManager.loadConfig();\n\n while (true) {\n w(`\\n${Colors.cyan}${Colors.bold}⚙️ Configuração Cast Code${Colors.reset}\\n`);\n w(`${Colors.gray}${'─'.repeat(30)}${Colors.reset}\\n\\n`);\n\n const action = await withEsc(() => smartInput.askChoice('O que deseja fazer?', [\n { key: '1', label: 'Ver configuração atual', description: 'Mostrar provedores e modelos' },\n { key: '2', label: 'Configuração inicial completa', description: 'Wizard de setup' },\n { key: '3', label: 'Adicionar provedor', description: 'Novo serviço de IA' },\n { key: '4', label: 'Remover provedor', description: 'Remover serviço' },\n { key: '5', label: 'Configurar modelo', description: 'Definir modelo para finalidade' },\n { key: '6', label: 'Ver caminho do arquivo', description: 'Local do config.yaml' },\n { key: '7', label: 'Sair', description: 'Voltar ao chat' },\n ]));\n\n if (action === null) {\n console.log(chalk.yellow('\\nSaindo do menu de configuração...\\n'));\n return;\n }\n\n switch (action) {\n case '1':\n await this.showConfig();\n break;\n case '2':\n await this.withEscHandler(() => this.initService.runInitialSetup());\n return;\n case '3':\n await this.withEscHandler(() => this.addProviderInteractive());\n break;\n case '4':\n await this.withEscHandler(() => this.removeProviderInteractive());\n break;\n case '5':\n await this.withEscHandler(() => this.setModelInteractive());\n break;\n case '6':\n console.log(`\\n📁 ${this.configManager.getConfigPath()}\\n`);\n break;\n case '7':\n return;\n }\n }\n }\n\n private async showConfig(): Promise<void> {\n await this.configManager.loadConfig();\n const config = this.configManager.getConfig();\n\n const w = (s: string) => process.stdout.write(s);\n const Colors = {\n cyan: '\\x1b[38;5;51m',\n green: '\\x1b[38;5;82m',\n red: '\\x1b[38;5;196m',\n yellow: '\\x1b[38;5;220m',\n gray: '\\x1b[38;5;245m',\n bold: '\\x1b[1m',\n reset: '\\x1b[0m',\n };\n\n w(`\\n${Colors.cyan}${Colors.bold}⚙️ Configuração Atual${Colors.reset}\\n`);\n w(`${Colors.gray}${'─'.repeat(40)}${Colors.reset}\\n\\n`);\n\n w(`${Colors.yellow}📦 Provedores configurados:${Colors.reset}\\n`);\n const providers = this.configManager.getConfiguredProviders();\n if (providers.length === 0) {\n w(`${Colors.gray} Nenhum provedor configurado${Colors.reset}\\n`);\n w(`${Colors.gray} Use \"cast config init\" ou /config add-provider${Colors.reset}\\n`);\n } else {\n for (const provider of providers) {\n const meta = PROVIDER_METADATA[provider];\n const isConfigured = this.configManager.isProviderConfigured(provider);\n const status = isConfigured \n ? `${Colors.green}✓` \n : `${Colors.red}✗`;\n w(` ${status} ${meta.name} ${Colors.gray}(${provider})${Colors.reset}\\n`);\n }\n }\n\n w(`\\n${Colors.yellow}🤖 Modelos configurados:${Colors.reset}\\n`);\n for (const purpose of MODEL_PURPOSES) {\n const modelConfig = config.models[purpose.value];\n if (modelConfig) {\n const providerName = PROVIDER_METADATA[modelConfig.provider].name;\n w(` ${Colors.cyan}${purpose.label.padEnd(12)}${Colors.reset} → ${modelConfig.model}\\n`);\n w(` ${Colors.gray}${' '.repeat(12)} ${providerName}${Colors.reset}\\n`);\n }\n }\n\n w(`\\n${Colors.gray}📁 Arquivo: ${this.configManager.getConfigPath()}${Colors.reset}\\n\\n`);\n }\n\n private async addProviderInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const availableProviders = Object.keys(PROVIDER_METADATA).filter(\n (p) => !this.configManager.isProviderConfigured(p as ProviderType)\n ) as ProviderType[];\n\n if (availableProviders.length === 0) {\n console.log(chalk.yellow('\\n⚠️ Todos os provedores já estão configurados!\\n'));\n return;\n }\n\n console.log(chalk.cyan('\\n📦 Adicionar Provedor'));\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor deseja adicionar?',\n choices: availableProviders.map((p) => ({\n name: `${PROVIDER_METADATA[p].name} - ${PROVIDER_METADATA[p].description}`,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const meta = PROVIDER_METADATA[provider];\n\n let config: { apiKey?: string; baseUrl?: string } = {};\n\n if (provider === 'ollama') {\n const baseUrl = await inputWithEsc({\n message: 'URL do servidor Ollama:',\n default: meta.defaultBaseUrl,\n });\n if (baseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n config = { baseUrl };\n } else {\n console.log(chalk.gray(`→ Obtenha sua API key em: ${meta.websiteUrl}`));\n \n const apiKeyRaw = await inputWithEsc({\n message: `API Key para ${meta.name}:`,\n validate: (v) => {\n const clean = v.trim();\n if (clean.length <= 5) return 'API key muito curta';\n if (/[\\s%]/.test(clean)) return 'API key contém caracteres inválidos (espaços ou %)';\n return true;\n },\n });\n\n if (apiKeyRaw === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n const apiKey = apiKeyRaw.trim();\n\n const useCustom = await confirmWithEsc({\n message: 'Usar URL customizada?',\n default: false,\n });\n\n if (useCustom === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n let baseUrl: string | undefined;\n if (useCustom) {\n baseUrl = await inputWithEsc({\n message: 'URL da API:',\n default: meta.defaultBaseUrl,\n });\n if (baseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n\n config = { apiKey, baseUrl };\n }\n\n await this.configManager.addProvider(provider, config);\n console.log(chalk.green(`\\n✓ Provedor ${meta.name} adicionado com sucesso!\\n`));\n }\n\n private async removeProviderInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const configuredProviders = this.configManager.getConfiguredProviders();\n if (configuredProviders.length === 0) {\n console.log(chalk.yellow('\\n⚠️ Nenhum provedor configurado para remover.\\n'));\n return;\n }\n\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor deseja remover?',\n choices: configuredProviders.map((p) => ({\n name: PROVIDER_METADATA[p].name,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const confirmRemove = await confirmWithEsc({\n message: `Tem certeza que deseja remover ${PROVIDER_METADATA[provider].name}?`,\n default: false,\n });\n\n if (confirmRemove === null || !confirmRemove) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const config = this.configManager.getConfig();\n delete config.providers[provider];\n await this.configManager.saveConfig(config);\n console.log(chalk.green(`\\n✓ Provedor removido.\\n`));\n }\n\n private async setModelInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const availableProviders = this.configManager.getConfiguredProviders();\n if (availableProviders.length === 0) {\n console.log(\n chalk.red('\\n❌ Nenhum provedor configurado. Configure um provedor primeiro.\\n')\n );\n return;\n }\n\n console.log(chalk.cyan('\\n🤖 Configurar Modelo'));\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const purpose = await selectWithEsc<ModelPurpose>({\n message: 'Para qual finalidade?',\n choices: MODEL_PURPOSES.map((p) => ({\n name: `${p.label} - ${p.description}`,\n value: p.value,\n })),\n });\n\n if (purpose === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor?',\n choices: availableProviders.map((p) => ({\n name: PROVIDER_METADATA[p].name,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const meta = PROVIDER_METADATA[provider];\n\n const usePopular = await confirmWithEsc({\n message: `Usar um dos modelos populares do ${meta.name}?`,\n default: true,\n });\n\n if (usePopular === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n let model: string | null;\n\n if (usePopular) {\n model = await selectWithEsc<string>({\n message: 'Escolha o modelo:',\n choices: [\n ...meta.popularModels.map((m) => ({ name: m, value: m })),\n { name: '➕ Outro modelo...', value: '__custom__' },\n ],\n });\n\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n if (model === '__custom__') {\n model = await inputWithEsc({\n message: 'Nome do modelo:',\n default: meta.popularModels[0],\n });\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n } else {\n model = await inputWithEsc({\n message: 'Nome do modelo:',\n default: meta.popularModels[0],\n });\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n\n await this.configManager.setModel(purpose, {\n provider,\n model,\n });\n\n const purposeLabel = MODEL_PURPOSES.find((p) => p.value === purpose)?.label;\n console.log(\n chalk.green(`\\n✓ Modelo para \"${purposeLabel}\" configurado: ${model}\\n`)\n );\n }\n}\n"],"names":["ConfigCommandsService","handleConfigCommand","args","smartInput","subcommand","useInquirerFlow","includes","pause","withEscHandler","initService","runInitialSetup","showConfig","addProviderInteractive","setModelInteractive","removeProviderInteractive","console","log","configManager","getConfigPath","showConfigMenu","resume","fn","result","withEsc","chalk","yellow","w","s","process","stdout","write","Colors","cyan","green","gray","bold","reset","loadConfig","repeat","action","askChoice","key","label","description","config","getConfig","red","providers","getConfiguredProviders","length","provider","meta","PROVIDER_METADATA","isConfigured","isProviderConfigured","status","name","purpose","MODEL_PURPOSES","modelConfig","models","value","providerName","padEnd","model","availableProviders","Object","keys","filter","p","selectWithEsc","message","choices","map","baseUrl","inputWithEsc","default","defaultBaseUrl","websiteUrl","apiKeyRaw","validate","v","clean","trim","test","apiKey","useCustom","confirmWithEsc","addProvider","configuredProviders","confirmRemove","saveConfig","usePopular","popularModels","m","setModel","purposeLabel","find"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/modules/config/services/config-commands.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport chalk from 'chalk';\nimport { ConfigManagerService } from './config-manager.service';\nimport { InitConfigService } from './init-config.service';\nimport {\n ProviderType,\n PROVIDER_METADATA,\n MODEL_PURPOSES,\n ModelPurpose,\n} from '../types/config.types';\nimport {\n selectWithEsc,\n inputWithEsc,\n confirmWithEsc,\n CancelledPromptError,\n withEsc,\n} from '../../repl/utils/prompts-with-esc';\n\ninterface SmartInput {\n askChoice: (question: string, choices: { key: string; label: string; description: string }[]) => Promise<string>;\n question: (prompt: string) => Promise<string>;\n pause: () => void;\n resume: () => void;\n}\n\n@Injectable()\nexport class ConfigCommandsService {\n constructor(\n private readonly configManager: ConfigManagerService,\n private readonly initService: InitConfigService\n ) {}\n\n async handleConfigCommand(args: string[], smartInput?: SmartInput): Promise<void> {\n const subcommand = args[0];\n const useInquirerFlow = ['init', 'setup', 'add-provider', 'set-model', 'set-api-key', 'remove-provider'].includes(subcommand || '');\n\n if (useInquirerFlow) {\n smartInput?.pause();\n }\n\n try {\n switch (subcommand) {\n case 'init':\n case 'setup':\n await this.withEscHandler(() => this.initService.runInitialSetup());\n break;\n\n case 'show':\n await this.showConfig();\n break;\n\n case 'add-provider':\n await this.withEscHandler(() => this.addProviderInteractive());\n break;\n\n case 'set-model':\n await this.withEscHandler(() => this.setModelInteractive());\n break;\n\n case 'set-api-key':\n await this.withEscHandler(() => this.setApiKeyInteractive());\n break;\n\n case 'remove-provider':\n await this.withEscHandler(() => this.removeProviderInteractive());\n break;\n\n case 'path':\n console.log(this.configManager.getConfigPath());\n break;\n\n default:\n if (smartInput) {\n await this.showConfigMenu(smartInput);\n } else {\n await this.showConfig();\n }\n }\n } finally {\n if (useInquirerFlow) {\n smartInput?.resume();\n }\n }\n }\n\n private async withEscHandler<T>(fn: () => Promise<T>): Promise<void> {\n const result = await withEsc(fn);\n if (result === null) {\n console.log(chalk.yellow('\\n\\n❌ Cancelado. Voltando ao menu...\\n'));\n }\n }\n\n private async showConfigMenu(smartInput: SmartInput): Promise<void> {\n const w = (s: string) => process.stdout.write(s);\n const Colors = {\n cyan: '\\x1b[38;5;51m',\n green: '\\x1b[38;5;82m',\n yellow: '\\x1b[38;5;220m',\n gray: '\\x1b[38;5;245m',\n bold: '\\x1b[1m',\n reset: '\\x1b[0m',\n };\n\n await this.configManager.loadConfig();\n\n while (true) {\n w(`\\n${Colors.cyan}${Colors.bold}⚙️ Configuração Cast Code${Colors.reset}\\n`);\n w(`${Colors.gray}${'─'.repeat(30)}${Colors.reset}\\n\\n`);\n\n const action = await withEsc(() => smartInput.askChoice('O que deseja fazer?', [\n { key: '1', label: 'Ver configuração atual', description: 'Mostrar provedores e modelos' },\n { key: '2', label: 'Configuração inicial completa', description: 'Wizard de setup' },\n { key: '3', label: 'Adicionar provedor', description: 'Novo serviço de IA' },\n { key: '4', label: 'Remover provedor', description: 'Remover serviço' },\n { key: '5', label: 'Configurar modelo', description: 'Definir modelo para finalidade' },\n { key: '6', label: 'Alterar API key', description: 'Atualizar credencial de um provedor' },\n { key: '7', label: 'Ver caminho do arquivo', description: 'Local do config.yaml' },\n { key: '8', label: 'Sair', description: 'Voltar ao chat' },\n ]));\n\n if (action === null) {\n console.log(chalk.yellow('\\nSaindo do menu de configuração...\\n'));\n return;\n }\n\n switch (action) {\n case '1':\n await this.showConfig();\n break;\n case '2':\n await this.runInquirerFlow(smartInput, () => this.initService.runInitialSetup());\n return;\n case '3':\n await this.runInquirerFlow(smartInput, () => this.addProviderInteractive());\n break;\n case '4':\n await this.runInquirerFlow(smartInput, () => this.removeProviderInteractive());\n break;\n case '5':\n await this.runInquirerFlow(smartInput, () => this.setModelInteractive());\n break;\n case '6':\n await this.runInquirerFlow(smartInput, () => this.setApiKeyInteractive());\n break;\n case '7':\n console.log(`\\n📁 ${this.configManager.getConfigPath()}\\n`);\n break;\n case '8':\n return;\n }\n }\n }\n\n private async runInquirerFlow(smartInput: SmartInput, fn: () => Promise<void>): Promise<void> {\n smartInput.pause();\n try {\n await this.withEscHandler(fn);\n } finally {\n smartInput.resume();\n }\n }\n\n private async showConfig(): Promise<void> {\n await this.configManager.loadConfig();\n const config = this.configManager.getConfig();\n\n const w = (s: string) => process.stdout.write(s);\n const Colors = {\n cyan: '\\x1b[38;5;51m',\n green: '\\x1b[38;5;82m',\n red: '\\x1b[38;5;196m',\n yellow: '\\x1b[38;5;220m',\n gray: '\\x1b[38;5;245m',\n bold: '\\x1b[1m',\n reset: '\\x1b[0m',\n };\n\n w(`\\n${Colors.cyan}${Colors.bold}⚙️ Configuração Atual${Colors.reset}\\n`);\n w(`${Colors.gray}${'─'.repeat(40)}${Colors.reset}\\n\\n`);\n\n w(`${Colors.yellow}📦 Provedores configurados:${Colors.reset}\\n`);\n const providers = this.configManager.getConfiguredProviders();\n if (providers.length === 0) {\n w(`${Colors.gray} Nenhum provedor configurado${Colors.reset}\\n`);\n w(`${Colors.gray} Use \"cast config init\" ou /config add-provider${Colors.reset}\\n`);\n } else {\n for (const provider of providers) {\n const meta = PROVIDER_METADATA[provider];\n const isConfigured = this.configManager.isProviderConfigured(provider);\n const status = isConfigured \n ? `${Colors.green}✓` \n : `${Colors.red}✗`;\n w(` ${status} ${meta.name} ${Colors.gray}(${provider})${Colors.reset}\\n`);\n }\n }\n\n w(`\\n${Colors.yellow}🤖 Modelos configurados:${Colors.reset}\\n`);\n for (const purpose of MODEL_PURPOSES) {\n const modelConfig = config.models[purpose.value];\n if (modelConfig) {\n const providerName = PROVIDER_METADATA[modelConfig.provider].name;\n w(` ${Colors.cyan}${purpose.label.padEnd(12)}${Colors.reset} → ${modelConfig.model}\\n`);\n w(` ${Colors.gray}${' '.repeat(12)} ${providerName}${Colors.reset}\\n`);\n }\n }\n\n w(`\\n${Colors.gray}📁 Arquivo: ${this.configManager.getConfigPath()}${Colors.reset}\\n\\n`);\n }\n\n private async addProviderInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const availableProviders = Object.keys(PROVIDER_METADATA).filter(\n (p) => !this.configManager.isProviderConfigured(p as ProviderType)\n ) as ProviderType[];\n\n if (availableProviders.length === 0) {\n console.log(chalk.yellow('\\n⚠️ Todos os provedores já estão configurados!\\n'));\n return;\n }\n\n console.log(chalk.cyan('\\n📦 Adicionar Provedor'));\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor deseja adicionar?',\n choices: availableProviders.map((p) => ({\n name: `${PROVIDER_METADATA[p].name} - ${PROVIDER_METADATA[p].description}`,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const meta = PROVIDER_METADATA[provider];\n\n let config: { apiKey?: string; baseUrl?: string } = {};\n\n if (provider === 'ollama') {\n const baseUrl = await inputWithEsc({\n message: 'URL do servidor Ollama:',\n default: meta.defaultBaseUrl,\n });\n if (baseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n config = { baseUrl };\n } else {\n console.log(chalk.gray(`→ Obtenha sua API key em: ${meta.websiteUrl}`));\n \n const apiKeyRaw = await inputWithEsc({\n message: `API Key para ${meta.name}:`,\n validate: (v) => {\n const clean = v.trim();\n if (clean.length <= 5) return 'API key muito curta';\n if (/[\\s%]/.test(clean)) return 'API key contém caracteres inválidos (espaços ou %)';\n return true;\n },\n });\n\n if (apiKeyRaw === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n const apiKey = apiKeyRaw.trim();\n\n const useCustom = await confirmWithEsc({\n message: 'Usar URL customizada?',\n default: false,\n });\n\n if (useCustom === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n let baseUrl: string | undefined;\n if (useCustom) {\n baseUrl = await inputWithEsc({\n message: 'URL da API:',\n default: meta.defaultBaseUrl,\n });\n if (baseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n\n config = { apiKey, baseUrl };\n }\n\n await this.configManager.addProvider(provider, config);\n console.log(chalk.green(`\\n✓ Provedor ${meta.name} adicionado com sucesso!\\n`));\n }\n\n private async removeProviderInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const configuredProviders = this.configManager.getConfiguredProviders();\n if (configuredProviders.length === 0) {\n console.log(chalk.yellow('\\n⚠️ Nenhum provedor configurado para remover.\\n'));\n return;\n }\n\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor deseja remover?',\n choices: configuredProviders.map((p) => ({\n name: PROVIDER_METADATA[p].name,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const confirmRemove = await confirmWithEsc({\n message: `Tem certeza que deseja remover ${PROVIDER_METADATA[provider].name}?`,\n default: false,\n });\n\n if (confirmRemove === null || !confirmRemove) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const config = this.configManager.getConfig();\n delete config.providers[provider];\n await this.configManager.saveConfig(config);\n console.log(chalk.green(`\\n✓ Provedor removido.\\n`));\n }\n\n private async setModelInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const availableProviders = this.configManager.getConfiguredProviders();\n if (availableProviders.length === 0) {\n console.log(\n chalk.red('\\n❌ Nenhum provedor configurado. Configure um provedor primeiro.\\n')\n );\n return;\n }\n\n console.log(chalk.cyan('\\n🤖 Configurar Modelo'));\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const purpose = await selectWithEsc<ModelPurpose>({\n message: 'Para qual finalidade?',\n choices: MODEL_PURPOSES.map((p) => ({\n name: `${p.label} - ${p.description}`,\n value: p.value,\n })),\n });\n\n if (purpose === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor?',\n choices: availableProviders.map((p) => ({\n name: PROVIDER_METADATA[p].name,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const meta = PROVIDER_METADATA[provider];\n\n const usePopular = await confirmWithEsc({\n message: `Usar um dos modelos populares do ${meta.name}?`,\n default: true,\n });\n\n if (usePopular === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n let model: string | null;\n\n if (usePopular) {\n model = await selectWithEsc<string>({\n message: 'Escolha o modelo:',\n choices: [\n ...meta.popularModels.map((m) => ({ name: m, value: m })),\n { name: '➕ Outro modelo...', value: '__custom__' },\n ],\n });\n\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n if (model === '__custom__') {\n model = await inputWithEsc({\n message: 'Nome do modelo:',\n default: meta.popularModels[0],\n });\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n } else {\n model = await inputWithEsc({\n message: 'Nome do modelo:',\n default: meta.popularModels[0],\n });\n if (model === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n }\n\n await this.configManager.setModel(purpose, {\n provider,\n model,\n });\n\n const purposeLabel = MODEL_PURPOSES.find((p) => p.value === purpose)?.label;\n console.log(\n chalk.green(`\\n✓ Modelo para \"${purposeLabel}\" configurado: ${model}\\n`)\n );\n }\n\n private async setApiKeyInteractive(): Promise<void> {\n await this.configManager.loadConfig();\n\n const configuredProviders = this.configManager\n .getConfiguredProviders()\n .filter((p) => p !== 'ollama');\n\n if (configuredProviders.length === 0) {\n console.log(chalk.yellow('\\n⚠️ Nenhum provedor com API key configurável encontrado.\\n'));\n return;\n }\n\n console.log(chalk.cyan('\\n🔑 Alterar API Key'));\n console.log(chalk.gray('(pressione ESC para cancelar)\\n'));\n\n const provider = await selectWithEsc<ProviderType>({\n message: 'Qual provedor deseja atualizar?',\n choices: configuredProviders.map((p) => ({\n name: PROVIDER_METADATA[p].name,\n value: p,\n })),\n });\n\n if (provider === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n const currentConfig = this.configManager.getProviderConfig(provider) as { baseUrl?: string } | undefined;\n const apiKeyRaw = await inputWithEsc({\n message: `Nova API key para ${PROVIDER_METADATA[provider].name}:`,\n validate: (v) => {\n const clean = v.trim();\n if (clean.length <= 5) return 'API key muito curta';\n if (/[\\s%]/.test(clean)) return 'API key contém caracteres inválidos (espaços ou %)';\n return true;\n },\n });\n\n if (apiKeyRaw === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n let baseUrl = currentConfig?.baseUrl;\n const changeBaseUrl = await confirmWithEsc({\n message: 'Deseja alterar a base URL também?',\n default: false,\n });\n\n if (changeBaseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n\n if (changeBaseUrl) {\n const newBaseUrl = await inputWithEsc({\n message: 'Nova base URL:',\n default: baseUrl || PROVIDER_METADATA[provider].defaultBaseUrl,\n });\n if (newBaseUrl === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\n baseUrl = newBaseUrl;\n }\n\n await this.configManager.addProvider(provider, {\n apiKey: apiKeyRaw.trim(),\n baseUrl,\n });\n\n console.log(chalk.green(`\\n✓ API key de ${PROVIDER_METADATA[provider].name} atualizada.\\n`));\n }\n}\n"],"names":["ConfigCommandsService","handleConfigCommand","args","smartInput","subcommand","useInquirerFlow","includes","pause","withEscHandler","initService","runInitialSetup","showConfig","addProviderInteractive","setModelInteractive","setApiKeyInteractive","removeProviderInteractive","console","log","configManager","getConfigPath","showConfigMenu","resume","fn","result","withEsc","chalk","yellow","w","s","process","stdout","write","Colors","cyan","green","gray","bold","reset","loadConfig","repeat","action","askChoice","key","label","description","runInquirerFlow","config","getConfig","red","providers","getConfiguredProviders","length","provider","meta","PROVIDER_METADATA","isConfigured","isProviderConfigured","status","name","purpose","MODEL_PURPOSES","modelConfig","models","value","providerName","padEnd","model","availableProviders","Object","keys","filter","p","selectWithEsc","message","choices","map","baseUrl","inputWithEsc","default","defaultBaseUrl","websiteUrl","apiKeyRaw","validate","v","clean","trim","test","apiKey","useCustom","confirmWithEsc","addProvider","configuredProviders","confirmRemove","saveConfig","usePopular","popularModels","m","setModel","purposeLabel","find","currentConfig","getProviderConfig","changeBaseUrl","newBaseUrl"],"mappings":"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"}
@@ -153,6 +153,11 @@ const MODEL_PURPOSES = [
153
153
  label: 'Planner',
154
154
  description: 'Modelo para planejamento de tarefas'
155
155
  },
156
+ {
157
+ value: 'tester',
158
+ label: 'Tester',
159
+ description: 'Modelo para geração e atualização de testes'
160
+ },
156
161
  {
157
162
  value: 'cheap',
158
163
  label: 'Econômico',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/config/types/config.types.ts"],"sourcesContent":["export type ProviderType = \n | 'openai' \n | 'anthropic' \n | 'gemini' \n | 'kimi' \n | 'ollama' \n | 'deepseek'\n | 'openrouter';\n\nexport interface BaseProviderConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\nexport interface OpenAIConfig extends BaseProviderConfig {}\nexport interface AnthropicConfig extends BaseProviderConfig {}\nexport interface GeminiConfig extends BaseProviderConfig {}\nexport interface KimiConfig extends BaseProviderConfig {}\nexport interface DeepSeekConfig extends BaseProviderConfig {}\nexport interface OpenRouterConfig extends BaseProviderConfig {}\n\nexport interface OllamaConfig {\n baseUrl: string;\n}\n\nexport interface ProvidersConfig {\n openai?: OpenAIConfig;\n anthropic?: AnthropicConfig;\n gemini?: GeminiConfig;\n kimi?: KimiConfig;\n deepseek?: DeepSeekConfig;\n openrouter?: OpenRouterConfig;\n ollama?: OllamaConfig;\n}\n\nexport interface ModelConfig {\n provider: ProviderType;\n model: string;\n temperature?: number;\n maxTokens?: number;\n}\n\nexport type ModelPurpose = \n | 'default' \n | 'subAgent' \n | 'coder' \n | 'architect' \n | 'reviewer' \n | 'planner' \n | 'cheap';\n\nexport type ModelsConfig = Partial<Record<ModelPurpose, ModelConfig>>;\n\nexport interface CastConfig {\n version: number;\n providers: ProvidersConfig;\n models: ModelsConfig;\n}\n\nexport interface ProviderMetadata {\n type: ProviderType;\n name: string;\n description: string;\n requiresApiKey: boolean;\n defaultBaseUrl?: string;\n websiteUrl: string;\n popularModels: string[];\n}\n\nexport const PROVIDER_METADATA: Record<ProviderType, ProviderMetadata> = {\n openai: {\n type: 'openai',\n name: 'OpenAI',\n description: 'GPT-4, GPT-4o, GPT-3.5 Turbo e outros',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.openai.com/v1',\n websiteUrl: 'https://platform.openai.com',\n popularModels: [\n 'gpt-5.2',\n 'gpt-5.1',\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5-nano',\n 'gpt-4.1',\n 'gpt-4.1-mini',\n 'gpt-4.1-nano',\n ],\n },\n anthropic: {\n type: 'anthropic',\n name: 'Anthropic',\n description: 'Claude 3.5 Sonnet, Claude 3 Opus, etc.',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.anthropic.com',\n websiteUrl: 'https://console.anthropic.com',\n popularModels: [\n 'claude-opus-4-1-20250805',\n 'claude-sonnet-4-20250514',\n 'claude-3-7-sonnet-20250219',\n 'claude-3-5-haiku-20241022',\n ],\n },\n gemini: {\n type: 'gemini',\n name: 'Google Gemini',\n description: 'Gemini Pro, Gemini Ultra via Google AI Studio',\n requiresApiKey: true,\n defaultBaseUrl: 'https://generativelanguage.googleapis.com',\n websiteUrl: 'https://ai.google.dev',\n popularModels: [\n 'gemini-2.5-pro',\n 'gemini-2.5-flash',\n 'gemini-2.5-flash-lite',\n 'gemini-3-pro-preview',\n 'gemini-3-flash-preview',\n ],\n },\n kimi: {\n type: 'kimi',\n name: 'Moonshot Kimi',\n description: 'Kimi K1, Kimi K2 - modelos chineses avançados',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.moonshot.cn/v1',\n websiteUrl: 'https://platform.moonshot.cn',\n popularModels: ['kimi-k2-0905-preview', 'kimi-k2-turbo-preview', 'kimi-k2-thinking', 'kimi-k2-thinking-turbo'],\n },\n deepseek: {\n type: 'deepseek',\n name: 'DeepSeek',\n description: 'DeepSeek Chat, DeepSeek Coder',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n websiteUrl: 'https://platform.deepseek.com',\n popularModels: ['deepseek-reasoner', 'deepseek-r1', 'deepseek-chat'],\n },\n openrouter: {\n type: 'openrouter',\n name: 'OpenRouter',\n description: 'Acesso a múltiplos modelos via uma API',\n requiresApiKey: true,\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n websiteUrl: 'https://openrouter.ai',\n popularModels: [\n 'openai/gpt-5',\n 'anthropic/claude-sonnet-4',\n 'google/gemini-2.5-pro',\n 'meta-llama/llama-3.1-70b-instruct',\n ],\n },\n ollama: {\n type: 'ollama',\n name: 'Ollama (Local)',\n description: 'Modelos locais via Ollama - gratuito e privado',\n requiresApiKey: false,\n defaultBaseUrl: 'http://localhost:11434',\n websiteUrl: 'https://ollama.com',\n popularModels: [\n 'llama3.3',\n 'llama3.2',\n 'llama3.1',\n 'qwen3',\n 'gemma3',\n 'mistral',\n ],\n },\n};\n\nexport const MODEL_PURPOSES: { value: ModelPurpose; label: string; description: string }[] = [\n { value: 'default', label: 'Padrão', description: 'Modelo principal para conversas gerais' },\n { value: 'subAgent', label: 'Sub-Agentes', description: 'Modelo para tarefas paralelas (pode ser mais barato)' },\n { value: 'coder', label: 'Coder', description: 'Modelo especializado em programação' },\n { value: 'architect', label: 'Architect', description: 'Modelo para design de sistemas e arquitetura' },\n { value: 'reviewer', label: 'Reviewer', description: 'Modelo para revisão de código' },\n { value: 'planner', label: 'Planner', description: 'Modelo para planejamento de tarefas' },\n { value: 'cheap', label: 'Econômico', description: 'Modelo barato para tarefas simples' },\n];\n"],"names":["MODEL_PURPOSES","PROVIDER_METADATA","openai","type","name","description","requiresApiKey","defaultBaseUrl","websiteUrl","popularModels","anthropic","gemini","kimi","deepseek","openrouter","ollama","value","label"],"mappings":";;;;;;;;;;;QAuKaA;eAAAA;;QAlGAC;eAAAA;;;AAAN,MAAMA,oBAA4D;IACvEC,QAAQ;QACNC,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;IACH;IACAC,WAAW;QACTP,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;SACD;IACH;IACAE,QAAQ;QACNR,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;SACD;IACH;IACAG,MAAM;QACJT,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YAAC;YAAwB;YAAyB;YAAoB;SAAyB;IAChH;IACAI,UAAU;QACRV,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YAAC;YAAqB;YAAe;SAAgB;IACtE;IACAK,YAAY;QACVX,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;SACD;IACH;IACAM,QAAQ;QACNZ,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;YACA;SACD;IACH;AACF;AAEO,MAAMT,iBAAgF;IAC3F;QAAEgB,OAAO;QAAWC,OAAO;QAAUZ,aAAa;IAAyC;IAC3F;QAAEW,OAAO;QAAYC,OAAO;QAAeZ,aAAa;IAAuD;IAC/G;QAAEW,OAAO;QAASC,OAAO;QAASZ,aAAa;IAAsC;IACrF;QAAEW,OAAO;QAAaC,OAAO;QAAaZ,aAAa;IAA+C;IACtG;QAAEW,OAAO;QAAYC,OAAO;QAAYZ,aAAa;IAAgC;IACrF;QAAEW,OAAO;QAAWC,OAAO;QAAWZ,aAAa;IAAsC;IACzF;QAAEW,OAAO;QAASC,OAAO;QAAaZ,aAAa;IAAqC;CACzF"}
1
+ {"version":3,"sources":["../../../../src/modules/config/types/config.types.ts"],"sourcesContent":["export type ProviderType = \n | 'openai' \n | 'anthropic' \n | 'gemini' \n | 'kimi' \n | 'ollama' \n | 'deepseek'\n | 'openrouter';\n\nexport interface BaseProviderConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\nexport interface OpenAIConfig extends BaseProviderConfig {}\nexport interface AnthropicConfig extends BaseProviderConfig {}\nexport interface GeminiConfig extends BaseProviderConfig {}\nexport interface KimiConfig extends BaseProviderConfig {}\nexport interface DeepSeekConfig extends BaseProviderConfig {}\nexport interface OpenRouterConfig extends BaseProviderConfig {}\n\nexport interface OllamaConfig {\n baseUrl: string;\n}\n\nexport interface ProvidersConfig {\n openai?: OpenAIConfig;\n anthropic?: AnthropicConfig;\n gemini?: GeminiConfig;\n kimi?: KimiConfig;\n deepseek?: DeepSeekConfig;\n openrouter?: OpenRouterConfig;\n ollama?: OllamaConfig;\n}\n\nexport interface ModelConfig {\n provider: ProviderType;\n model: string;\n temperature?: number;\n maxTokens?: number;\n}\n\nexport type ModelPurpose = \n | 'default' \n | 'subAgent' \n | 'coder' \n | 'architect' \n | 'reviewer' \n | 'planner' \n | 'tester'\n | 'cheap';\n\nexport type ModelsConfig = Partial<Record<ModelPurpose, ModelConfig>>;\n\nexport interface CastConfig {\n version: number;\n providers: ProvidersConfig;\n models: ModelsConfig;\n}\n\nexport interface ProviderMetadata {\n type: ProviderType;\n name: string;\n description: string;\n requiresApiKey: boolean;\n defaultBaseUrl?: string;\n websiteUrl: string;\n popularModels: string[];\n}\n\nexport const PROVIDER_METADATA: Record<ProviderType, ProviderMetadata> = {\n openai: {\n type: 'openai',\n name: 'OpenAI',\n description: 'GPT-4, GPT-4o, GPT-3.5 Turbo e outros',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.openai.com/v1',\n websiteUrl: 'https://platform.openai.com',\n popularModels: [\n 'gpt-5.2',\n 'gpt-5.1',\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5-nano',\n 'gpt-4.1',\n 'gpt-4.1-mini',\n 'gpt-4.1-nano',\n ],\n },\n anthropic: {\n type: 'anthropic',\n name: 'Anthropic',\n description: 'Claude 3.5 Sonnet, Claude 3 Opus, etc.',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.anthropic.com',\n websiteUrl: 'https://console.anthropic.com',\n popularModels: [\n 'claude-opus-4-1-20250805',\n 'claude-sonnet-4-20250514',\n 'claude-3-7-sonnet-20250219',\n 'claude-3-5-haiku-20241022',\n ],\n },\n gemini: {\n type: 'gemini',\n name: 'Google Gemini',\n description: 'Gemini Pro, Gemini Ultra via Google AI Studio',\n requiresApiKey: true,\n defaultBaseUrl: 'https://generativelanguage.googleapis.com',\n websiteUrl: 'https://ai.google.dev',\n popularModels: [\n 'gemini-2.5-pro',\n 'gemini-2.5-flash',\n 'gemini-2.5-flash-lite',\n 'gemini-3-pro-preview',\n 'gemini-3-flash-preview',\n ],\n },\n kimi: {\n type: 'kimi',\n name: 'Moonshot Kimi',\n description: 'Kimi K1, Kimi K2 - modelos chineses avançados',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.moonshot.cn/v1',\n websiteUrl: 'https://platform.moonshot.cn',\n popularModels: ['kimi-k2-0905-preview', 'kimi-k2-turbo-preview', 'kimi-k2-thinking', 'kimi-k2-thinking-turbo'],\n },\n deepseek: {\n type: 'deepseek',\n name: 'DeepSeek',\n description: 'DeepSeek Chat, DeepSeek Coder',\n requiresApiKey: true,\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n websiteUrl: 'https://platform.deepseek.com',\n popularModels: ['deepseek-reasoner', 'deepseek-r1', 'deepseek-chat'],\n },\n openrouter: {\n type: 'openrouter',\n name: 'OpenRouter',\n description: 'Acesso a múltiplos modelos via uma API',\n requiresApiKey: true,\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n websiteUrl: 'https://openrouter.ai',\n popularModels: [\n 'openai/gpt-5',\n 'anthropic/claude-sonnet-4',\n 'google/gemini-2.5-pro',\n 'meta-llama/llama-3.1-70b-instruct',\n ],\n },\n ollama: {\n type: 'ollama',\n name: 'Ollama (Local)',\n description: 'Modelos locais via Ollama - gratuito e privado',\n requiresApiKey: false,\n defaultBaseUrl: 'http://localhost:11434',\n websiteUrl: 'https://ollama.com',\n popularModels: [\n 'llama3.3',\n 'llama3.2',\n 'llama3.1',\n 'qwen3',\n 'gemma3',\n 'mistral',\n ],\n },\n};\n\nexport const MODEL_PURPOSES: { value: ModelPurpose; label: string; description: string }[] = [\n { value: 'default', label: 'Padrão', description: 'Modelo principal para conversas gerais' },\n { value: 'subAgent', label: 'Sub-Agentes', description: 'Modelo para tarefas paralelas (pode ser mais barato)' },\n { value: 'coder', label: 'Coder', description: 'Modelo especializado em programação' },\n { value: 'architect', label: 'Architect', description: 'Modelo para design de sistemas e arquitetura' },\n { value: 'reviewer', label: 'Reviewer', description: 'Modelo para revisão de código' },\n { value: 'planner', label: 'Planner', description: 'Modelo para planejamento de tarefas' },\n { value: 'tester', label: 'Tester', description: 'Modelo para geração e atualização de testes' },\n { value: 'cheap', label: 'Econômico', description: 'Modelo barato para tarefas simples' },\n];\n"],"names":["MODEL_PURPOSES","PROVIDER_METADATA","openai","type","name","description","requiresApiKey","defaultBaseUrl","websiteUrl","popularModels","anthropic","gemini","kimi","deepseek","openrouter","ollama","value","label"],"mappings":";;;;;;;;;;;QAwKaA;eAAAA;;QAlGAC;eAAAA;;;AAAN,MAAMA,oBAA4D;IACvEC,QAAQ;QACNC,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;IACH;IACAC,WAAW;QACTP,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;SACD;IACH;IACAE,QAAQ;QACNR,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;SACD;IACH;IACAG,MAAM;QACJT,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YAAC;YAAwB;YAAyB;YAAoB;SAAyB;IAChH;IACAI,UAAU;QACRV,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YAAC;YAAqB;YAAe;SAAgB;IACtE;IACAK,YAAY;QACVX,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;SACD;IACH;IACAM,QAAQ;QACNZ,MAAM;QACNC,MAAM;QACNC,aAAa;QACbC,gBAAgB;QAChBC,gBAAgB;QAChBC,YAAY;QACZC,eAAe;YACb;YACA;YACA;YACA;YACA;YACA;SACD;IACH;AACF;AAEO,MAAMT,iBAAgF;IAC3F;QAAEgB,OAAO;QAAWC,OAAO;QAAUZ,aAAa;IAAyC;IAC3F;QAAEW,OAAO;QAAYC,OAAO;QAAeZ,aAAa;IAAuD;IAC/G;QAAEW,OAAO;QAASC,OAAO;QAASZ,aAAa;IAAsC;IACrF;QAAEW,OAAO;QAAaC,OAAO;QAAaZ,aAAa;IAA+C;IACtG;QAAEW,OAAO;QAAYC,OAAO;QAAYZ,aAAa;IAAgC;IACrF;QAAEW,OAAO;QAAWC,OAAO;QAAWZ,aAAa;IAAsC;IACzF;QAAEW,OAAO;QAAUC,OAAO;QAAUZ,aAAa;IAA8C;IAC/F;QAAEW,OAAO;QAASC,OAAO;QAAaZ,aAAa;IAAqC;CACzF"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ const _strict = /*#__PURE__*/ _interop_require_default(require("node:assert/strict"));
6
+ const _nodetest = require("node:test");
7
+ const _configtypes = require("./config.types");
8
+ function _interop_require_default(obj) {
9
+ return obj && obj.__esModule ? obj : {
10
+ default: obj
11
+ };
12
+ }
13
+ // Validate PROVIDER_METADATA entries expose every provider with consistent required fields.
14
+ (0, _nodetest.test)('PROVIDER_METADATA contains complete metadata for every provider type', ()=>{
15
+ const entries = Object.entries(_configtypes.PROVIDER_METADATA);
16
+ (0, _strict.default)(entries.length > 0, 'Expected at least one provider definition');
17
+ for (const [providerKey, metadata] of entries){
18
+ _strict.default.strictEqual(metadata.type, providerKey, 'Metadata type should match the dictionary key');
19
+ _strict.default.ok(typeof metadata.name === 'string' && metadata.name.trim().length > 0, 'Provider name must be a non-empty string');
20
+ _strict.default.ok(typeof metadata.description === 'string' && metadata.description.length > 0, 'Provider description must exist');
21
+ _strict.default.ok(typeof metadata.requiresApiKey === 'boolean', 'requiresApiKey must always exist');
22
+ _strict.default.ok(typeof metadata.websiteUrl === 'string' && metadata.websiteUrl.startsWith('http'), 'Providers must expose a website URL');
23
+ _strict.default.ok(Array.isArray(metadata.popularModels) && metadata.popularModels.length > 0, 'Each provider should list at least one popular model');
24
+ _strict.default.ok(typeof metadata.defaultBaseUrl === 'string', 'Providers should specify defaultBaseUrl');
25
+ }
26
+ });
27
+ // Confirm OpenRouter configuration references a well-known popular model and correct base URL.
28
+ (0, _nodetest.test)('OpenRouter metadata highlights a known popular model and base URL', ()=>{
29
+ const openRouter = _configtypes.PROVIDER_METADATA.openrouter;
30
+ _strict.default.strictEqual(openRouter.type, 'openrouter');
31
+ _strict.default.strictEqual(openRouter.defaultBaseUrl, 'https://openrouter.ai/api/v1');
32
+ _strict.default.ok(openRouter.popularModels.includes('openai/gpt-5'), 'OpenRouter provider should advertise the openai/gpt-5 model in its popular collection');
33
+ });
34
+ // Ensure MODEL_PURPOSES now documents the tester purpose with accurate label and description.
35
+ (0, _nodetest.test)('MODEL_PURPOSES includes tester purpose with descriptive metadata', ()=>{
36
+ const testerEntry = _configtypes.MODEL_PURPOSES.find((purpose)=>purpose.value === 'tester');
37
+ _strict.default.ok(testerEntry, 'Tester purpose entry must exist');
38
+ _strict.default.strictEqual(testerEntry?.label, 'Tester');
39
+ _strict.default.ok(testerEntry?.description.includes('teste'), 'Tester description should mention test-related responsibilities');
40
+ });
41
+ // Verify MODEL_PURPOSES stays complete and free of duplicates compared to the declared catalog.
42
+ (0, _nodetest.test)('MODEL_PURPOSES values remain unique and match the expected catalog', ()=>{
43
+ const expectedOrder = [
44
+ 'default',
45
+ 'subAgent',
46
+ 'coder',
47
+ 'architect',
48
+ 'reviewer',
49
+ 'planner',
50
+ 'tester',
51
+ 'cheap'
52
+ ];
53
+ const actualValues = _configtypes.MODEL_PURPOSES.map((item)=>item.value);
54
+ const uniqueValues = new Set(actualValues);
55
+ _strict.default.strictEqual(actualValues.length, expectedOrder.length, 'MODEL_PURPOSES must cover the full catalog of purposes');
56
+ _strict.default.strictEqual(uniqueValues.size, actualValues.length, 'MODEL_PURPOSES should not contain duplicate values');
57
+ _strict.default.deepStrictEqual(actualValues, expectedOrder, 'MODEL_PURPOSES should stay in the documented order');
58
+ });
59
+
60
+ //# sourceMappingURL=config.types.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/config/types/config.types.spec.ts"],"sourcesContent":["import assert from 'node:assert/strict';\nimport { test } from 'node:test';\n\nimport { MODEL_PURPOSES, PROVIDER_METADATA } from './config.types';\n\n// Validate PROVIDER_METADATA entries expose every provider with consistent required fields.\ntest('PROVIDER_METADATA contains complete metadata for every provider type', () => {\n const entries = Object.entries(PROVIDER_METADATA);\n assert(entries.length > 0, 'Expected at least one provider definition');\n\n for (const [providerKey, metadata] of entries) {\n assert.strictEqual(metadata.type, providerKey, 'Metadata type should match the dictionary key');\n assert.ok(typeof metadata.name === 'string' && metadata.name.trim().length > 0, 'Provider name must be a non-empty string');\n assert.ok(typeof metadata.description === 'string' && metadata.description.length > 0, 'Provider description must exist');\n assert.ok(typeof metadata.requiresApiKey === 'boolean', 'requiresApiKey must always exist');\n assert.ok(typeof metadata.websiteUrl === 'string' && metadata.websiteUrl.startsWith('http'), 'Providers must expose a website URL');\n assert.ok(Array.isArray(metadata.popularModels) && metadata.popularModels.length > 0, 'Each provider should list at least one popular model');\n assert.ok(typeof metadata.defaultBaseUrl === 'string', 'Providers should specify defaultBaseUrl');\n }\n});\n\n// Confirm OpenRouter configuration references a well-known popular model and correct base URL.\ntest('OpenRouter metadata highlights a known popular model and base URL', () => {\n const openRouter = PROVIDER_METADATA.openrouter;\n assert.strictEqual(openRouter.type, 'openrouter');\n assert.strictEqual(openRouter.defaultBaseUrl, 'https://openrouter.ai/api/v1');\n assert.ok(\n openRouter.popularModels.includes('openai/gpt-5'),\n 'OpenRouter provider should advertise the openai/gpt-5 model in its popular collection'\n );\n});\n\n// Ensure MODEL_PURPOSES now documents the tester purpose with accurate label and description.\ntest('MODEL_PURPOSES includes tester purpose with descriptive metadata', () => {\n const testerEntry = MODEL_PURPOSES.find((purpose) => purpose.value === 'tester');\n assert.ok(testerEntry, 'Tester purpose entry must exist');\n assert.strictEqual(testerEntry?.label, 'Tester');\n assert.ok(\n testerEntry?.description.includes('teste'),\n 'Tester description should mention test-related responsibilities'\n );\n});\n\n// Verify MODEL_PURPOSES stays complete and free of duplicates compared to the declared catalog.\ntest('MODEL_PURPOSES values remain unique and match the expected catalog', () => {\n const expectedOrder: Array<typeof MODEL_PURPOSES[number]['value']> = [\n 'default',\n 'subAgent',\n 'coder',\n 'architect',\n 'reviewer',\n 'planner',\n 'tester',\n 'cheap',\n ];\n\n const actualValues = MODEL_PURPOSES.map((item) => item.value);\n const uniqueValues = new Set(actualValues);\n\n assert.strictEqual(actualValues.length, expectedOrder.length, 'MODEL_PURPOSES must cover the full catalog of purposes');\n assert.strictEqual(uniqueValues.size, actualValues.length, 'MODEL_PURPOSES should not contain duplicate values');\n assert.deepStrictEqual(actualValues, expectedOrder, 'MODEL_PURPOSES should stay in the documented order');\n});\n"],"names":["test","entries","Object","PROVIDER_METADATA","assert","length","providerKey","metadata","strictEqual","type","ok","name","trim","description","requiresApiKey","websiteUrl","startsWith","Array","isArray","popularModels","defaultBaseUrl","openRouter","openrouter","includes","testerEntry","MODEL_PURPOSES","find","purpose","value","label","expectedOrder","actualValues","map","item","uniqueValues","Set","size","deepStrictEqual"],"mappings":";;;;+DAAmB;0BACE;6BAE6B;;;;;;AAElD,4FAA4F;AAC5FA,IAAAA,cAAI,EAAC,wEAAwE;IAC3E,MAAMC,UAAUC,OAAOD,OAAO,CAACE,8BAAiB;IAChDC,IAAAA,eAAM,EAACH,QAAQI,MAAM,GAAG,GAAG;IAE3B,KAAK,MAAM,CAACC,aAAaC,SAAS,IAAIN,QAAS;QAC7CG,eAAM,CAACI,WAAW,CAACD,SAASE,IAAI,EAAEH,aAAa;QAC/CF,eAAM,CAACM,EAAE,CAAC,OAAOH,SAASI,IAAI,KAAK,YAAYJ,SAASI,IAAI,CAACC,IAAI,GAAGP,MAAM,GAAG,GAAG;QAChFD,eAAM,CAACM,EAAE,CAAC,OAAOH,SAASM,WAAW,KAAK,YAAYN,SAASM,WAAW,CAACR,MAAM,GAAG,GAAG;QACvFD,eAAM,CAACM,EAAE,CAAC,OAAOH,SAASO,cAAc,KAAK,WAAW;QACxDV,eAAM,CAACM,EAAE,CAAC,OAAOH,SAASQ,UAAU,KAAK,YAAYR,SAASQ,UAAU,CAACC,UAAU,CAAC,SAAS;QAC7FZ,eAAM,CAACM,EAAE,CAACO,MAAMC,OAAO,CAACX,SAASY,aAAa,KAAKZ,SAASY,aAAa,CAACd,MAAM,GAAG,GAAG;QACtFD,eAAM,CAACM,EAAE,CAAC,OAAOH,SAASa,cAAc,KAAK,UAAU;IACzD;AACF;AAEA,+FAA+F;AAC/FpB,IAAAA,cAAI,EAAC,qEAAqE;IACxE,MAAMqB,aAAalB,8BAAiB,CAACmB,UAAU;IAC/ClB,eAAM,CAACI,WAAW,CAACa,WAAWZ,IAAI,EAAE;IACpCL,eAAM,CAACI,WAAW,CAACa,WAAWD,cAAc,EAAE;IAC9ChB,eAAM,CAACM,EAAE,CACPW,WAAWF,aAAa,CAACI,QAAQ,CAAC,iBAClC;AAEJ;AAEA,8FAA8F;AAC9FvB,IAAAA,cAAI,EAAC,oEAAoE;IACvE,MAAMwB,cAAcC,2BAAc,CAACC,IAAI,CAAC,CAACC,UAAYA,QAAQC,KAAK,KAAK;IACvExB,eAAM,CAACM,EAAE,CAACc,aAAa;IACvBpB,eAAM,CAACI,WAAW,CAACgB,aAAaK,OAAO;IACvCzB,eAAM,CAACM,EAAE,CACPc,aAAaX,YAAYU,SAAS,UAClC;AAEJ;AAEA,gGAAgG;AAChGvB,IAAAA,cAAI,EAAC,sEAAsE;IACzE,MAAM8B,gBAA+D;QACnE;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACD;IAED,MAAMC,eAAeN,2BAAc,CAACO,GAAG,CAAC,CAACC,OAASA,KAAKL,KAAK;IAC5D,MAAMM,eAAe,IAAIC,IAAIJ;IAE7B3B,eAAM,CAACI,WAAW,CAACuB,aAAa1B,MAAM,EAAEyB,cAAczB,MAAM,EAAE;IAC9DD,eAAM,CAACI,WAAW,CAAC0B,aAAaE,IAAI,EAAEL,aAAa1B,MAAM,EAAE;IAC3DD,eAAM,CAACiC,eAAe,CAACN,cAAcD,eAAe;AACtD"}
@@ -449,14 +449,21 @@ Keep the summary under 500 words. Output ONLY the summary, no preamble.`),
449
449
  try {
450
450
  for await (const event of stream){
451
451
  if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
452
- const content = event.data.chunk.content;
453
- if (typeof content === 'string' && content) {
454
- yield content;
455
- fullResponse += content;
452
+ const text = this.extractTextFromModelContent(event.data.chunk.content);
453
+ if (text) {
454
+ yield text;
455
+ fullResponse += text;
456
456
  }
457
457
  }
458
458
  if (event.event === 'on_chat_model_end') {
459
459
  const output = event.data?.output;
460
+ if (!fullResponse && output?.content) {
461
+ const fallbackText = this.extractTextFromModelContent(output.content);
462
+ if (fallbackText) {
463
+ yield fallbackText;
464
+ fullResponse += fallbackText;
465
+ }
466
+ }
460
467
  const usage = output?.usage_metadata || output?.response_metadata?.usage;
461
468
  if (usage) {
462
469
  interactionInputTokens += usage.input_tokens || usage.prompt_tokens || usage.promptTokens || 0;
@@ -509,6 +516,35 @@ Keep the summary under 500 words. Output ONLY the summary, no preamble.`),
509
516
  this.messages = [];
510
517
  this.tokenCount = 0;
511
518
  }
519
+ extractTextFromModelContent(content) {
520
+ if (!content) return '';
521
+ if (typeof content === 'string') {
522
+ return content;
523
+ }
524
+ if (Array.isArray(content)) {
525
+ let combined = '';
526
+ for (const item of content){
527
+ combined += this.extractTextFromModelContent(item);
528
+ }
529
+ return combined;
530
+ }
531
+ if (typeof content === 'object') {
532
+ const record = content;
533
+ if (typeof record.text === 'string') {
534
+ return record.text;
535
+ }
536
+ if (typeof record.content === 'string') {
537
+ return record.content;
538
+ }
539
+ if (record.content) {
540
+ return this.extractTextFromModelContent(record.content);
541
+ }
542
+ if (record.delta) {
543
+ return this.extractTextFromModelContent(record.delta);
544
+ }
545
+ }
546
+ return '';
547
+ }
512
548
  async compactHistory() {
513
549
  const before = this.messages.length;
514
550
  if (before < 4) {